Don’t Play with Fire: Prioritize Zyxel Firewall Update to Fix Unreported Vulnerability
Our analysis has identified multiple vulnerabilities affecting Zyxel’s USG line of firewalls and VPN appliances running firmware versions 5.36 and below. The vulnerabilities can allow an unauthenticated attacker to force the admin interface of the device to send an HTTP GET to any URL of the attacker’s choosing and store the full response on the device. This creates the potential for an XSS against the administrator account of the device, ultimately leading to full attacker control of the appliance. Likewise, an attacker could request an internal address, thus enabling a bypass of the firewall itself.
Notably, these issues are part of the Zero Touch Provisioning (ZTP) capabilities of the device and are thus intended to be exposed to the Zyxel Cloud, known as Nebula. The vulnerable interface is often internet-facing and exposed to potential attackers.
These vulnerabilities are not present in the most recent version of Zyxel firmware (5.37), released last year. Of note, Zyxel has disabled ZTP altogether as of V5.37 patch 1. Eclypsium notified Zyxel of the vulnerabilities but they declined to issue an advisory as the vulnerabilities are not present in the latest version of the firmware. However, since CVEs have not been issued for these vulnerabilities, organizations may not know that they need to update the firmware on their devices. As such, we encourage teams to update their firmware to the latest available version.
Analysis of Vulnerabilities
We identified vulnerabilities that could allow an attacker to manipulate a device in several ways including:
- Force the router to make an HTTP GET or POST of the attacker’s choosing
- Get the responses and store them on the router
- Make SMB requests
All of this can be performed just from an attacker having network visibility to the management UI—no credentials are needed.
Force the router to make any HTTP GET or Trusted HTTPS request
The script located at https://[target]/ztp/cgi-bin/twoFApincode lacks validation for the FQDN parameter. Intended values passed to it should point to Nebula, but we can insert any domain we like, given it starts with ‘https’ or does not start with the schema. Consider the following script:
In this case, we can pass any FQDN we want, say: example.com#, effectively removing any unwanted parameters. Also, posturl uses requests.post (1.0.4 requests) internally, which will follow redirects by default, so the target server can then redirect the POST request anywhere. Trust verification is based on a very permissive internal CA certs file, which trusts many certificate authorities (notably, it does NOT work with Let’s Encrypt). As such, we can:
- Send a POST request without a body and any query string we like to any trusted HTTPS target
- Send a GET request with any query string we like to any trusted HTTPS target
- Send a GET request with any query string we like to any HTTP target (thanks to the redirect).
The request can target any URL or IP address that the firewall will be able to see, including loopback interface. This means that in addition to forcing the firewall to visit a malicious domain, an attacker could also use this vulnerability to perform a bypass of the firewall itself.
The following simple proof-of-concept script illustrates how we can force an HTTP POST:
Getting the response back (Dumping ZTP logs)
At this point, we have managed to make a request to any target of our choosing, but we did not get the response back. Luckily the response is stored in the ZTP logs and is easily accessible. We can dump the logs simply by querying a URL on the device , which … does not require authentication.
This request will get back all of the logs, and incidentally also the logged response (by thelogging.info(r.text) line from the previous issue).
Forcing SMB requests
Additionally, we identified a service on the router called proactor1.2, located at /usr/sbin/proactor1.2/pro. It seems to be an undocumented CIFS/SMB1.0 client that is exposed to administrative users. Combining it with the previous issues, we can use this client to force SMB requests. SMB Credentials are not included automatically so the attacker has to set them.
This redirect will force the router to attempt to connect to port 445, and consecutively to port 139 on fail on host 10.1.1.1:
http://127.0.0.1:10444/cifs/10.1.1.1/test?action=browse&browser=1&use rname=admin&passwd=1&pattern=&
Crashing the SMB client service
If the URL passed to the SMB service is malformed, the service crashes with the segmentation fault message printed out if you run it manually. This is the specific URL that was able to cause a crash:
http://127.0.0.1:10444/cifs/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Key takeaways
One of the things that makes supply chain security so tricky is that vulnerabilities are often hidden behind the vendor’s curtain. Vulnerabilities may be hidden in low-level code and components that traditional scans don’t see. Likewise, vulnerabilities can affect the vendor’s overarching management processes such as how updates are delivered, or in this case, how assets are provisioned and managed.
Zero-touch provisioning options are great, enabling IT teams to easily deploy firewalls. However, we always have to remember that these conveniences are also trade-offs. The more that things are done “automagically,” the more trust we are putting in our vendors, and the more crucial it is to be able to verify that product components are secure.
Vendors should be transparent about the vulnerabilities that affect these systems. Enterprises often don’t update firewall firmware unless there is a good reason. So if there is a glaring vulnerability that could allow an attacker to take control of the device, then customers absolutely need to know about it.
For any questions or comments regarding this research, please reach out to the Eclypsium team at [email protected].