~8 min read
Your router might be a security nightmare: Tales from Pwn2Own Toronto 2022

This blogpost is the second part of our two-part series looking back at our accomplishments and journey to Pwn2Own 2022 in Toronto. The previous instalment detailed our journey in exploiting the HP M479fdw printer. We also cover our journey through the 2024 edition of Pwn2Own in Cork, Ireland, starting with the first post on exploiting the Canon imageCLASS MF656Cdw printer!
TL;DR
Back in 2022, Neodyme competed at Pwn2Own Toronto, uncovering several vulnerabilities in the Netgear RAX30 router. By chaining these bugs into a full “SOHO Smashup” (Small Office/Home Office) exploit, we earned a $50,000 prize. This blog post walks through the technical details of that journey — from initial discovery to a successful WAN-side exploit.
Intro
Participating in Pwn2Own had been on my to-do list for a long time and three years ago, I finally gave it a shot. Together with my colleagues at Neodyme, we decided to target the “SOHO Smashup” category at Pwn2Own Toronto 2022. The goal: exploit a router via its WAN interface, then pivot to another device on the LAN. Our target chain involved a Netgear RAX30 router and an HP M479fdw printer.
Netgear devices had already appeared in two previous Pwn2Own competitions, so we had a few solid write-ups from other researchers to learn from. That helped us gain a head start in understanding the target. After all, a router is really just a Linux box with an antenna, right?
Attack Surface Discovery
We started by just downloading the official firmware and extracting it with binwalk. The firmware was unencrypted and the rootfs already showed many interesting binaries. But with such a large attack surface, it is important to rule out the mundane parts as much and soon as possible.
This can easily be done dynamically by looking a which services are running and which services are exposed, and all we need for this is a shell.
After spending some time exploring potential entry points, we found our first bug that gave us a shell — but unfortunately, it didn’t meet the criteria for Pwn2Own :(
However, during the exploitation process, we stumbled upon an even easier way to get a shell:
The router automatically executes PHP files placed on a USB thumb drive. ¯\_(ツ)_/¯
By uploading some generic shell.php
(taken from the internet), we quickly gained a reverse shell, giving us a foothold on the device and allowing us to move forward.
With access to the running system, tools like ps
and netstat
helped us narrow down the attack surface, letting us focus on the services that were left.
Eventually, one of my colleagues discovered a bug in the JSON parser of the fing_dil
binary.
The fing
service is used to map MAC addresses to device names and is enabled by default.
It queries all MAC addresses from a database and sends them to https://netgear-devrecog.fing.io/2/devrecog
, which in return responds with JSON data like this:
{
"devices": [
{
"recognition": {
"type-group-name": "Network",
"mac-vendor": "LG Electronics",
"rank": 75,
"model": "Galaxy S6",
"os-name": "Android",
"type": "ROUTER",
"brand": "Apple",
"os-ver": "5.0.0",
"type-name": "Router"
},
"mac": "001122334455"
}
],
"networks": [
{
"recognition": {
"InternetInfo": {
"hostname": "leet.host.name",
"regioncode": "RM",
"city": "Rome",
"timezone": "America/Los_Angeles",
"countrycode": "IT",
"isp": "Verizon",
"organization": "Verizon",
"continentcode": "EU"
}
}
}
]
}
Below, we provide the code that interprets the response. Maybe you can spot the bug? However, this snippet is just an example — there are more fields that are vulnerable to the same bug:

Response parsing code
The code is retrieving the length of the JSON property value via strlen
and is not restricting the size to the length of the destination buffer used in the following memcpy
after that.
Yes, this is just a basic stack buffer overflow ;), but the binary will surely have stack canaries, right?

Yes, this is state of security in a major brands router in 2022, yikes. They could have at least also made the stack executable :(
Exploitation
To exploit the bug we would need to MITM the request but the traffic is SSL encrypted.
Unfortunately to them, they explicitly disabled certificate validation in curl
, so that didn’t pose a problem.
Since by then, we already had code execution on the router, we immediately attached gdb
to the process to help us with harnessing the overflow.
For testing, we redirected the request for the fing-api
to our own server, responding with a cyclic pattern in the device type.
With this, we successfully crashed the application.

State of the executable after our payload
…and gained control over the registers r4
to r11
and pc
, awesome!
Since the checksec
output earlier showed us that the binary has neither stack canaries nor PIE, this exploit should be ROP101, ezpz.
Well, the fing_dil
binary isn’t compiled as PIE, but it’s loaded at a fixed base address of 0x00010000
.
Unfortunately, that address begins with a null byte as its most significant byte.
Since we are using strlen
, our input gets cut off early, as we stop at a nullbyte :( .
Additionally, system-wide ASLR is enabled, so external library addresses are randomized.
These circumstances limit our control over the stack. We can only use a one-gadget, and it has to be located within the binary itself; plus that gadget would need to create a reverse shell. Of course, there’s always a chance that the perfect gadget for these harsh conditions exists, but this was not the case for us this time.
But since we are CTFers we got creative and had a shell the next day anyway ;)
As mentioned earlier, our primitive gave us control over registers starting from r4
.
This also means that r0
to r3
remained untouched, with r2
and r3
containing valid data.
It should be noted that an invalid address read crashes the program and the service wouldn’t restart automatically.
Leveraging our arbitrary read primitive, we tried to leak a library address by jumping back into the HTTP request handling code.
The idea was to have the router send us a pointer address as the value of the Content-Length
header, and then respond with our overflow payload again to retain control over the execution flow.
If successful, the next step would be to leak a got
table address and do a textbook ROP from this point.
However, this approach often failed to return a libcurl address; instead, we would receive a pointer to the heap.
It remains a mystery why this happened, but the behaviour definitely helped us in the following steps.
If the leaked heap address points to somewhere > 0x10000000
we are good to go and may create a nullbyte-free ROP chain.
Otherwise, we need to rely on luck.
We noticed that most heap allocations with a size of 16MB end up around 0xB00...
, so after spraying af few crafted objects onto the heap, we could somewhat assume that 0xAF010101
had been allocated with our data and hope for the best with a one-shot exploit path.
Regardless of which path succeeded, we eventually achieved remote code execution.
To persist access, we created a cronjob that spawned a minimal reverse SSH server, providing us with an interactive session.
This is accomplished by jumping to a function in the binary that allowed us to create a file in /var/spool/cron/crontabs
, the directory used by the Cron service.
On the Pwn2Own Main Stage
Like advertisements of toothpaste, we only rated the effectiveness or success rate of our exploit around 99% and at the competition we were reminded of that fact, as our exploit failed in our first try :(
But as with everything that’s performed live, these things happen and our second attempt worked without issues and let us continue our SOHO smashup chain with the HP M479fdw printer, which you can read more about in our previous blogpost. Overall we learned quite a lot about fault-proofing our exploit for the competition and were eager to try again at more Pwn2Own competitions. Don’t forget to check out the first blogpost in the next series about our exploits and setup for 2024 in Ireland!
We at Neodyme thrive in complex challenges and are always eager to dive deep into custom protocols or architectures, providing expert level insights to our clients. Just get in touch if you need research driven assessments tailored to your needs, we are happy to face those challenges!