The Internet of Things (IoT) has become an increasingly popular target for cyber attacks in recent years because these devices are often poorly secured and can be easily compromised.
To highlight the vulnerabilities of IoT devices and encourage better security practices from manufacturers, the Zero Day Initiative (ZDI) organized a Pwn2Own competition last fall in Toronto that focused on hacking into IoT devices such as printers, network-attached storage (NAS) devices, routers, and smart speakers.
This competition brought together experienced hackers to demonstrate their skills in finding and exploiting vulnerabilities in these devices.
Here, we will explore the research we conducted on the Netgear RAX30 router for the Pwn2Own competition.
Bypassing Buffer Overflow Protections: Stack Canaries
When conducting research for a Pwn2Own competition, it is not uncommon to discover multiple vulnerabilities in the targeted device or software.
In fact, right at the beginning of our research, we identified several vulnerabilities that were trivially exploitable.
However, since the competition reduces points for duplicate issues, we knew that simply reporting these vulnerabilities would not be enough.
Instead, we decided to dig deeper and uncover more complex and novel vulnerabilities that would provide us with a competitive advantage.
It didn’t take long before we found an easy to find but difficult to exploit vulnerability in the soap_serverd process running on port 5000.
This process handles SOAP messages related to management functionality, mostly in the LAN.
This looked like a good candidate to exploit since we assumed most teams would go for the easy wins.
The vulnerability we found was a stack-based buffer overflow.
This class of vulnerabilities is usually trivial to exploit when there are no stack protections.
However, it turned out that a few versions back, Netgear decided to recompile all the binaries in the RAX30 router with stack canaries making the exploitation much harder.
Eventually we had to find and exploit five vulnerabilities in a cool chain that earned us five points in the Pwn2Own competition, where Team82 had success in a number of categories in addition to targeting routers.
This exploit chain can be leveraged by an attacker to gain pre-authentication remote code execution on affected devices.
Successful exploits could allow attackers to monitor users’ internet activity, hijack internet connections and redirect traffic to malicious websites, or inject malware into network traffic.
An attacker could also use these vulnerabilities to access and control networked smart devices (security cameras, thermostats, smart locks), change router settings including credentials or DNS settings, or use a compromised network to launch attacks against other devices or networks.
Before going into the details about the exploit chain we developed, let’s talk about stack canaries.
Stack canaries are a widely used security mechanism that help protect against buffer overflow attacks.
They work by placing a small value on the stack called a canary, which is checked for modification before a function returns.
If the canary has been tampered with, the program terminates to prevent further exploitation.
When looking into bypassing stack canaries you generally have three options:
- Find another vulnerability that could leak the canary from memory
- Brute-force the canary (This is possible only in specific cases)
- “Logically” bypass the canary: do something with the overflow before the canary is checked.
We will focus on the third option: logically bypassing the canary.
While this is something that is thrown around every time bypassing canaries is brought up, there aren’t that many real world examples where this technique is used.
Netgear devices have a dedicated server (soap_serverd) running on port 5000 (HTTP) and 5043 (HTTPS) that is used as a programmatic API (SOAP) for the router.
The exposed API allows users to query the device and change its configuration.
The server is mainly used by the NETGEAR Nighthawk App for iOS and Android.
There are more than 180 actions exposed by the server and they are sorted by the following categories:
Almost all of the functions exposed by the server require authentication.
NETGEAR RAX30 Vulnerability Details
CVE-2023-27357 NETGEAR RAX30 GetInfo Missing Authentication Information Disclosure Vulnerability
One of the few commands that does not require authentication is GetInfo. In the Get response, we can find details about the device such as the model, serial number, and more.
There is not much we can do with this information at this point but let’s keep this for later.
CVE-2023-27368: NETGEAR RAX30 soap_serverd Stack-based Buffer Overflow Authentication Bypass Vulnerability
To handle communication, soap_serverd reads the HTTP headers first and then proceeds to parse them using the sscanf function to extract the HTTP method, path, and protocol version.
The code above will split POST /soap/server_sa/ HTTP/1.1 into three parameters:
- method: POST
- path: /soap/server_sa/
- protocol: HTTP/1.1
As we can see in the calls to memset, each parameter (method, path, protocol) is expected to be no more than 0x7FC bytes long.
The server does not check the length of the method, path, and protocol fields meaning we can overflow them and overwrite data on the stack.
Unfortunately the HTTP receive function over TCP port 5000 limits the size of the HTTP header, thus limiting the amount of data we can overflow.
In order to avoid that limitation we used something a bit different.
CVE-2023-27369: NETGEAR RAX30 soap_serverd Stack-based Buffer Overflow Authentication Bypass Vulnerability
The soap_serverd binary listens for incoming messages on two ports:
- 5043 (SSL)
Different socket read and socket write functions are called depending on the port that the SOAP message was sent to.
When reading the SOAP message headers, the server reads data from the socket one byte at a time.
However, we discovered that in the SSL flow, the read function doesn’t check how many bytes were read, which could lead to a buffer overflow.
Reading unlimited data can result in two issues:
- Stack exhaustion: sending large buffers can read more than the stack size and crash the server
- Buffer is of unexpected size: The flow that parses the header expects them to be at a certain maximum size.
We can use this vulnerability to write long buffers on the stack while bypassing the overall buffer-size limit.
If we use SSL to send the SOAP message, we are not limited in size (due to the stack overflow mentioned above) meaning we can overwrite as much data as we want.
Bypassing stack canaries
Now that we understand the sscanf vulnerability and can trigger it without any limitations on how much data we can overwrite, we are left with only one issue: the stack canneries.
Once we overwrite data from the stack and right before the function that handles HTTP requests returns, the stack canary is checked and crashes the program.
In recent versions on the RAX30 router, NETGEAR started to compile the soap_soerverd binary with stack protections.
These protections make it much harder to exploit the stack overflow in the traditional way. Our approach to bypassing the stack canary was to try to (somewhat) logically bypass it.
Stack canaries are set at the beginning of functions that have the potential for an overflow, but are checked only at the end of the frame.
This means that by using the sscanf overflow, we can overwrite the canary, finish the request handling and response flow and only then get to the end of the function where the canary is checked.
Stack layout and calls
Since most of the SOAP commands require authentication, we focused on trying to bypass the authentication flow.
Function that checks authentication in soap_serverd
The first thing the server checks when authenticating users is whether the request came from 127.0.0.1 (localhost). Requests coming from localhost do not require authentication. Luckily we discovered that the socket source IP is stored on the stack in an offset we can overwrite with our stack overflow.
Using the stack overflow to overwrite the socket IP to 127.0.0.1 we are able to make the server think the request was generated locally, bypass authentication and run any soap_serverd command.
This vulnerability by itself is not enough because usually we are limited to 0x800 (2048), and so we chained it with the previous vulnerability over TCP port 5043 (SSL), which allowed us to write more data on the stack. The final payload we constructed was:
payload = POST + SPACE + (“a” * [REDUCTED]) + SPACE + (“b” * [REDACTED]) + “127.0.0.1” + (“c” * [REDACTED])
POST: HTTP Method
(“a” * [REDACTED]): Path (URI)
(“b” * [REDACTED]): Part of Protocol (padding)
127.0.0.1: Part of Protocol (data to overwrite on stack to bypass auth)
(“c” * [REDACTED]): Part of Protocol (padding)
Using the fake IP (127.0.0.1) as we see in the “After” image, we are able to bypass authentication and call any function the soap_serverd exposes as if we are fully authenticated. We decided to call the GetConfigInfo command which returns the entire router configuration including the device’s serial, MAC address, hashed passwords, and much more.
CVE-2023-27370: Using soap_serverd auth Bypass to Reset the Admin Password
When setting up the router, users are required to enter a new, unique password and provide security questions and answers that will allow them to restore the password if they forget it. The answers to these questions are stored in plain-text (base64) in the device configuration. In order to reset the device password, users need the serial number of the router and the answers to the security questions. Therefore, by getting the raw configuration using the three vulns above, an attacker will be able to reset the admin password.
We used this vulnerability in the Pwn2Own competition to reset the router’s admin password and chained it with CVE-2023-27367.
CVE-2023-27367: Authentication Bypass to RCE Using Magic telnet and Command Injection
In the past, researchers have discovered a “magic packet” that can enable Telnet on NETGEAR routers by enabling port 23 TCP in the firewall. https://github.com/davejagoda/NetgearTelnetEnable
The RAX30 router was no different. We discovered that it is still possible to send that “open-telnet-magic-packet” with a few changes from the previous models, and open Telnet.
The packet is built using:
- Device MAC address
- SHA256 hash of the password used to set up the router
In order to build the payload, we use the following (which we now have because we obtained a copy of the configuration and reseted the admin’s hash):
- secret key: “AMBIT_TELNET_ENABLE+” + sha256(password)
- cleartext: MAC (null padding 0x10) + username (null padding 0x10) + sha256(password) (null padding 0x50)
- hash: MD5(cleartext)
- (hash + cleartext) (null padding 0xb0)
- Create the magic packet – Use Blowfish algorithm to encrypt the payload with a secret key as the key.
After sending the magic packet, the device will run a telnet server and open port 23 TCP for new connections. However, now we face a new problem: the telnet interface is restricted to specific commands. We were jailed.
So, we had to look for another vulnerability, a command injection. We discovered that the TFTP command is not filtered before it is executed (CVE-2023-27370), which means that we can run any command using that interface.
This meant we now had shell access to the router (using the telnet service), and had the ability to execute arbitrary commands
Summary: PoC PreAuth RCE Flow
- Using CVE-2023-27357 (Sensitive Information Exposed Without Authentication), we retrieve the device serial number.
- Using CVE-2023-27369 (SSL Read stack overflow), we are able to send a HTTPs payload without size restrictions.
- Using CVE-2023-27368 (sscanf stack overflow), we are able to write a payload long enough to overwrite the socket IP, bypass authentication, and read the device configuration.
- Using CVE-2023-27370 (Plain text secrets in the configuration) to obtain the plain-text security questions and answers, and the serial number we got earlier we can change the admin password
- After changing the password we can send a magic packet to enable a restricted telnet server on the device
- Using CVE-2023-27367 (Restricted shell escape), we get root access remote code execution on the device
These five CVEs can be chained together to compromised affected RAX30 routers, the most severe of which enable pre-authentication remote code execution on the device. NETGEAR recommends users update these devices immediately.