Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2021-34730 — Cisco RV110w UPnP stack overflow | Kitploit
Tools/GitHubGitHub/badmonkey7/cve-2021-34730
Embedded Systems SecurityIoT SecurityVulnerability AnalysisExploitationReverse EngineeringDebuggersNetwork SecurityHardware HackingFirmware AnalysisBinary Exploitation
GitHubbadmonkey7/cve-2021-34730

CVE-2021-34730

2874 years agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Cisco RV110w UPnP stack overflow

View Repository

Cisco RV110W UPnP 0day Analysis

Preface

UPnP has been a hot topic recently. I happened to have a Cisco RV110W device on hand. In August 2021, Cisco officially disclosed a 0day regarding UPnP in the RV series, but the specific details were not published. So I wanted to debug and exploit this vulnerability using the device. The vulnerability advisory can be seen on the official website.

Preparation

First, update the firmware to the latest version 1.2.2.8. The next challenge is how to debug and locate the vulnerability. The first step in debugging is to get a shell on the device. However, the latest firmware does not provide a debug interface. I obtained debug access to the latest firmware via UART and by modifying the firmware package. For the specific method, refer to a previous article I wrote: Router Debugging: Getting a Shell.

Debugging Preparation

The Cisco RV110W uses the MIPSEL architecture, so we need a corresponding gdb-server. You can either cross-compile one yourself or use a pre-compiled one. I recommend gdb-static-cross.

Vulnerability Location

The official advisory indicates the vulnerability exists in the UPnP service. First, log into the admin panel, go to FireWall → Basic Settings, and enable UPnP.

Untitled

Then scan the ports with nmap, but the UPnP port is not found. However, testing shows that UPnP is indeed open.

Untitled

Here I use UPnPy for vulnerability testing and exploitation.

root@kitploit:~
import socket
msg = \
    b'M-SEARCH * HTTP/1.1\r\n' \
    b'HOST:239.255.255.250:1900\r\n' \
    b'ST:upnp:rootdevice\r\n' \
    b'MX:2\r\n' \
    b'MAN:"ssdp:discover"\r\n' \
    b'\r\n'

# Set up UDP socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((b"192.168.2.100",23333)) # local IP
s.settimeout(2)
s.sendto(msg, (b'239.255.255.250', 1900))
addr = ('192.168.2.1', 1900) # gateway IP
try:
    while True:
        data, addr = s.recvfrom(65507)
        print(addr,data)

except socket.timeout:
    pass

Indeed, we receive a UPnP response, and there is a corresponding UPnP process running on the device.

Untitled

Service Analysis

UPnP is a general protocol standard, and most vendors implement it according to the standard, meaning many actions are identical. However, it is still necessary to analyze the services provided by the device to locate and exploit the vulnerability. Again, use UPnPy to gather information.

root@kitploit:~
import upnpy
import socket

import requests
from upnpy.ssdp.SSDPDevice import SSDPDevice
msg = \
    b'M-SEARCH * HTTP/1.1\r\n' \
    b'HOST:239.255.255.250:1900\r\n' \
    b'ST:upnp:rootdevice\r\n' \
    b'MX:2\r\n' \
    b'MAN:"ssdp:discover"\r\n' \
    b'\r\n'

# Set up UDP socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((b"192.168.2.100",23333))
s.settimeout(2)
s.sendto(msg, (b'239.255.255.250', 1900))
addr = ('192.168.2.1', 1900)
data = b""
try:
    while True:
        data, addr = s.recvfrom(65507)
        print(addr,data)
except socket.timeout:
    pass

# data = b'HTTP/1.1 200 OK\r\nCache-Control: max-age=120\r\nDate: Fri, 01 Jan 2010 00:44:16 GMT\r\nExt: \r\nLocation: http://192.168.2.1:1780/InternetGatewayDevice.xml\r\nServer: POSIX UPnP/1.0 linux/5.70.48.16\r\nST: upnp:rootdevice\r\nUSN: uuid:31474a87-67ea-dae4-2f73-f157fb06d22b::upnp:rootdevice\r\n\r\n'
# data = b'HTTP/1.1 200 OK\r\nCache-Control: max-age=3600\r\nST: upnp:rootdevice\r\nUSN: uuid:824ff22b-8c7d-41c5-a131-8c3bad401726::upnp:rootdevice\r\nEXT:\r\nServer:  Unspecified, UPnP/1.0, Unspecified\r\nLocation: http://192.168.3.1:56688/rootDesc.xml\r\n\r\n'

