前言:该篇文章的学习主要是由于在复现 CVE-2020-8423 的过程中遇到了一点关于动态调试的问题,学长推荐了一篇文章是关于这个漏洞的,于是来这里学习一下动态调试的方法。
环境搭建:
固件分享链接(是 cCor4ng3 师傅的)夸克网盘,链接:https://pan.quark.cn/s/38df4f0919b4,提取码:6AEk
binwalk 解包固件:
1 | binwalk -Me CVE.bin |

1 | readelf -h ./busybox |

1 | #安装qemu和arm的动态链接库 |

1 | sudo chroot ./ ./qemu-arm-static ./bin/httpd |
之后我们可以看到一系列报错:
1 | init_core_dump 1784: rlim_cur = 0, rlim_max = 0 |
我们可以打开 ida,去搜索这个 welome 字符串:

然后定位一下字符串出现的位置:

最开始 MOV R0,#1;MOV R3,R0;CMP R3,#0,显然是会执行红色的分支 sleep,最后返回 loc_2CF84 函数进行一个死循环,我们想要篡改死循环的状态,就可以把程序MOV R3,R0;修改为MOV R3,1;就可以进入右分支。
我们可以借助 rasm2 工具:
1 | # 1. 浅克隆最新代码 |

然后选中修改行,edit->patch program->change bytes 修改 values

修改过后我们可以看到程序汇编发生变化,这样就可以稳定进入右侧了:

保存修改之后(下面有说保存的方式),再次运行程序发现依旧卡住了,我们继续往下看汇编:

保存:

右侧依旧存在同样的问题,按照之前的方式修改一遍之后保存,再次运行程序:

可以看到我们此时监听的是 81 端口,ip 为 255.255.255.255

搭建一个虚拟网桥
1 | sudo ip link add br0 type bridge |
sudo ip link add br0 type bridge- 含义:在系统中创建一个名为
br0的虚拟网桥接口(相当于在软件层面上新建了一个“虚拟交换机”)。 sudo ip link set eth0 master br0- 含义:将物理网卡
eth0插到网桥br0上,使其成为br0的从属接口(Master/Slave 关系)。此后eth0就像是虚拟交换机上的一个网线插口。 sudo ip addr flush dev eth0- 含义:清空物理网卡
eth0上原有的 IP 地址。因为网卡加入网桥后,IP 地址需要绑定在网桥br0上,而不是物理网卡本身。 sudo ip link set eth0 up- 含义:启用物理网卡
eth0(开启链路层连接)。 sudo ip link set br0 up- 含义:启用虚拟网桥
br0。 sudo dhcpcd br0- 含义:让网桥
br0发起 DHCP 请求,从局域网路由器重新获取一个新的 IP 地址。
配置前:电脑直接通过 eth0 上网,IP 地址绑定在 eth0 上。
配置后:数据流变为 外部网络 <-> eth0 <-> br0 <-> 本机/虚拟机,IP 地址绑定在 br0 上。后续创的虚拟机可以直接挂载到 br0 上,与本机处于同一个物理局域网段内。

最后再检测一下,打开:http://192.168.206.148/goform/getProduct如下返回即为配置成功

漏洞分析:
依据 POC 我们可以知道,漏洞点存在于 R7WebsSecurityHandler 函数当中:

找到 password=这里:

"%*[^=]=%[^;];*"是一个正则表达式,表示跳过等号”=”前面的所有内容,并提取等号和分号”;”之间的值。
正则这里之前学 web 的时候了解过,不过忘完了,看看 ai 的解释:
1 | %*[^=] |
这里没有对用户的输入进行过滤,因此有机会覆盖掉堆栈劫持程序流
想要执行到这里,首先需要满足前面的 if 判断:

这里我们直接使用"/goform/xxxx"即可
先进行简单的溢出尝试,开启另一个终端用 gdb 连上远程调试:
1 | sudo chroot ./ ./qemu-arm-static -g 1234 ./bin/httpd |
1 | gdb-multiarch ./bin/httpd |
然后使用 python requests 库来构造 HTTP 请求:
1 | import requests |
在我们的 exp 发送后,发现到有几项寄存器被写入了”aaaa”,debug 中得到了报错信息:Cannot dereference [0x61616161]表示 strstr 函数在试图读取内存地址 0x61616161 时发生非法访问报错(Segfault)。

