0x00 写在前面
本实验是对 CVE-2018-5767 漏洞的调试分析和复现,所有实验过程均在本地搭建的虚拟机中进行。通过该实验比较深入地理解了该漏洞的成因和利用过程。
请严格遵守所在地法律法规。
0x01 环境搭建
调试环境搭建
使用 peda
将导致只能正常断点和运行,无法显示寄存器及相应参数状态。所以这里还是需要使用 pwndbg
。
pwndbg
的安装也没有那么难,看网上的教程说人家必须要 python.xxx
,所以还去卸载并安装 python
就傻了,其实人家是一个逐步移除支持的过程,在 issue
中有说到在哪个版本移除了 Ubuntu18.04
中默认的 python3.6
的支持,所以只需要 clone
了后,再`checkout
到支持的分支中即可。
这里随便选择了一个支持的正式版本,然后按照官网安装即可,一瞬成功:https://github.com/pwndbg/pwndbg/tree/5d4026d647806f1c06e787120e51aab3c7a560de。
ROPgadget
的安装也是按照 GitHub
官 方仓库中的命令执行即可。
qemu
的安装也是普通的安装即可。
固件提取
本次调试是在 Ubuntu18.04
环境下,借助 qemu-arm-static
进行的,调试使用 gdb
和 ida
结合着。
存在问题的固件为:Tenda AC15 15.03.1.16_multi
该存在漏洞的固件 US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin
下载完成进行固件的分析,使用 binwalk
提取即可,它会自动将其解压形成一个文件夹,同时能看到该固件的格式为arm小端
1 | binwalk -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin |
然后找到存在漏洞的文件 文件系统 squashfs-root
及下面的 httpd
。
chroot,即 change root directory (更改 root 目录)。在 linux 系统中,系统默认的目录结构都是以 /,即以根 (root) 开始的。而在使用 chroot 之后,系统的目录结构将以指定的位置作为 / 位置。
1 | cd xxx.bin.extracted/squashfs-root |
固件patch
由于是 arm
架构的,所以需要借助 qemu
进行模拟调试,由于模拟的环境缺少真机中的一些必要的组件直接运行可能无法工作,因此需要进行 patch
将一些其他不重要的检测进行过滤。通过将 httpd
在 ida 中打开后,全局搜索字符串 Welcome to
然后定位到下面这个比较的地方,将两个比较指令 patch
掉。
经过对比发现 MOV R3 R0
对应的机器码是 00 30 A0 E1
,然后给它改成 01 30 A0 E3 00 00 53 E3 02 00 00 CA 01 00 A0 E3
,然后导出就 patch
成功,然后放置在原来的位置进行替换,此时再执行就绕过了此处的检测,再执行就会成功走到 Connect to server failed.
了,然后就服务启动成功了
1 | 2cf90 |
网络配置
在 qemu
进行模拟调试时需要先进行网络环境的配置,不然可能等下的 IP
地址会很奇怪。可以参考这个文章进行网络环境的配置,如果在执行过程中出现一个报错,应该是里面的有一个自定义写的脚本 /etc/qemu-ifup
依赖不够,所以安装一下即可。
然后保存 patch
后 将 httpd
拷贝进去进行替换原始文件并添加权限即可。
出现上述界面环境就配置成功了。
0x02 漏洞分析
这个程序的漏洞很简单,就是未对输入数据进行检查,具体而言是未对用户提供的 HTTP
报文中的 cookie
字段进行长度检查,然后就直接将数据拷贝到缓冲区进行处理,造成了栈溢出。
在 ida
中进行查看,在第 87
行将从用户提供的 cookie
中提取 password=
后面的字段,如果提取成功则直接将其中的数据使用 sscanf
读取的缓冲区 v33
中。
而 v33
是定义在函数开头的局部变量,其大小只有 128
字节,因此当用户输入过长时将会溢出该缓冲区。
这里我就懒得去一步一步分析控制流找到这个参数具体是哪部分受控的,我们直接简单粗暴,往这个接口中灌入很长的
password
参数,观测程序是否崩溃来看我们是否能正常触发这个接口,如果不能再进一步调试找条件。
0x03 漏洞调试
先运行一个 poc
观测程序崩溃
1 | #!/usr/bin/python |
可以发现下面的程序运行后,原程序崩溃,触发了 Segment fault
。
此时,重新启动程序,以 qemu
支持的远程调试模式进行启动。将安装好的 qemu-arm-static
拷贝到该文件系统的根目录中,然后执行命令
1 | sudo chroot ./ ./qemu-arm-static -L ./ -g 1234 ./bin/httpd |
即可开启一个 gdb
的远程调试 server
,此时可以使用 gdb
进行连接即可,但是由于是跨架构的调试,所以需要使用 gdb-multiarch
,于是在文件系统根目录中执行 gdb-multiarch ./bin/httpd
将读取该文件,准备进行调试。
然后使用命令 target remote :1234
即可成功连接过去,如下图所示,可以看到成功连接了
为了确定程序溢出时,溢出数据覆盖栈中关键数据的偏移,需要修改 PoC
中的填充数据,这里可以简单使用 cyclic
来生成 4
字节不重复的输入填充,然后更新新的 PoC
然后在漏洞函数 R7WebsSecurityHandler
退出前下断点,这个通过 ida
可以看到是 0x002ED18
。
所以在程序中下断点:b * 0x002ED18
,而后运行程序 c
,此时 qemu
中的程序会继续执行,可以看到其输出了一系列的 log
信息后,在进行 http
服务的监听,等待连接,此时运行新的 PoC
触发断点。
可以看到此时触发断点时栈中的数据,溢出位置的数据是 0x65616170
,对应 paae
,所以找到了溢出位置的偏移是 460
。
继续运行程序,在函数结尾停止后,观测到 PC
填入时,最后 1bit
被置为 0
了(0x6561616d->0x6561616c
),这是因为 ARM
模式与 thumb
模式的切换问题:通常 PC
指针指向的地址都是 4
字节对齐,即地址的 [1:0]
位总是为 0
,这也是我们说的 ARM
模式。现在很多 CPU
都支持混合编码即同时支持 ARM
指令和 Thumb
指令,因此为了区分 Thumb
指令,ARM
将 [0]
位设置成 1
,即地址最低位如果是 1
,表示当前指令是 Thumb
指令,否则为 ARM
指令。在函数退出时执行了 pop pc
的操作,而最低有效位(LSB)将会被写入到 CPSR
寄存器的 T
位中,而 PC
本身的最低位则会被置零。
此时要进行栈溢出的利用,需要该漏洞程序开启的保护,如下图所示可以看到保护机制开启了 NX
,因此我们需要使用 ROP
链进行利用。
所以,先找找 gadget
,先找一个 gadget
命令为:
1 | ROPgadget --binary ./lib/libc.so.0 --only 'mov|blx' |
再找一个 gadget
1 | ROPgadget --binary ./lib/libc.so.0 --only 'pop' |
这两条指令的选取时需要是对应的寄存器,即 mov r3、pop r3
,最终选取的指令如下:
1 | 0x00040cb8 mov r0, sp; blx r3; |
在拥有了 gadget
后,需要获取 libc
的基地址,由于关闭了 ASLR
,所以可以直接从程序中读取函数并减去偏移计算出基地址。
在 pwndbg
中查看 strcmp
的地址,并在 ida
中看 libc
的偏移,计算即可。
此时,结合获取到的 ROP
链和程序覆盖时的偏移位置,可以构建 exp
其中构建的 payload
为:
1 | pl='a'*444+".png"+p32(pop_r3)+p32(puts)+p32(mov_r0)+_str |
pop_r3
对应 448
,puts
对应 452
,mov_r0
对应 456
,_str
对应 460
。
再结合前面的图进行分析,pop_r3
将被放置在 stack04
,puts
被放置在 stack05
,mov_r0
将被放置在 stack06
,_str
将被放置在 stack07
。
修改完毕后,重复上面的过程,再次走到断点处,观测其中的数据如下图所示,可以看到成功让 PC
能走向 ROP
链 ,此时停在断点处,马上 GO
!同时发现栈中的结构也与构想一致。
此时继续执行程序,成功执行 puts
函数,并且打印了自定义字符串 Hello
。
那 getshell
只需要将函数换成 system
,参数换成 /bin/sh
即可。
如下图所示,可以看到此时执行的 PC
指令即 system
而对应的参数在 R0
中即 /bin/sh
,于是可以完成 getshell
。
但是其实是没有成功的,按照网上的说法,qemu
对 /bin/sh
的模拟存在缺陷,因此直接使用程序会报错,会崩溃。即使出现了下面这正确的布局数据依然是不得行的。
0x04 内存布局变化图
最终在调试过程中的一些关键位置时的内存变化图如下
0x05 exp
这个能打印,但是 system
跑不起来。
1 | import requests |
0x06 参考链接
Tenda-AC15栈溢出漏洞复现:https://www.52pojie.cn/thread-1674625-1-1.html
CVE-2018-5767:https://wzt.ac.cn/2019/03/19/CVE-2018-5767/