“人生苦短,我用Python“——软件溢出漏洞

测试软件的溢出漏洞

FreeFloat FTP Server会在运行的主机上建立一个FTP。其他计算机上的用户可以登录到这个FTP上来存取文件。

*例如,在主机192.168.0.116的C盘中运行这个FTP软件,在另外一台计算机中可以使用FTP下载工具或者命令的方式进行访问。*这里采用命令的方式对其进行访问,(使用FreeFloat FTP Server这个服务器对登录没有任何限制,输入任意的用户名和密码都可以登录进去)
在这里插入图片描述
在这里插入图片描述

测试这个工具是否存在栈溢出漏洞
输入用户名时,尝试使用一个特别长的字符串作为用户名,来看看在用户名输入的位置是否存在溢出漏洞,例如数百个‘a’。
在这里插入图片描述
系统并没有崩溃,而是正常地出现了输入密码界面。
打开WireShark来捕获此次登录的数据包来看一下
在这里插入图片描述
可见所发送的数据包并没有将所有‘a’收录进来! 那么该如何将所有‘a’发送出去呢,最直接的方法就是 自行构造数据包 ,然后将数据包发送出去。

编写一个可以自动连接FreeFloat FTP Server的客户端脚本
导入需要使用的socket库:import socket
创建一个socket套接字:s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
利用这个套接字就可以建立到目标的连接:connect=s.connect(('192.168.0.116',21))
在这里插入图片描述
执行之后,就建立好一个到目标主机的21端口的连接,但是FTP连接需要验证,仍然需要向目标服务器提供一个用户名和密码。
服务器通常会对用户名和密码的正确性进行验证,也就是将用户的输入与自己保存的记录进行比对。
把FreeFloat FTP Server 用户名的输入作为渗透测试的切入点,首先来检查这个软件是否存在栈溢出的现象,这个检查很简单,在输入用户名的时候,输入成百上千的字符,同时观察目标服务器的反应。

首先观察一下正常连接到目标服务器上数据包的格式
在这里插入图片描述
图中输入的用户名是一段字符,这段字符前面的“USER”,后面是一个回车符和换行符“\r\n”。使用socket套接字中的send()方法可以将一个字符串以数据包的形式发送出去,这里面以成百上千的“A”作为用户名:s.send('USER AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n')

FTP服务器工具崩溃
在这里插入图片描述

计算软件溢出的偏移地址

这里显示软件FreeFloat FTP Server执行到地址“41414141”处时就无法在继续进行。出现这种情况的原因是 原本保存下一条地址的EIP寄存器中的地址被溢出的字符“A”所覆盖。“\x41”在ASCII表中表示的正是字符“A”,也就是说现在EIP寄存器中的内容就是“AAAA”,而操作系统无法在这个地址找到一条可以执行的命令,从而引发系统的崩溃。
在这里插入图片描述
每一次这个软件执行时所分配的地址都是不相同的。所以现在需要知道的不是EIP的绝对地址,而是EIP相对输入数据起始位置的相对位移
如果这个位移的值不大,可以用逐步尝试的方法获取这个值。但是如果位移比较大,还需要使用到一些工具来提高效率。
可以借助 Metasploit 中内置的两个工具pattern_create和pattern_offset来完成这个任务。

pattern_create可以用来创建一段没有重复字符的文本。
将这段文本发送到目标服务器,当发生溢出时,记录下程序发生错误的地址(也就是EIP中的内容),这个地址其实就是文本中的4个字符
利用pattern_offset快速找到这4个字符在文本中的偏移量,而这个偏移量就是EIP寄存器的地址。

首先打开kali虚拟机,打开终端进入到Metasploit的目录:cd /usr/share/metasploit-framework/tools/exploit,然后再这个目录中执行工具pattern_create.rb,这时一个由Ruby语言编写的脚本。了解这个工具的使用方法,可以使用参数-h来显示所有可以使用的参数及其用法。
在这里插入图片描述
生成
在这里插入图片描述
替换到脚本代码中
在这里插入图片描述
运行脚本,导致FTP工具崩溃
在这里插入图片描述
提示信息中的地址“37684136”,然后使用pattern_offset来查找这个值对应的偏移量。
执行工具pattern_offset.rb,同样可以使用-h来查看参数帮助。
在这里插入图片描述
使用参数-q加上溢出的地址值,使用-l来指定字符串的长度(就是之前pattern_create.rb所使用的参数,也就是500)
在这里插入图片描述
现在向目标发送呢能够导致系统溢出到EIP的数据,之前已经计算出EIP的偏移量是230,那么现在提供了230个字符“A”即可,之后就是4个“B”。

import socket
buff="\x41"*230+"\x42"*4
target="192.168.0.116"
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((target,21))
s.send("USER "+buff+"\r\n")
s.close()

再次运行,提示信息变为42424242,也就是4个“B”
在这里插入图片描述

查找JMP ESP指令

如何让目标服务器执行恶意的攻击载荷?让这个EIP中的地址指向攻击载荷。

先看一下输入的用户名数据在执行时是如何分布的:
在这里插入图片描述
按照栈的设计,ESP寄存器应该就位于EIP寄存器的后面(中间可能会有一些缝隙)。使用大量字符来溢出栈的时候,也可以使用特定字符来覆盖ESP,二来虽然无法对ESP寄存器进行定位,但是可以利用一条“JMP ESP”的跳转指令来实现跳转到当前ESP寄存器。
在这里插入图片描述
这里还需要使用到Immunity Debugger,但是这个工具本身并没有提供查找“JMP ESP”命令的功能需要借助Mona.py这个插件完成这个任务。Mona.py的使用方法也很简单,只要将下载好的这个插件复制到Immunity Debugger安装目录下的PyCommands文件夹中就可以使用。然后再Immunity Debugger的命令行中输入“!mona”命令。

在这里插入图片描述
在命令行中执行“!mona jmp -r esp”来查找“JMP ESP”命令,
在这里插入图片描述
这里面选择一条指令来作为跳转指令,需要记录下地址“77DBF049”
这里其实就是Python变成向目标发送“JMP ESP”指令的地址时使用的是大端格式,而当前的地址“77DBF049”其实是小端格式,两者都需要进行调整。
如果希望“77DBF049”来覆盖目标地址,在使用Python编写渗透程序时就要使用倒置的地址
“/x49/xF0/xDB/x77”(因为是在栈中,先进后出)。

向目标发送能够导致系统溢出到EIP的数据,之前已经计算出EIP的偏移量是230,现在提供了230个字符“A”即可,之后就是“/x49/xF0/xDB/x77”

import socket
buff="\X41"*230+"/x49/xF0/xDB/x77"
target='192.168.0.116'
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((target,21))
s.send("USER "+buff+"\r\n")
s.close()

重复之前的步骤,在虚拟机中打开FreeFloat FTP Server,然后执行上面的脚本。
在这里插入图片描述
现在只需要把希望在目标计算机上执行的代码添加进去即可。
这段脚本如果在目标计算机上执行,就会自动启动计算器程序。下面将这段脚本添加到原来程序的buff中,修改之后的程序就变成如下。
在这里插入图片描述
执行这段脚本之后,目标系统的FreeFloat FTP Server崩溃,但是却没有启动计算器程序

启动Immunity Debugger来调试一下,可以看到这里之前的命令都执行成功了,但是ESP的地址向后发生了偏移,这样就导致了Shellcode的代码并没有全部加载到ESP中,最前面一部分在ESP的外面,这样就会导致即使控制了程序,但是由于ESP中只有一部分Shellcode,因此执行的时候缺失了一部分,从而导致程序不能够正常执行。
在这里插入图片描述

解决的方法就是一个特殊的指令“\x90”

“\x90”其实就是NOPS,也就是空指令,这个指令不会执行任何的实际操纵。但是它也是一条指令,因此会顺序地向下执行,这样即使并不知道ESP的真实地址,只需要躲在EIP后面添加一些空指令,只要这些空指令够多,将Shellcode偏移进ESP,就可以顺利执行Shellcode。

向程序添加20个“\x90”
在这里插入图片描述
执行一下这段脚本,目标系统弹出一个计算器程序。这说明编写的漏洞程序已经成功。

坏字符的确定

FTP对用户名是有限制的,并非所有字符都可以出现在用户名中。如果内容中包含这种不被允许的字符,就可能导致FTP服务器拒绝接收后面的内容,从而导致代码只传送了一部分。
但是每个程序,甚至每个程序的入口接收的规则都不一样,很难直接指出哪些是坏字符,但是可以使用逐个测试的方法找出这些字符。

“BBBB”现在所在位置就是EIP指针的位置,它后面的位置就是要放置坏字符的位置。
在这里插入图片描述
这段程序将会把所有的字符都发送到目标服务器中,但是坏字符串会引起服务的终止
在这里插入图片描述
在这里可以看到在“BBBB”后面第一行的后面出现了“Password required”,这说明在“BBBB”后面的第一行里出现了导致目标软件认为用户名已经输入结束的字符了。
这一行,一共是4个字符“\x00\x01\x02\x03”,首先将这里面的“\x00”去掉,如果程序继续向下执行,那么说明这个字符是坏字符,还是这个程序,修改之后变为:在这里插入图片描述

执行这个程序,查看结果
在这里插入图片描述
前面的8个字符没有问题了,在第三行用户名的输入再次被终止了,那么这说明现在的“\x01\x02\x03\x04\x05\x06\x07\x08\x09”已经没有问题了,出现问题的一定是“\x0a\x0b\x0c\x0d”中的一个。再将这4个字符一个一个去掉。首先去掉“\x0a”,然后执行这个程序,使用Immunity Debugger查看里面的变化,坏字符刚好是“\x0a”。在这里插入图片描述
这个程序中的坏字符是“\x00” “\x0a” “\x40”,那么在编写Shellcode的时候,就需要避免这三个坏字符。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值