Unveiling the Unauthenticated Command Execution Vulnerability in Cisco IOS XE System WebUI

9 min readNov 23, 2023

This article will analyze and summarize the recent critical CVEs (CVE-2023–20198, CVE-2023–20273) in Cisco IOS XE.

Environment Setup

A Cisco ISR 4300 router for research to analyze a 1day exploit for executing backdoor commands. Since this router runs on the Cisco IOS XE system, I can directly use the Cisco ISR environment for my research.

Setting up a virtual environment is also simple. By searching file name keywords on Google and ZoomEye without version identifiers, one can find many old versions of ova and qcow2 files. The downside is the inability to find the latest firmware. If you want to research the latest firmware, you can only purchase it on second-hand platforms.



After setting up the environment, the first step is to analyze the authorized RCE vulnerability. The principle of this vulnerability is relatively simple, with the issue arising from IPv6 address filtering. The relevant code is shown below:

function utils.isIpv6Address(ip) if utils.isNilOrEmptyString(ip) then return false end local chunks = utils.splitString(ip,":") if #chunks > 8 or #chunk s < 3 then return false end for i=1,#chunks do if chunks[i] ~="" and chunks[i]:match("([a-fA-F0-9]*)") == nil and tonumber(chunks[i],16) <= 65535 then return false end end return true end

The issue lies in the regular expression: chunks[I]: match(“([a-fA-F0–9]*)”), Due to the absence of a restriction on the end character, this means that as long as the beginning portion of the constructed string can successfully match the regular expression, it will pass. Let’s conduct a test below:

The latest patch code is as follows:

The updated regular expression is ip:match(“^([a-fA-F0–9:]+)$”), making it nearly impossible to bypass.

There are several command injection points:

In the validateSnortRequestfunction, there is a check for IP address, because the IPv6 check can be bypassed, it can lead to command injection.

The validateSmuRequest function checks the IP address, which is then concatenated into the url in the generateUrlAndDestination function, ultimately leading to command injection.

In this file, there are several instances of command injection vulnerabilities, stemming from the same cause. Due to the lack of proper validation for the ipaddress field, when it is concatenated into the URL, it leads to command injection.


Next, let’s analyze a more severe unauthorized vulnerability. I believe this vulnerability should be called the Unauthorized Cisco Command Execution vulnerability, allowing the execution of arbitrary Cisco commands with pri 15 privileges.

I believe this vulnerability arises from an error configuration in Nginx, as shown below:

location /lua5 { internal; if ($scheme = http) { rewrite /lua5 /webui_wsma_http; } if ($scheme = https) { rewrite /lua5 /webui_wsma_https; } } location /webui_wsma_http { internal; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass$NGX_IOS_HTTP_PORT liin; } location /webui_wsma_https { internal; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass$NGX_IOS_HTTPS_PORT liin; }

First, through auditing the Lua code of the web UI, it can be observed that executing CLI code is ultimately achieved by accessing the /lua path. However, because this path is configured with an internal field, it can only be accessed by internal Nginx code.

Furthermore, upon examining the code, it can be identified that the /lua path ultimately selects access to the /webui_wsma_http(s) path based on whether it is http or https. Similarly, external access to this path is not possible, theoretically making it impossible to bypass this portion of the nginx configuration.

However, the /webui_wsma_http(s) path is also not the final location for executing CLI commands. The ultimate communication with the iosd program is achieved by accessing http(s):// We can conduct a test.

By exploiting the aforementioned authorized RCE vulnerability to gain Linux privileges, then executing the following command:

We can see that the ultimate execution of CLI commands is handled by the iosd program service.

Continuing the audit of the Nginx configuration, we can find a configuration like this in /tmp/nginx.conf:

location / { proxy_read_timeout 900; proxy_pass liin; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header Via $server_addr; }

By default, nginx sends requests to the iosd backend. This leads to a potential approach: we can directly access http://host/webui_wsma_http to request the backend at

Upon testing, it was found that this approach is not feasible, as this request path will be matched to the location /webui_wsma_http route first, and due to the inclusion of the internal keyword, it returns a 404 error.

However, upon further consideration, it is realized that this approach is actually valid, but it requires a workaround. Nginx services decode URL encoding, and the iosd service also performs URL decoding, as shown below:

Through monitoring nginx’s socket traffic using strace, it was observed that while nginx decodes the URL during request forwarding to the proxy server, it re-encodes the URL before sending the request to the backend server, without issues. However, upon reaching the iosd server, the URL is decoded twice.

This presents an opportunity for a double encoding attack. If we initiate a request with: http://host/%2577ebui_wsma_http, the request received by nginx will be http://host/%77ebui_wsma_http. As no other route is matched, it defaults to the default route and sends the request to the iosd backend as Since the backend webui_wsma_http does not perform authentication checks, this leads to an unauthorized access vulnerability.

