RV130X Firmware Analysis

20 minute read

1. RV130X Firmware Analysis

Firmware analysis is an essential part of security research and targeted search for vulnerabilities in IoT products, vehicle components, industrial control systems, and a multitude of other types of software/hardware systems designed for various purposes.

1.1. Cisco RV130 VPN router

We will be using a firmware for the Cisco RV130 VPN router which can be downloaded from Cisco. The file is named RV130X_FW_1.0.3.55.bin

1.1.1.  Information Gathering

By examining the firmware header, it’s possible to identify the string “RV132ND7CODE”.

image-center

Performing this check is crucial to verify that the information shown in the filename RV130X_FW_1.0.3.55.bin is accurate. Through quick OSINT research, we can determine that this string corresponds to the target hardware, the Cisco RV130 VPN Router.

It appears that this firmware is also compatible with the WiFi-enabled model, the Cisco RV130W VPN Router. This assumption will be confirmed later when we examine the contents of the files present in the filesystem.

image-center

Router Motherboard

Through OSINT research, we were able to locate a PCB board image of the Cisco RV130W router and identify its exposed development interfaces:

  • JTAG Port: A series of pin headers can be observed that matches the typical layout of a JTAG connector, which is commonly used for debugging and programming embedded devices. This interface features an unpopulated 20-pin header (only the holes where components should be soldered are present).

  • UART Serial Port: Typically used for accessing the management console, basic configuration, and debugging. This interface features an unpopulated 5-pin header.

image-center image-center

Hardware Specification
Component         Specification                          
CPU         Cavium CNS3410 ARM11MPCore (@600MHz)
Memory       128MB (SDRAM) DDR2                  
Storage     32MB Parallel NOR Flash            
Network     5x Gigabit Ethernet ports          
WiFi         Broadcom BCM43217 (2T2R 802.11bgn)  
USB         1x USB 2.0 host port                
Power Port   12 VDC, 2 A                        
FCC ID       N89-RV130W                          
IC ID       5005A-RV130W                        
Board ID     3763-20400102R                      
Physical Dimensions 149.86 x 29.9 x 150.11 mm    
Weight       0.72 kg                              
Power Supply 12V 2.5A                          
Firmware Stock Specifications
Feature                 Specification              
Stock bootloader     U-Boot 2008.10-mpcore    
Stock OS           Linux 2.6.31              
Default SSID       ciscosb1                  
Default IP Address 192.168.1.1              
Default login user cisco                    
Default login password cisco                
Network Protocols Support
Protocol   Support Details                        
DHCP   Server and Client                    
PPPoE Point-to-Point over Ethernet        
PPTP   Point-to-Point Tunneling Protocol  
DNS   Proxy support                        
IGMP   Proxy and multicast forwarding      
RSTP   Rapid Spanning Tree Protocol        
DynDNS Yes, with NOIP support            
NAT/PAT Network/Port Address Translation
Security Features
Feature             Details                                    
Access Control Management ACLs plus MAC ACLs        
Secure Management HTTPS with username/password complexity
Firewall Type Stateful Packet Inspection (SPI)      
DoS Protection SYN Flood, Echo Storm, ICMP/UDP/TCP Flood
Content Blocking Java, cookies, active-X, HTTP proxy  
Web Filter Yes, filters and blocks harmful sites    


Furthermore, OSINT research revealed that the Cisco RV130W VPN router has reached End Of Lifestatus, with its last firmware update (target) released in June 2020.

As a result, there are known software vulnerabilities that Cisco has not patched for this router model.

image-center

1.1.2. Extract Filesystem

We’ll recursively extract files from the firmware using Binwalk with the following command:

binwalk –preserve-symlinks -Me RV130X_FW_1.0.3.55.bin

Where:

  • –preserve-symlinks: Maintains the original symbolic links (symlinks) during firmware extraction, instead of modifying them for security purposes
  • -M: Recursively scan extracted files
  • -e: Automatically extract known file types
  • RV130X_FW_1.0.3.55.bin: Target firmware file

This command will extract all the files while keeping the original symlinks structure intact, which is particularly useful for maintaining the exact firmware structure for analysis purposes.

image-center

