A few months ago, we took part in Pwn2Own Austin 2021. Organized by the Zero Day Initiative, the event focuses on the exploitation of vulnerabilities in phones, printers, NAS, and more – a welcomed opportunity to put our skills to the test and compete with the brightest minds in the reversing and exploitation scene.
This is the second article of a three-part series on exploit chains we submitted to Pwn2Own, focusing on our Cisco RV340 submissions. You can find our first submission write-up about the Western Digital My Cloud Pro Series PR4100 here.
When we first started looking at the device we were mostly looking for logic flaws in both software (e.g., web server CGI handlers) and configurations (e.g., Nginx configuration), a by-product of some research we released almost a year ago on authentication bypasses affecting the same product line. This turned out to be an excellent idea, even if it led to a quite convoluted exploit, chaining three different vulnerabilities to obtain remote command execution as root over the LAN interface. Read on for all the technical details!
Affected vendor & product
Vendor Advisory |
Cisco RV340 Dual WAN Gigabit VPN Router (https://www.cisco.com/)
https://www.cisco.com/c/en/us/support/docs/csa/cisco-sa-smb-mult-vuln-KA9PK6D.html |
Vulnerable version | 1.0.03.24 and earlier |
Fixed version | 1.0.03.26 |
CVE IDs | CVE-2022-20705 CVE-2022-20708 CVE-2022-20709 CVE-2022-20711 |
Impact | 10 (critical) AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H |
Credit | Q. Kaiser, IoT Inspector Research Lab |
Description
The exploit chain combines three different bugs:
- Unauthenticated arbitrary file upload
- Unauthenticated file move
- Unauthenticated command injection
The chain takes advantage of the first two flaws to create the following primitives:
- Unauthenticated file move is used to get arbitrary file read
- Unauthenticated arbitrary file upload + unauthenticated file move is used to get arbitrary file write
We use the arbitrary file write to create fake session files on the device, the arbitrary file read is used to leak necessary information to build a fake session file.
Once the fake session files are created on the device, we use our fake sessionid
to trigger the authenticated command injection allowing us to execute commands as root.
Bug 1 – Unauthenticated Arbitrary File Upload
The web interface is handled by Nginx, with the configuration located under /etc/nginx
. In /etc/nginx/conf.d/rest.url.conf
, there is an attempt to check that some Authorization header is set.
The logic is such that any non-null Authorization header would set $deny
to “0”. So, sending literally any valid-looking Authorization header as part of a request to /api/operations/ciscosb-file:form-file-upload
will bypass the authorization check.
We can take advantage of this authorization bypass to write arbitrary files to the Nginx upload directory located at /tmp/upload
, with files named with increasing index (e.g. /tmp/upload/0000000001
, /tmp/upload/0000000002
). Given that we’re unauthenticated, the upload CGI will not handle our uploaded file and the files will stay there.
Bug 2 – Unauthenticated File Move
Still looking at the Nginx configuration, there is a misconfiguration in /etc/nginx/conf.d/web.upload.conf
.
As we can see in the output below, the /upload
endpoint is protected but /form-file-upload
is left wide open:
The only thing we need to do to reach the unauthenticated endpoint without triggering any errors is to set the form fields that are set by Nginx when handing it through /upload
: file.name
, file.content_type
, file.path
, file.md5
, and file.size
.
The parameter of interest to us is file.path
.
In upload.cgi
, a prepare_file
function is called. This function is supposed to move the Nginx generated temporary file to another location on disk (/tmp/upload.bin
).
We control file.path
that is passed as src_file
, fileparam
that is passed as dst_file
, and pathparam
that is passed as file_type
.
By submitting an upload request for a file type of ‘Portal’, we can move arbitrary files to /tmp/www
. Once the file is copied over, we can leak its content by requesting ‘login.html
‘ or ‘index.html
‘ given that they are both symlinked (‘/www/login.html
->
/tmp/www/login.html
‘ and ‘/www/index.html
->
/tmp/www/index.html
‘).
Note that it works because the prepare_file
function is called before checking the query path value:
Bug 3 – Authenticated Command Injection (update-clients RPC)
The jsonrpc
CGI handling all the web administration requests is configured to forward specific RPC requests to a ConfD
server.
All the RPC requests are documented in /etc/confd/yang/
, these RPC requests define the expected input with strong typing. The RPC name is always a valid binary or script present in the device PATH.
In this example, update-clients
is actually a Perl script located at /usr/bin/update-clients
. As we can see from the script excerpt below, it is vulnerable to arbitrary command injection given that parameters are passed within double quotes, allowing the injection of shell expansion or backticks.
To fully understand the expected format of that JSON RPC call, we searched through the Angular based client code and found this entry:
Which led us to this reduced test case:
We confirmed the injection by connecting to the newly opened telnet listener:
We are running as root so privilege escalation won’t be required. This is due to the fact that the server receiving these YANG-based RPC calls is confd
, which runs as root on the device.
Exploitation Strategy
Session Files Format
When a user logs into a Cisco RV340, the following session files are created:
The session file holds a JSON object like the one below:
The sessionid
is a base64 encoded string of slash separated values holding username, time of emission, and source IP address:
Creating Fake Session Directories
With our arbitrary file move, we are limited to moving files into /tmp/www
, which means we cannot immediately overwrite files located in /tmp
.
To overcome that, we take advantage of symlink indirection by moving the /var
directory to /tmp/www/iotinspector
. The /var
directory is actually a symlink to /tmp
. This is the equivalent of doing this:
Even though we’re receiving errors, the file is created:
Next on the list of things, we need to do, is creating our fake session directories in /tmp/www
and then moving them to /tmp
to create one or replace the existing one.
If we simplify it down to shell commands, this is what it looks like. The part we control is put between ‘<>’
This is all possible thanks to mv
moving files to directories even if the second argument does not end with a forward slash.
Identifying Uploaded Files Location
If a user has been uploading files prior to our exploit running, files may be located under the /tmp/upload
directory used by Nginx. And even if there are none there, Nginx keeps a counter throughout its uptime that increases on each file upload.
When we upload a file, we don’t know at which exact location it has been written, so we need to guess that before we perform our move.
The strategy to “leak” the uploaded file location follows:
- Loop through potential uploaded file names from
/tmp/upload/0000000001
to/tmp/upload/0000000100
. - For each potential file name, move it to
/tmp/www/login.html
- Leak the content of
/tmp/www/login.html
by sending a GET request, hash the response and compare it to the hash of our recently uploaded file. - If the hash matches, move
/tmp/www/login.html
back to its original location and recover the login page by moving/www/login.html.default
to/tmp/www/login.html
.
Crafting Fake Session Files
The cisco user is a default user that cannot be deleted and will always be part of the admin group so we can stick to that user. However, we need to handle the time and timeout values.
The timeout value is discarded if the file /tmp/webcache/web-session-timeout.json
exists. We could move it to /dev/null
and create a session file with a timeout value of 999999 but the removal of that file might trigger unknown issues.
Instead, we can leak the device uptime in seconds and use it to generate our fake session object. Leaking the uptime is really simple, we can try to move the proc uptime to the login page. This ends up overwriting the login page with the content of proc uptime at the time of reading. Then we read the login page by sending a GET request and parse the uptime value.
One issue that might be blocking is the presence of equal signs in the sessionid
. The destination filename can only contain underscore, dot, and alphanumeric characters. This means that if the sessionid
contains an equal sign, the move will fail.
Three parameters influence the presence of equal signs in the base64 encoded sessionid
:
- username → we can’t control it
- source IP → we can control it, we just need to get the right DHCP lease
- device uptime → we can’t control it
- add a slash followed by padding characters that gets discarded when
sessionid
is parsed
In the end, we just used padding to remove equals sign in the base64 encoded sessionid
. Equipped with that knowledge, we can craft fake session objects.
Sending Command Injection
Now that our fake session is created on the device, we can send authenticated requests to trigger the command injection bug described as Bug 3 – Authenticated Command Injection (update-clients RPC).
Running The Exploit
Key Takeaways
If we break it down, the fundamental issue that allowed us to exploit these vulnerabilities is a misunderstanding of Nginx configurations. These kinds of misconfigurations have been mostly identified in large web applications since Orange Tsai released its excellent research on breaking parsers logic, but they can also affect embedded devices running web servers! We can only advise researchers in that space to review the configuration of any web server they may find in their way for potential authentication bypasses.
The command injection vulnerability could be considered as a “second order” injection in that the attacker has to understand the inner relationship between ConfD, its configuration files, and the scripts it’s linked to. For researchers focusing on devices relying on ConfD
, it could be interesting to develop scripts identifying RPC endpoints definitions with loosely typed inputs calling insecure scripts (Perl, Lua, shell, etc.) ?
We hope that these ideas for further research will help you during your next endeavor if you’re interested in Cisco devices.
Timeline
2021-11-03 – Vulnerability reported to vendor
2022-02-02 – Cisco release its advisory
2022-02-17 – IoT Inspector release its advisory
原文始发于iot-inspector:Advisory: Cisco RV340 Dual WAN Gigabit VPN Router (RCE over LAN)
转载请注明:Advisory: Cisco RV340 Dual WAN Gigabit VPN Router (RCE over LAN) | CTF导航