通常情况下栈溢出可能造成的后果有两种,一类是本地提权另一类则是远程执行任意命令,通常C/C++并没有提供智能化检查用户输入是否合法的功能,同时程序编写人员在编写代码时也很难始终检查栈是否会发生溢出,这就给恶意代码的溢出提供了的条件,利用溢出,攻击者可以控制程序的执行流,从而控制程序的执行过程并实施恶意行为,而微软的DEP保护机制则可使缓冲区溢出失效,不过利用ROP反导技术依然是可被绕过的,接下来将具体分析如何利用ROP技术绕过DEP保护机制。
课件下载地址:https://pan.baidu.com/s/1WwKp2GTVaCEQOLPUM49dUw 提取码:nk9h
缓冲区溢出的常用攻击方法是将恶意 shellcode 注入到远程服务的堆栈中,并利用 jmp esp
等跳板指令跳转到堆栈中执行恶意的代码片段,从而拿到目标主机的控制权。为了演示攻击的具体手法以及二进制漏洞挖掘的思路,这里作者编写了远程服务程序FTP Server
该服务运行后会在本机开启 0.0.0.0:9999
端口,你可以通过nc命令远程连接到服务器并可以执行一些命令.
如上图就是运行后的FTP服务器,通过nc工具链接服务端的地址nc 192.168.1.8 9999
可以得到一个FTP交互环境,此时可以执行send | hello world
命令,来向服务器发送一段字符串,同时服务器会返回给你Data received successfully
这样的提示信息,好了我们开始分析程序并挖掘漏洞吧。
模糊测试与分析
要执行模糊测试的第一步就是要确定发送数据包中包头的格式,这里我们可以使用Wireshark工具监控TCP流,将源地址设置为192.168.1.2
,目标地址设置为 192.168.1.8
,监控并从中得到数据传输的格式信息,过滤语句 tcp.stream and ip.src_host==192.168.1.2 and ip.dst_host==192.168.1.8
该语句可以精确的过滤出我们所需要的数据。
上图中我们可以直观的看出,数据包的格式仅仅是 send | hello lyshark
并没有添加任何的特殊符号,更没有加密传输,接下来就是要验证send函数是否存在缓冲区溢出了,这里我们需要编写一个模糊测试脚本来对目标服务进行测试,脚本内容如下,Python 脚本执行后会对目标FTP服务进行发包测试。
# coding:utf-8
import socket,time
def initCount(count,Inc):
buffer = ["A"]
while len(buffer)<=50:
buffer.append("A" * count)
count = count + Inc
return buffer
def Fuzz(addr,port,buffer):
try:
for string in buffer:
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connect = sock.connect((addr,port))
sock.recv(1024)
command = b'send |/.:/' + string.encode()
sock.send(command)
sock.close()
time.sleep(1)
print('Fuzzing Pass with {} bytes'.format(len(string)))
except Exception:
print('\n This buffer cannot exceed the maximum {} bytes'.format(len(string)))
if __name__ == "__main__":
# initCount 10 说明从0开始递增,每次递增100
buff = initCount(0,100)
Fuzz("192.168.1.8",9999,buff)
上方的代码的构造需要具体分析数据包的形式得到,在漏洞模糊测试中上方代码中间部分的交互需要根据不同程序的交互方式进行修改与调整,这里测试脚本执行后当缓冲区填充为2200bytes
时程序崩溃了,说明该程序的send函数确实存在缓冲区溢出漏洞,其次该程序缓冲区的大小应在2200字节以内。
经过模糊测试我们可知该函数确实存在漏洞,为了能让读者更加深入的理解缓冲区发生的原因和定位技巧,我将具体分析一下其汇编代码的组织形式,这里为了方便演示我将在攻击主机进行逆向分析。
首先打开X64dbg将FTP程序载入并运行,接着我们需要使用Netcat链接本机 nc 192.168.1.2 9999
并进入一个可交互的shell环境中,然后输入待发送的字符串不要回车。
接着我们回到X64DBG按下ctrl + G
在recv函数上下一个断点,因为程序接收用户输入的功能需要使用recv函数的,所以这里我们直接下断,然后运行程序,发送数据后会被断下,我们直接回到程序领空,会看到以下代码片段,这里我们需要在 0040148D
这个内存地址处下一个F2断点,然后取消系统领空中recv上的断点。
通过再次发送send | hello lyshark
程序会被断下,我们单步向下跟进会发现下面的代码片段,这里正是我们的send
函数所执行的区域,此处我们记下这个内存地址 004017D5
然后关闭X64dbg
打开IDA Pro加载程序并按下G键,我们来到刚刚的内存地址处,这里已经给大家分析好了,关键的变量是分配了3000
个字节的缓冲区,直接传递给了_Function3
函数。
接着我们继续跟进这个call _Function3
函数,会发现子过程内部并没有对接收缓冲区大小进行严格的过滤,强制将3000byte
的数据拷贝到2024byte
的缓冲区中,此时缓冲区就会发生溢出,从而导致堆栈失衡,程序崩溃,这和上方的模糊测试脚本得到的结果是差不多的。
为了能够更加精确的计算出缓冲区的具体大小,我们还需
控制EIP寄存器
构建漏洞利用代码
ROP技术绕过DEP保护
ASLR 如何绕过解析
将脚本集成到Metasploit
原创作品,转载请注明出处!i
原文地址:https://www.cnblogs.com/LyShark/p/12340479.html