From the image, we can determine the following information:

  •  Architecture: ARM Little Endian
  •  Board ID: RV13
  •  Build date: 2020-03-27
  •  The image contains 4 sections:
    • Bin Header
    • Linux Kernel (zImage)
    • gzip compressed data
    • Squashfs filesystem (very common in embedded devices).

Additionally, using the previous command, the recursive extraction of file 3479, which represents the compressed gzip file, is performed.

image-center

The binwalk execution on the gzip file reveals the following information:

  • Linux kernel version: 2.6.31 (confirming the OSINT research findings)
  • User developer: johnny
  • Project name: RV110W_cavium

It appears that the “squashfs-root-0” extraction contains the most significant information.

image-center

After extracting the binary using binwalk the extracted file system looks like:

image-center

Now that we’ve extracted the filesystem, we can navigate through the files and attempt to find some useful information.

image-center

image-center

Let’s start with the study of binaries.

1.2. The choice of binaries for fuzzing

1.2.1.  First – takes input from a file

Let’s begin by obtaining a list of all binaries with the execution flag enabled present in the firmware, along with their respective sizes.

image-center

Through an LLM, it was possible to further narrow down the search using the following prompts:

  1.  ”< list of binaries > From this list, check ten binaries at a time to tell me if they accept file input (and with which input flags)”
  2.  ”Which of the previously mentioned binaries would make good AFL targets?”

image-center

Since the “jsonparse” and “xmlparser1” binaries have already been analyzed in the post below, I opted not to fuzz them again and instead focused on identifying a more intriguing target: https://blog.attify.com/fuzzing-iot-devices-part-1/.

The choice for the first file remains between various “busybox” applets and “rxp”.

Let’s use QEMU to execute busybox with ARM architecture to discover its version and available functions.

image-center

While busybox 1.7.2 is from 2007, the build date shows 2020-03-27, suggesting a patched version. Given that busybox is built upon widely-tested utilities, finding novel vulnerabilities here is unlikely.

Let’s examine the rxp binary:

image-center

OSINT research enabled us to locate the source code for both the target binary version 1.4.4 and the latest version 1.5.2, which simplified our analysis.

image-center

image-center

A diff comparison was performed between the two projects to identify patches missing from version 1.4.4.

Both projects contain the file “xmlparser.c” which appears to handle XML file parsing.

Several vulnerable functions were identified in version 1.4.4 that were subsequently patched in version 1.5.2.

image-center image-center

However, this information proved irrelevant, as subsequent analysis of the binary using Ghidra revealed that the rxp binary in the firmware is merely a branch of the open-source version 1.4.4 and had already been patched by Cisco.

1.2.2.  Second – receives data not directly from files

Here too, I used an LLM to obtain a list of potentially suitable binaries. The prompt:

image-center

After manual processing of the search results, the following candidates were identified:

image-center

Among these binaries, httpd proved to be the most interesting target, and was subsequently selected for the second fuzzing campaign.

The selection of httpd as the target was strategically motivated, as this component is responsible for managing the router’s web interface.

Analysis of historical CVE vulnerabilities for this model demonstrated that the majority of successful attacks exploited vulnerabilities in the login webpage. These vulnerabilities were particularly significant as they frequently enabled attackers to completely circumvent the router’s authentication mechanisms.

1.3. Fuzzing Campaign - rpx

The binary selected for this fuzzing campaign is “rxp”, an executable that, as previously mentioned, is used for parsing XML files.

Below is an excerpt from rxp’s man page:

image-center image-center image-center image-center

1.3.1.  Summary

The fuzzing operation ran for approximately 15 hours and 40 minutes, producing the following results:

Metric                 Master Slave1 Slave2 Slave3
Unique/Saved Crash 8       9       8       7      
Unique/Saved Hang   0       2       2       3      
Total Crash       340     626     639     635    
Corpus Count       1989   2033   2086   1983  
Cycle Done         196     35     34     37    

It should be noted that the unique crashes detected may be either identical or different across various instances.

1.3.2.  Functions target

The fuzzing was performed on the following functions responsible for analyzing the input XML file:

image-center

The function names were taken from the rxp 1.4.4 open-source project.

1.3.3. Corpus Acquisition and Minimization

The test cases were generated using an LLM and sourced from the following GitHub directories:

All files from these directories were then consolidated into a single directory named “corpus_mega” using the following command:

image-center

Subsequently, realizing that the Windows Kali subsystem would not be suitable for AFL++ installation, the operation was moved to a Kali VMware machine to install AFL++ with QEMU support and perform corpus minimization using afl-cmin.

image-center

Subsequently, a decision was made to remove excessively large XML files to prevent slowdowns during the fuzzing process.

image-center

The final corpus consists of 148 XML elements.

image-center

1.3.4.  Launch the fuzzing campaign

After corpus minimization, four AFL++ processes were launched

  • one master and three slaves,
  • using QEMU virtualization to execute the ARM32 architecture binary.

Each instance was configured to employ dictionary-based mutations using xml.dict to enhance corpus transformation accuracy.

./AFLplusplus/afl-fuzz -Q -M Master -i corpus -o output -x ../AFLplusplus/dictionaries/xml.dict ./squashfs-root/usr/sbin/rxp -s @@ 2> /dev/null
./AFLplusplus/afl-fuzz -Q -S Slave1 -i corpus -o output -x ../AFLplusplus/dictionaries/xml.dict ./squashfs-root/usr/sbin/rxp -s @@ 2> /dev/null
./AFLplusplus/afl-fuzz -Q -S Slave2 -i corpus -o output -x ../AFLplusplus/dictionaries/xml.dict ./squashfs-root/usr/sbin/rxp -s @@ 2> /dev/null
./AFLplusplus/afl-fuzz -Q -S Slave3 -i corpus -o output -x ../AFLplusplus/dictionaries/xml.dict ./squashfs-root/usr/sbin/rxp -s @@ 2> /dev/null

After approximately 5 hours of scanning, initial results were obtained, including several “crashes”.

image-center

After approximately 12 hours, both crashes and hangs were detected:

image-center

After approximately 15 hours and 40 minutes, the results remained largely consistent with the previous findings.

image-center

1.3.5.  Proof of Work

As expected, the binary crashes when executed.

image-center

The content of the file causing the program to crash is as follows:

image-center

Now, it’s important to identify the exact instruction where the binary crashes, so we’ll use gdb-multiarch and QEMU for debugging.

Let’s start the binary in remote debugging mode:

image-center

Let’s connect gdb-multiarch to the debug socket:

image-center

Let’s identify the crash location:

image-center

Continue with execution:

image-center

The binary crashes when calling “free” in the shared library. Further investigation in this direction could lead to binary exploitation and potential CVE discovery.

1.4. Fuzzing Campaign – httpd

To practice, I decided to analyze the httpd binary, which does not directly accept input from stdin.

In this case, since the binary accepts neither file nor stdin input, it will be necessary to patch “httpd” and utilize AFL++ environment variables to directly fuzz the HTTP request parsing function.

1.4.1.  Summary

The fuzzing operation ran for approximately 9 hours and produced the following results:

Metric                 Master Slave1 Slave2 Slave3
Unique/Saved Crash 0       0       0       0      
Unique/Saved Hang   0       0       0       0      
Total Crash       0       0       0       0      
Corpus Count       877     302     294     309    
Cycle Done         879     151     141     142    

Although no crashes were detected.

1.4.2.  Binary Patching and library Injection

In this case, the binary had already been analyzed in the following post, so I simply reproduced the steps for patching.

The httpd binary currently forks to the background using the daemon function. This forking behavior is not desirable during fuzzing..

image-center

The daemon function needs to be overridden to return 0 without forking. This can be accomplished either through LD_PRELOAD or by patching the assembly instructions.

An additional modification is required to make “httpd” process exactly one request (unlike a typical web server that processes requests indefinitely) before terminating. This enables identification of which specific request, if any, causes the web server to crash.

To close a socket, httpd calls the close function. There are three locations from where “close” is called.

image-center

Among them, we need to modify the one at 0x231c0 to call exit(0) instead of close.

image-center

To patch the instructions, we will use Cutter which is a GUI for radare2. Ghidra also supports patching binaries, but Cutter is better suited for this use case.

Upon navigating to 0x231c0 in Cutter, the following disassembly can be observed:

image-center

Double-clicking on close takes us to 0x106b4.

image-center

The exit function is located at 0x10b64.

image-center

The bl close instruction can be modified to bl 0x10b64 to call the exit function instead.

image-center