device = SSDPDevice(addr, data.decode())
services = device.get_services()

services_id = [services[i].id.split(":")[-1] for i in range(len(services))]

for id in services_id:
    service = device[id]
    actions = service.get_actions()
    for action in actions:
        for argument in action.arguments:
            print(id,action.name,argument.name)

This yields a series of service information, partially listed below:

root@kitploit:~
WANIPConn1 AddPortMapping NewRemoteHost
WANIPConn1 AddPortMapping NewExternalPort
WANIPConn1 AddPortMapping NewProtocol
WANIPConn1 AddPortMapping NewInternalPort
WANIPConn1 AddPortMapping NewInternalClient
WANIPConn1 AddPortMapping NewEnabled
WANIPConn1 AddPortMapping NewPortMappingDescription
WANIPConn1 AddPortMapping NewLeaseDuration
WANIPConn1 DeletePortMapping NewRemoteHost
WANIPConn1 DeletePortMapping NewExternalPort
WANIPConn1 DeletePortMapping NewProtocol
WANIPConn1 GetExternalIPAddress NewExternalIPAddress

These services can be roughly categorized into get-type, set-type, and a few delete-type services. Since one of the main purposes of UPnP is to expose internal network devices to external networks, certain configurations (such as port mapping) are necessary. As configuration requires parameters, these parameters are essentially the parameters in set-type services.

Service Location

Since not all services are implemented by the vendor, we need to reverse-engineer the firmware ourselves. First, locate upnp_mainloop.

Untitled

All processing logic is implemented in upnp_dispatch. Following that, we find the handling parts for SSDP and HTTP requests.

Untitled

ssdp_process handles the M-Search request during discovery, while upnp_http_process handles HTTP requests. Since normal service calls are HTTP requests, it is likely that upnp_http_process contains the vulnerability. An example of a service call is shown below.

Untitled

Inside upnp_http_process, it further calls upnp_http_fsm_engine.

Untitled

Following that, we find that it executes several functions at off_45ab80.

Untitled

These functions include initialization and protocol header parsing. The last function is upnp_http_fsm_dispatch, which is suspected to call the corresponding service function.

Untitled

Following upnp_http_fsm_dispatch, we indeed find that it calls function methods, but it does so based on a1 and a2, making it impossible to determine the specific called function without dynamic debugging.

Untitled

If it is a normal SSDP discovery request, it calls SUB_405B34 and description_process. If it is a service-related request, it calls soap_process. Inside soap_process, depending on the request header, it calls either query_process or action_process.

We focus on action_process. Based on the request header of service calls, we suspect that soap_control within action_process corresponds to service invocation.

Untitled

Inside soap_control, dynamic debugging is still required to determine the specific function information.

Untitled

Finally, through dynamic debugging, we confirm that sub_414C28 corresponds to the AddPortMapping action, with the function call chain:

root@kitploit:~
sub_414c28->upnp_portmap_add->upnp_osl_nat_config->strcpy(stack overflow)

However, inside upnp_portmap_add, the WAN interface IP of the device is checked. Since I did not configure a WAN interface during testing, I directly set the WAN IP via nvram.

Untitled

During stack overflow, we need to control the program flow to reach the red block, because the function in the blue block will access the overflowed stack, causing the program to crash before RCE. Therefore, we need to set the value of *(a2+11) to 0. Fortunately, this value is controllable.

Untitled

Exploitation

Since the latest firmware does not have telnetd, you can get a reverse shell and then upload a utelnetd to enable telnet.

display-exploit.gif

Refer to Various Ways to Get a Reverse Shell.

Download Tool