分析环境:
操作系统: Win7pro (winxp的符号配置到自闭)
环境配置: python 2.7.15(配置winxp环境时 如果出现已知无法更改环境变量成功可以尝试重启)
漏洞软件: PCMan’s FTP Server 2.0.0.0
调试器: WinDbg
POC:
https://www.exploit-db.com/exploits/26471
或者可以用简版如下:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 21))
s.recv(1024)
User = 'anonymous'
Password='A'*8000
s.send("USER" + User + "\r\n")
print s.recv(1024)
s.send("PASS" + Password + "\r\n")
print s.recv(1024)
POC运行结果
kb 显示的参数 从左到右分别为 ebp, ret ,arg1, arg2,返回值被AAAA覆盖,此时esp之前是返回上层函数的地址,在0012ed6c之前下硬件写入条件断点,重开windbg附加进程调试,命令如下:
ba w4 0012ed5c ".if(poi(0012ed5c)=0x41414141){}.else{gc}"
再次执行poc,程序在004173af处断下,溢出已经发生,但未覆盖函数返回值。
在IDA中搜索此地址 可知指令处于wirte_char函数中。
OD硬件断点下载004173af处 即可回溯出上层调用函数地址00417403
通过IDA的Ctrl+X 依次往上可以追溯调用函数依次为write_char<——output<——sprintf函数。查看sprintf函数的上层调用,发现在sub_403E60中可能触发堆栈溢出,记录sprintf函数地址00412CBF,使用硬件断点进行追踪。
第一次中断写入数据
第二次写入数据
第三次写入数据
第四次调用写入数据
第五次写入数据
第六次调用sub_403E60函数
进入Sprintf函数前参数记录
调用Sprintf函数分析 由填充格式和内存中的数据结果分析可知,Sprintf函数在传入Password的时候 采用%s方式传入,出现格式化字符串漏洞。
对比进入函数前堆栈截图可知此时返回地址已被覆盖掉
Exploit构造分析
结合截图中所出现几个关键信息有以下构造思路:
从IDA分析和动态调试中可以看到,此漏洞为格式化字符串漏洞,那么从理论上讲构造参数中的Name参数和Password参数都可以进行返回地址攻击(RETN 0x4)。此处使用Password参数进行构造,
Password填充起始地址为0019E4FD,函数返回EIP指向0019ECD8所储存的值,返回后ESP值为0019ECE0,同时根据调用Sprintf函数的结束图可知最后的填充地址为0019F442(出现00截断),不开辟空间情况下可以使用的shellcode填充大小为 0019F442-(0019ECD8+4)=0x766。前置填充的垃圾数据大小为0019ECD8-0019E4FD=0x7DB。
Exploit·1 直接进行二进制修改测试
重点关注参数传递 是什么参数构成了填充溢出 如何构造