The instruction immediately before can be changed from mov r0, sl to eor r0, r0 which sets register r0 to 0 to give us the following disassembly.

image-center

The modification results in calling exit(0). A secondary modification is required to patch out the daemon call at 0x22CB4.

image-center

The instruction can be modified to eor r0, r0 to make the application interpret the call as successful.

image-center

Finally, with the changes in place go to File -> Commit changes to save the modifications. Let’s rename the file to httpd_patched.

Let’s verify if the binary has been correctly patched and modify its permissions for execution.

image-center

Running “httpd_patched” we can see that it doesn’t fork to the background and that quits after processing a single request as shown below.

image-center

To enable file-based input for httpd, we can utilize the opensource desocksmulti project, which serves as a bridge between network applications and file-based tools. This tool is particularly valuable for fuzzing network binaries with tools like AFL++ that primarily work with file input.

Desocksmulti works by intercepting network socket operations (socket(), bind(), listen(), and accept()) and redirecting them to stdin and stdout.

The compilation of desockmulti requires an ARM cross compiler. The armv7-eabihf-uclibc toolchain from bootlin is particularly suitable for this purpose. A uclibc-based toolchain is necessary as the firmware binaries utilize the same library.

This compatibility can be verified by running the file command on /usr/sbin/httpd, which indicates that the binary is dynamically linked to “ld-uClibc.so.0”.

image-center

So let’s clone the desockmulti repository:

image-center

Before compiling the code, the setup_timer() function call within the socket() function’s code must be commented out.

image-center

The compilation can be initiated by running make with the ARM-Linux-GCC compiler path specified in the CC environment variable.

image-center

The generated file desockmulti.so can be copied to the squashfs-root directory.

image-center

To verify that desockmulti functions correctly, httpd can be debugged using gdb-multiarch. First, a dependency to the “libpthread.so.0” library must be added using patchelf (which can be installed via apt). This addition is necessary because desockmulti utilizes threads, while httpd does not link to libpthread by default.

image-center

The binary can now accept requests from stdin, thus enabling fuzzing through AFL.

Although httpd_patched is prepared for fuzzing, it requires root privileges because it attempts to access /var/run/httpd.pid. To avoid this requirement, the binary can be modified to reference an alternative path that’s accessible without root privileges.

The binary can be opened with a hexadecimal editor to change /var/run/httpd.pid to /home/kali/hpd.pid and saved.

image-center

Rerunning httpd_patched we can see it runs without admin rights and errors.

image-center

Additionally, the file hpd.pid is created within the kali’s home directory.

image-center

1.4.3.  How to see http responses

To see the web server’s response, the debugger is required, as these will not be printed on the screen.

Go into “www” folder and run the binary in qemu specifying the -g parameter.

image-center

The path to desockmulti.so is specified in the “LD_PRELOAD” environment variable. The other variable “USE_RAW_FORMAT” is specific to desockmulti.

In another terminal, we can start gdb-multiarch, set a breakpoint on fprintf and attach to port 5555.

image-center

When the breakpoint on fprintf is triggered, pressing continue multiple times will eventually reveal the response code in register $r2.

image-center

1.4.4.  Corpus Acquisition and Minimization

The test cases and dictionary were sourced from the following GitHub directory:

These were supplemented with additional requests generated via LLM, along with the router’s basic login request.

image-center

image-center

Let’s now proceed with corpus minimization using afl-cmin.

image-center

The minimized corpus consists of 21 files.

image-center

The fuzzing process of the patched httpd binary can now begin.

1.4.5.  Launch the fuzzing campaign

Four AFL++ instances were launched (1 master and 3 slaves):

