Kali渗透测试:对软件的溢出漏洞进行测试
如何对一个软件进行渗透,渗透目标是FreeFloat FTP Server, 这是一款十分简单的FTP服务器软件。FreeFloat FTP Server会在运行的主机上建立一个FTP服务器,其他计算机上的用户可以登录这个FTP服务器来存取文件。如我们在IP地址为192.168.68.160的主机的C盘中运行FreeFloat FTP Server,在另一台计算机中可以使用FTP下载工具或者命令的方式对其进行访问。这里我们采用命令的方式对其进行访问,如下图所示:
实验环境
攻击机:Linux kali 5.10.0 IP:192.168.68.125
靶机:WinXP Profession IP:192.168.68.160
操作步骤
首先使用ftp命令,然后使用open命令打开192.168.68.160。**注意不要使用浏览器打开FreeFloat FTP Server, 否则你讲无法对这个登录过程进行观察。**使用FreeFloat FTP Server对登录没有任何限制,你输入任意的用户名和密码都可以登录。
首先输入任意用户名和密码,然后按Enter键便可登录到FreeFloat FTP Server, 如下图所示:
这里显示用户kali已经成功登录了,这样我们就可以使用FTP服务器中的任意资源,其实这里使用任何一个用户名都可以登录。
下面看看这个软件是否存在溢出漏洞。我们在输入用户名的时候,尝试使用一个特别长的字符串作为用户名,来看看在用户名输入的位置是否存在溢出漏洞。如输入数百个“a”作为用户名,如下图所示:
系统并没有崩溃,而且是正常出现了输入密码的提示界面,如下图所示:
其实用户名再输入更多的"a"也是一样的,系统依然不会崩溃,那么是不是这个软件不存在溢出漏洞呢?在编写漏洞渗透模块的时候,千万不要在此时就放弃,我们可以查看Wireshark捕获的此次登录过程的数据包,如下图所示:
我们发现,实际发送出去的数据包中的字符“a”的数量并没有那么多,无论我们在登录用户名时输入多长的用户名,实际上发送出去的只有78个“a”。显然,这个长度的字符是无法引起溢出的。那么我们有什么方法可以加大字符串的长度呢?
最直接的方法是我们自行构造数据包,然后将数据包发送出去,这样我们想要数据包中多少个“a”,就可以发送多少个“a”。
我们可以编写一个自动连接到目标FTP服务器的客户端脚本。我们采用Python来编写这段脚本,Python是现在网络渗透界非常流行的语言。
我们先建立一个到目标FTP服务器的连接。因为这个软件提供的是FTP服务, 所以我们只需要按照连接FTP服务的过程来编写这段脚本即可,而且这段脚本可以用来连接到任何提供FTP服务的软件上。😱
1. 在Kali中启动Python3
因为这个系统中同时内置了Python3 和 Python2,因此在启动时需要输入python3:
┌──(kali㉿kali)-[~]
└─$ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
接下来我们导入需要使用的socket库:
>>> import socket
成功建立一个socket对象,如下图所示:
>>> s = socket.socket()
利用这个套接字就可以建立到目标的连接:
>>> connect = s.connect(('192.168.68.160', 21))
执行之后,建立好一个到目标主机21端口的连接,但是到FTP服务器的连接需要认证,我们仍然需要想目标FTP服务器提供一个用户名和密码。服务器通常会对用户名和密码的正确性进行验证,也就是将用户的输入与自己保存的记录进行比对。我们可以将用户名的输入作为一个测试点,这是最常见的情形。这主要是因为以前,很多程序员会使用memcpy函数来将用户的输入复制到一个变量中,但是这些程序员往往会忽略对地址是否越界进行检查,从而导致数据的溢出,进而引发代码远程执行的问题。
现在我们就把FreeFloat FTP Server用户名的输入作为测试点。首先检查这个软件是否存在漏洞。这检查很简单,我们在输入用户名的时候,并不像常规的那样,输入几个或者十几个字符,而是输入成百上千个字符,同时观察目标FTP服务器的反应。
下面我们在Wireshark中观察一下抓取到的我们输入的用户名的数据包的格式。
在图中,我们输入的用户名是一段字符,这段字符前面是“USER”,后面是一个回车符和换行符“\r\n”。我们使用socket套接字中的send方法可以将一个字符串以数据包的形式发送出去,可以我们已成千上百的“A”作为用户名:
>>> connect = s.connect(('192.168.68.160', 21))
>>> shellcode = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
>>> data = b"USER "+shellcode+b"\r\n"
>>> s.connect(('192.168.68.160',21))
>>> s.send(data)
将这个数据包发送到目标FTP服务器上,我们可以看到这个FTP服务器崩溃了,并且出现了如下图的崩溃画面: