Device-driven vulnerabilities are now growing to be a major threat to the security of Windows and other operating systems. This is a new field, but there are few public technical documents describing this aspect. As far as I know, the first windows Device Driver attack was mentioned in the Win32 Device Drivers Communication Vulnerabilities White Paper by the SEC-LABS team. This article discloses some useful driving overflow technologies and depicts the blueprint for future research.
The second article worth reading is Barnaby Jack's article, called "Remote Windows Kernel Exploitation Stepinto the Ring 0 ". Due to the lack of technical documentation in this regard, I decided to share my own research results. In this article, I will introduce my device-driven attack technology and provide some detailed details about the available technology, including the complete attack code and sample-driven code for testing.
Readers need IA-32 Assembly reading and software vulnerability attack experience. In addition, it is strongly recommended that you read the two white papers mentioned earlier.
Lab environment Establishment
I used my small "lab" during the process ":
-A computer with 1 GB memory;
-Virtual Machine software, such as Vmware;
-Windbg or softice. I use the second method in VMware, but it is not stable;
-IDA anti-assembler;
-I will mention some software later.
Use pipe between the VM and the host for remote debugging, but other methods are usually better. If you want to further study the driver, the establishment of this environment is very important.
User-mode code (software) runs in Ring3 mode (it has no permission to access Ring0 mode) and cannot directly access the operating system functions, if you want to use these functions, you can only request them through call. This is called function encapsulation. The user mode memory address ranges from 0x00000000 to 0x7FFFFFFF.
Windows uses two permission modes (ring0 and ring3 ).
Driver loader
Before I release the simple driver, let's take a simple look at how to load it. Here is the code to implement this function:
/* Wdl. c */
# Define UNICODE
# Include
# Include
# Include
Void install_driver (SC _HANDLE SC, wchar_t * name)
{
SC _HANDLE service;
Wchar_t path [512];
Wchar_t * fp;
If (GetFullPathName (name, 512, path, & fp) = 0)
{
Printf ("[-] Error: GetFullPathName () failed, error = % d", GetLastError ());
Return;
}
Service = CreateService (SC, name, name, SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL, path, NULL,
NULL, NULL );
If (service = NULL)
{
Printf ("[-] Error: CreateService () failed, error % d", GetLastError ());
Return;
}
Printf ("[+] Creating service-success .");
CloseServiceHandle (SC );
If (StartService (service, 1, (const unsigned short **) & name) = 0)
{
Printf ("[-] Error: StartService () failed, error % d", GetLastError ());
If (DeleteService (service) = 0)
Printf ("[-] Error: DeleteService () failed, error = % d", GetLastError ());
Return;
}
Printf ("[*] Staring service-success .");
CloseServiceHandle (service );
}
Void delete_driver (SC _HANDLE SC, wchar_t * name)
{
SC _HANDLE service;
SERVICE_STATUS status;
Service = OpenService (SC, name, SERVICE_ALL_ACCESS );
If (service = NULL)
{
Printf ("[-] Error: OpenService () failed, error = % d", GetLastError ());
Return;
}
Printf ("[+] Opening service-success .");
If (ControlService (service, SERVICE_CONTROL_STOP, & status) = 0)
{
Printf ("[-] Error: ControlService () failed, error = % d", GetLastError ());
Return;
}
Printf ("[+] Stopping service-success .");
If (DeleteService (service) = 0 ){
Printf ("[-] Error: DeleteService () failed, error = % d", GetLastError ());
Return;
}
Printf ("[+] Deleting service-success ");
CloseServiceHandle (SC );
}
Int main (int argc, char * argv [])
{
Int m, B;
SC _HANDLE SC;
Wchar_t name [MAX_PATH];
Printf ("[+] Windows driver loader by Piotr Bania ");
If (argc! = 3)
{
Printf ("[!] Usage: wdl.exe (/l |/u) driver. sys ");
Printf ("[!] /L-load the driver ");
Printf ("[!] /U-unload the driver ");
Getch ();
Return 0;
}
If (strcmp (argv [1], "/l") = 0)
M = 0;
Else
M = 1; // default uninstall mode
SC = OpenSCManager (NULL, SERVICES_ACTIVE_DATABASE,
SC _MANAGER_ALL_ACCESS );
If (SC = NULL)
{
Printf ("[-] Error: OpenSCManager () failed ");
Return 0;
}
B = MultiByteToWideChar (CP_ACP, 0, argv [2],-1, name, MAX_PATH );
If (m = 0)
{
Printf ("[+] Trying to load: % s", argv [2]);
Install_driver (SC, name );
}
If (m! = 0)
{
Printf ("[+] Trying to unload: % s", argv [2]);
Delete_driver (SC, name );
}
Getch ();
}
/* Wdl. c ends */
Driver samples with Vulnerabilities
This is a sample code with a vulnerability driver. We will try to attack it later in this article. This driven framework model is based on Iczelion.
; Buggy. asm start
. 386
. Model flat, STDCALL
Option casemap: NONE
Include d: masm32demodewindows. inc
INCLUDE incstring. INC
INCLUDE inctstruc. INC
INCLUDE inctddk. INC
INCLUDE inctoskrnl. INC
INCLUDE incNtDll. INC
Includelib d: masm32libwdm. lib
Includelib d: masm32libtoskrnl. lib
Includelib d: masm32libtdll. lib
. CONST
P1_bj PDEVICE_OBJECT 0
TEXTW szDevPath, <DeviceBUGGY/0>
TEXTW szSymPath, <DosDevicesBUGGY/0>
. CODE
Assume fs: NOTHING
DriverDispatch proc uses esi edi ebx, pDriverObject, pIrp
Mov edi, pIrp
Assume edi: PTR _ IRP
Sub eax, eax
Mov [edi]. IoStatus. Information, eax
Mov [edi]. IoStatus. Status, eax
Assume edi: NOTHING
Mov esi, (_ irptr [edi]). PCurrentIrpStackLocation
Assume esi: PTR IO_STACK_LOCATION
. IF [esi]. MajorFunction = IRP_MJ_DEVICE_CONTROL
Mov eax, [esi]. DeviceIoControl. IoControlCode
. IF eax = 011111111 h
Mov eax, (_ irptr [edi]). SystemBuffer; inbuffer
Test eax, eax
Jz no_write
Mov edi, [eax]; [inbuffer] = dest
Mov esi, [eax + 4]; [inbuffer + 4] = src
Mov ecx, 512; ecx = 512 bytes
Rep movsb; copy
No_write:
. ENDIF
. ENDIF
Assume esi: NOTHING
Mov edx, IO_NO_INCREMENT; special calling
Mov ecx, pIrp
Call IoCompleteRequest
Mov eax, STATUS_SUCCESS
Ret
DriverDispatch ENDP
DriverUnload proc uses ebx esi edi, DriverObject local usSym: UNICODE_STRING
Invoke RtlInitUnicodeString, ADDR usSym, OFFSET szSymPath
Invoke IoDeleteSymbolicLink, ADDR usSym
Invoke IoDeleteDevice, p1_bj
Ret
DriverUnload ENDP
. CODE INIT
DriverEntry proc uses ebx esi edi, DriverObject, RegPath
Local usDev: UNICODE_STRING
Local usSym: UNICODE_STRING
Invoke RtlInitUnicodeString, ADDR usDev, OFFSET szDevPath
Invoke IoCreateDevice, DriverObject, 0, ADDR usDev, FILE_DEVICE_NULL, 0,
FALSE, OFFSET p1_bj
Test eax, eax
Jnz epr
Invoke RtlInitUnicodeString, ADDR usSym, OFFSET szSymPath
Invoke IoCreateSymbolicLink, ADDR usSym, ADDR usDev
Test eax, eax
Jnz epr
Mov esi, DriverObject
Assume esi: PTR DRIVER_OBJECT
Mov [esi]. PDISPATCH_IRP_MJ_DEVICE_CONTROL, OFFSET DriverDispatch
Mov [esi]. PDISPATCH_IRP_MJ_CREATE, OFFSET DriverDispatch
Mov [esi]. PDRIVER_UNLOAD, OFFSET DriverUnload
Assume esi: NOTHING
Mov eax, STATUS_SUCCESS
Epr:
Ret
DriverEntry ENDP
End DriverEntry
; Buggy. asm ends
Vulnerability Analysis
You can find a major vulnerability in the code above: