As a number of my projects start, when I heard that Pwn2Own Mobile 2021 had been announced, I set about looking at one of the targets. Having not looked at the Netgear device when it appeared in the 2019 contest, I decided to give it a lookover.
While going through various paths through various binaries, I came across a kernel module called NetUSB. As it turned out, this module was listening on TCP port 20005
on the IP 0.0.0.0
.
Provided there were no firewall rules in place to block it, that would mean it was listening on the WAN as well as the LAN. Who wouldn’t love a remote kernel bug?
NetUSB is a product developed by KCodes. It’s designed to allow remote devices in a network to interact with USB devices connected to a router. For example, you could interact with a printer as though it is plugged directly into your computer via USB. This requires a driver on your computer that communicates with the router through this kernel module.
It’s licensed to a large number of other vendors for use in their products, most notably:
Back in 2015 a different NetUSB vulnerability was discovered. From that came some great resources (including a very helpful exploit for that vulnerability by bl4sty which helped quickly verify this vulnerability).
The handshake used to initiate a connection is as follows:
After the handshake, a command-parsing while-loop is executed that contains the following code:
SoftwareBus_fillBuf
acts in a similar way to recv
by taking both a buffer and its size, filling the buffer with data read from the socket.
The command 0x805f
reaches the following code in the function SoftwareBus_dispatchNormalEPMsgOut
:
4 bytes are fetched from the remote PC. The number 0x11
is added to it and then used as a size value in kmalloc
. Since this supplied size isn’t validated, the addition of the 0x11
can result in an integer overflow. For example, a size of 0xffffffff
would result in 0x10
after 0x11
has been added to it.
This allocated region is then used and written to through both dereferencing and through the SoftwareBus_fillBuf
function:
Looking at the final call to SoftwareBus_fillBuf
, the supplied size is used as a maximum value to read from the remote socket. From the previous example, the size 0xffffffff
would be used here (not the overflown value) as the size sent to recv
.
Along with our report, we sent a suggested mitigation strategy. Before allocating memory with user supplied sizes, an integer overflow check should be performed, as so:
if(user_supplied_size + 0x11 < 0x11) return;
From an exploit perspective, there are a number of things to consider.
First, the minimum size we can allocate is 0x0
and the maximum is 0x10
. That means that the allocated object will always be in the kmalloc-32
slab of the kernel heap.
Second, we need to consider the amount of control over the overflow itself. We already know that the data being received over the socket is within control of the attacker, but is the size negotiable in any way? Since a size of 0xffffffff
is not realistically exploitable on a 32-bit system, it’s necessary to take a look at how SoftwareBus_fillBuf
actually works. Underneath this function is the standard socket recv
function. That means that the size supplied is only used as a maximum receive size and not a strict amount, like memcpy
.
It’s also important to consider how easy it is going to be to lay out the kernel heap for the overflow. Many exploits require the use of heap holes in order to make sure that the vulnerable heap structure will be placed before the object that will be overwritten. In the case of this kernel module, there’s a timeout of 16 seconds on the socket for receiving data, meaning the struct can be overflown up to 16 seconds after it is allocated. This removes the need to create a heap hole.
Finally, the selection of target structures that could be overwritten needs to be considered. There are some constraints as to which ones can be used.
kmalloc-32
.While these restrictions make it difficult to write an exploit for this vulnerability, we believe that it isn’t impossible and so those with Wi-Fi routers may need to look for firmware updates for their router.
Since this vulnerability is within a third party component licensed to various router vendors, the only way to fix this is to update the firmware of your router, if an update is available. It is important to check that your router is not an end-of-life model as it is unlikely to receive an update for this vulnerability.
Exploring the Netgear firmware update, the vulnerability was patched by adding a new size check to the function:
This vulnerability affects millions of devices around the world and in some instances may be completely remotely accessible. Due to the large number of vendors that are affected by the vulnerability, we reported this vulnerability directly to KCodes to be distributed among their licensees instead of targeting just the TP-Link or the Netgear device in the contest. This ensures that all vendors receive the patch instead of just one during the contest.
While we are not going to release any exploits for it, there is a chance that one may become public in the future despite the rather significant complexity involved in developing one. We recommend that all users follow the remediation information above in order to reduce any potential risk.
SentinelOne’s responsible disclosure policy can be found here.