The URL of the request can encode any one or more characters of webui and still gain unauthorized access to the iosd backend. However, encoding of the subsequent _wsma_http is not effective, as if webui is not encoded, it will match the /webui route first and prevent access to the iosd backend.

Official Fix

The official fix involves adding a Proxy-Uri-Source header. If the access to the iosd service is through the default route, it is set to: Proxy-Uri-Source: global.

If accessed through the /lua5 route, it is set to: Proxy-Uri-Source: webui_internal.

When the iosd backend handles the webui_wsma_http route, it only responds to the HTTP request if it detects the HTTP header as: Proxy-Uri-Source: webui_internal.

However, I believe that the core issue of this vulnerability has not been addressed, as I have also found the following configuration:

server { include /usr/binos/conf/nginx-conf/https-only/fallback.conf; listen unix:/var/run/shell_exec/nginx/pnp_python.sock; listen unix:/var/run/shell_exec/nginx/pnp_python_ssl.sock ssl; location /pnp_python { proxy_pass liin; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_read_timeout 1d; proxy_send_timeout 1d; proxy_connect_timeout 1d; } }

The iosd backend also responds to the pnp_python route. I will further investigate the operations that can be performed using this route.

Analysis of In-the-Wild Exploitation

The two vulnerabilities mentioned above were initially disclosed by Cisco. It was suspected that they discovered backdoors on their or their customers’ machines, leading to the discovery of these two vulnerabilities.

Cisco did not publicly disclose the details of the vulnerabilities but provided information on how to check if their devices have been compromised with a backdoor.

First Detection Method

The above code is speculated to be the backdoor discovered by Cisco on their devices. From the code, we can infer that:

The main function of this backdoor is to execute arbitrary Linux system commands by accessing: http://host/webui/logoutconfirm.html?logon_hash=???&common_type=subsystem -d “id”.

The crucial aspect is the need for the logon_hash value, which cannot be obtained. Upon investigation, it is surmised that the logon_hash value for each device is unique and should correspond one-to-one with the previously returned hexadecimal string.

Second Detection Method

Third Detection Method

The attacker not only leaves a backdoor on the target device but also patches an unauthorized vulnerability. This route will match requests containing the % (percent) sign. If the URI of the request contains a percent sign, it will return a 404 error.

In a normal device, if the request is http://host/%25, it will match the default route, sent to the backend iosd, and the expected response is:

However, when the target device has a backdoor, it will match the above route and return a 404. Therefore, this feature can be used to determine whether the target server has a backdoor.

Research on the In-the-Wild Exploitation of the Vulnerability

Subsequently, research was conducted on the in-the-wild exploitation of this vulnerability. Exported 40,000 targets from ZoomEye, harmless probing was carried out to determine if the targets were susceptible to Remote Code Execution (RCE), and the results are as follows:

Researching the failed targets, it was found that there were a large number of honeypots, which could be probed with the percent sign 404, leading to a significant number of false positives. After excluding honeypot targets, the remaining targets were manually tested, and the reasons for failures were attributed to network issues.

Combining the previous analysis with the probing results, we can conclude that the logon_hash backdoor has only two versions (with and without the Authorization header), and there have been no other updates since Cisco officially disclosed the backdoor.

Similarly, it can be inferred that the attacker initially patched unauthorized vulnerabilities, making devices with the backdoor resistant to RCE. Therefore, we cannot capture any effective backdoor code.

From the probing results above, it is evident that there are over 10,000 vulnerable targets. Some of these targets overlap with those successfully probed using the logon_hash method. Further investigation revealed that due to the difficulty of maintaining the backdoor on the device, once the device is restarted, the backdoor disappears. This led to some targets initially probed successfully with logon_hash failing after some time, while RCE probing succeeded.

Next is a statistical analysis of the affected devices and their architectures:


Update 2023/11/5

Subsequently, it was discovered that the backdoor had been updated again, with changes in two main parts. The first part:

This section of the update addresses the fix for the percentage 404 detection method. However, it is not fully repaired, and there are still distinctions between compromised and uncompromised devices.

For an uncompromised device:

However, when a compromised device encounters a percentage sign, it will directly redirect to the login.html page:

This section updates the authentication mechanism, making it more challenging to detect invaded targets using the logon_hash method. Now, the Authorization is not a hash value; instead, it requires the SHA1 hash value to be a specified value. In such cases, detection of invaded targets can only be achieved through hash collision, brute-forcing SHA1 hash values, and similar methods to bypass the backdoor’s authentication check.

  • Avoid exposing the web UI port to the public network
  • Update IOS XE systems to the latest official version.


Originally published at https://tutorialboy24.blogspot.com




Our mission is to get you into information security. We'll introduce you to penetration testing and Red Teaming. We cover network testing, Active Directory.