QEMU_LD_PREFIX=.. QEMU_SET_ENV=USE_RAW_FORMAT=1,LD_PRELOAD=../desockmulti.so ../../../AFLplusplus/afl-fuzz -Q -M Master -x ../../dict/http_request_fuzzer.dict.txt -i ../../req_input_cmin/ -o ../../req_output/ -- ../usr/sbin/httpd_patched
QEMU_LD_PREFIX=.. QEMU_SET_ENV=USE_RAW_FORMAT=1,LD_PRELOAD=../desockmulti.so ../../../AFLplusplus/afl-fuzz -Q -S Slave1 -x ../../dict/http_request_fuzzer.dict.txt -i ../../req_input_cmin/ -o ../../req_output/ -- ../usr/sbin/httpd_patched
QEMU_LD_PREFIX=.. QEMU_SET_ENV=USE_RAW_FORMAT=1,LD_PRELOAD=../desockmulti.so ../../../AFLplusplus/afl-fuzz -Q -S Slave2 -x ../../dict/http_request_fuzzer.dict.txt -i ../../req_input_cmin/ -o ../../req_output/ -- ../usr/sbin/httpd_patched
QEMU_LD_PREFIX=.. QEMU_SET_ENV=USE_RAW_FORMAT=1,LD_PRELOAD=../desockmulti.so ../../../AFLplusplus/afl-fuzz -Q -S Slave3 -x ../../dict/http_request_fuzzer.dict.txt -i ../../req_input_cmin/ -o ../../req_output/ -- ../usr/sbin/httpd_patched

Below, all instances can be observed simultaneously working to fuzz httpd.

image-center

Unfortunately, after 8 hours and 40 minutes of execution, no crashes were detected.

image-center

Several factors may explain the absence of crashes:

  1.  Binary Maturity and Previous Analysis
    •  The binary is widely known and has undergone extensive security research
    •  Many vulnerabilities have likely been identified and patched through previous investigations
    •  The codebase has benefited from multiple security reviews and improvements
  2.  Hardware Performance Limitations
    •  The fuzzing was conducted on a VMware virtual machine with restricted resources
    •  Limited computational power can affect:
    • The number of executions per second
    • The effectiveness of the fuzzing process
    • The ability to explore deeper program states
  3.  Technical Approach Limitations
    •  The absence of grammar mutators significantly impacted the fuzzing efficiency
    •  Grammar mutators would have provided:
      • Better understanding of HTTP protocol structure
      • More intelligent mutation strategies
      • Higher quality test case generation
      • Improved coverage of protocol-specific edge cases
      • More effective exploration of protocol-dependent code paths

These factors combined likely limited the fuzzing campaign’s effectiveness in identifying potential vulnerabilities.

2.  Recap and Conclusions

2.1. Overview of Findings

The security assessment of the Cisco RV130X router firmware (version 1.0.3.55) revealed several significant findings. Through comprehensive analysis and testing, we identified both known vulnerabilities and potential new security concerns.

The firmware, which hasn’t received updates since 2020, demonstrated multiple attack surfaces that could be exploited by malicious actors.

2.1.1.  Firmware Analysis

Through OSINT research, we gathered extensive information about both the hardware specifications and software components of the Cisco RV130X/RV130W VPN router.

The firmware analysis revealed that the device runs on an ARM11MPCore architecture with Linux kernel version 2.6.31.

Multiple outdated components were identified within the firmware, as no updates have been released since June 2020.

CVEs have been identified, including several critical security issues that could pose significant risks.

2.1.2.  Fuzzing Campaigns

The assessment included two distinct fuzzing campaigns with notably different outcomes:

RXP Binary Campaign:
  • Successfully identified multiple crash scenarios (32 unique crashes across four instances)
  • Detected seven potential hanging conditions
  • Achieved significant corpus coverage with over 8,000 test cases
  • Debug analysis confirmed exploitable conditions in memory management functions
  • Campaign duration: approximately 15 hours and 40 minutes
HTTPD Binary Campaign:
  • Required extensive binary patching to enable AFL++ compatibility
  • Implemented custom solutions for network protocol fuzzing using desockmulti
  • No crashes or hangs detected despite thorough testing
  • Campaign duration: approximately 9 hours

2.2. Technical Achievements

The assessment demonstrated successful implementation of various advanced security testing techniques:

  • Binary patching and modification for fuzzing compatibility
  • Custom tooling integration for network protocol testing
  • Effective use of AFL++ with QEMU for ARM architecture testing
  • Implementation of dictionary-based fuzzing strategies
  • Successful debugging of crash conditions using gdb-multiarch

2.3. Limitations and Challenges

Several factors influenced the assessment outcomes:

  • Limited computational resources in the virtual environment
  • Performance impact on fuzzing effectiveness
  • Complexity in adapting network services for fuzzing
  • Absence of grammar-aware mutation engines
  • Limited access to physical hardware for testing