Payload 在达到目标 sscanf 溢出点之前,先破坏了上一级函数传入的指针结构。当程序试图调用 strstr(a1->param, "password=") 时,读取到了被覆盖的无效地址(0x61616161),导致提前崩溃。
bt 看一下调用路径,发现在 0x2c5cc 进行报错:

跟踪 0x02c5cc 发现位于 sub_2c568 当中:


0x2c5cc在溢出后被执行,该子函数会卡住程序,因此我们要考虑去绕过这个函数:
在 R7WebsSecurityHandler 函数的下方还有一个 if 判断,若为 false 则可以直接跳转到函数末尾:
可以在 IDA 当中看一看,该 if 的小括号包含了下面的所有代码:

这段代码主要通过memcmp函数判断是否为“gif、png、js、css、jpg、jpeg”字符串,比如存在“.png”内容时,memcmp(v44, "png", 3u)的返回值为0,这个时候就会返回 false 跳转到函数最后。
1 | import requests |

可以发现 cyclic 触发了中断,可以去测一下偏移:

最终我们测出来的偏移是 444
但是这里有一个需要注意的地方:崩溃的返回地址显示是0x6561616c(‘laae’),我们还需要观察CPSR寄存器的T位进行判断,CPSR寄存器的标志位如下图所示:

涉及到 ARM 模式(LSB=0)和 Thumb 模式(LSB=1)的切换:栈上内容弹出到PC寄存器时,其最低有效位(LSB)将被写入CPSR寄存器的T位,而PC本身的LSB被设置为0。在 pwndbg 当中执行 p/t $cpsr 以二进制格式显示 CPSR 寄存器,发现 T 位值为 1,因此需要在之前的报错地址上手动加一还原
1 | ARM 架构中利用栈溢出覆盖 PC 寄存器实现指令集切换(ARM <-> Thumb)的底层原理: |

最后测出偏移实际上是 448

漏洞利用:

开启了 NX 保护,那就尝试去使用 ret2libc
在 Linux 系统中,可以通过查看或修改内核参数文件 /proc/sys/kernel/randomize_va_space 来确定是否开启了地址空间布局随机化(ASLR)。
1 | cat /proc/sys/kernel/randomize_va_space |
0:已关闭 (Disabled):完全禁用 ASLR,栈、堆和共享库地址每次运行均固定。
1:部分开启 (Conservative):开启栈、VDSO 和mmap地址随机化,但堆 Heap 地址固定
2:完全开启 (Full):在 1 的基础上,进一步开启堆(Heap,brk)地址随机化(默认开启值)。
临时修改(需 root 权限):
- 关闭 ASLR:
echo 0 > /proc/sys/kernel/randomize_va_space - 开启 ASLR:
echo 2 > /proc/sys/kernel/randomize_va_space


之后我们去拿 puts 函数,调用 puts 函数打印 str,如果执行成功,就是一个任意函数可执行漏洞:

之后我们想要查看 libc_base,使用 vmmap 发现不可以,后来询问学长,给出的解答是:vmmap读的是proc这个路径,因此 qemu 不能用 user 调试,而我们前面开的是 user,需要用 system-arm 去调试才能够读到。

那就换一个路径:info sharedlibrary

我们可以看到此时 lib/libc.so.0 的 libc_base 是 0x3fde000,但是经过 exp 的编写发现这个偏移也不对…….
于是看一看 puts 函数距离当前这个 libc 的偏移:0x3acd4,而前面拿到的 puts 偏移实际是 0x35cd4,也就是说 libc 表偏移是死的,那就是 libc 基址实际上并非 0x3fde000,而是 puts 实际地址减去实际偏移

libc_base = puts_addr - puts_offset = 0x3fde5000

可以拿这个 base 去看一看 gadgets 的偏移是否正确:发现偏移处依旧是我们寻找的 gadgets。

保险起见我们重启 gdb 重复这个操作,得到 libc_base 确实是不变的
确定了 libc_base 之后我们就可以构造 exp 了:
1 | import requests |
exp 并不难,就是调用了 puts 函数打印自己想要打印的字符串,前面偏移和绕过我们都讲述过了:

最终执行成功,确定了存在任意代码执行漏洞。
收获还是很大的,学习了如何利用 requests 包去测偏移,学习了在不开启 alsr 的情况下获取 libc_base 的方法
参考资料:
说些什么吧!