Iot Inspector Research Lab

Advisory: Cisco RV34X Series – Privilege Escalation in vpnTimer


A few weeks ago, we published an advisory on the Cisco RV series routers, where we outlined the root cause for authentication bypass and remote command execution issues.

This week, Cisco has released an advisory for another bug we reported around the same time: A privilege escalation issue, which could be used in combination with the other two issues to run arbitrary code with root privileges on affected RV34X devices. As embedded devices often run everything with root privileges, it’s relatively uncommon that we have the opportunity to find privilege escalation bugs, so this is a particularly interesting case. In this post, we’ll do a quick root-cause analysis of this bug we found.

Cisco RV340

© Cisco

Affected vendor & product Cisco Small Business RV Series Router (
Vulnerable version RV34X & below,
Fixed version RV34X series:
CVE IDs CVE-2021-1520
Impact 6.7 (medium) CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
Credit T. Shiomitsu, IoT Inspector Research Lab

RV34X Privilege Escalation in vpnTimer (CVE-2021-1520)

It’s not often that one gets to report a privilege escalation in the embedded security world. So often, everything is running as root, that opportunities for privilege escalation are few and far between. However, on the RV34X series, the nginx server runs as the www-data user. This isn’t particularly useful for an attacker and, as such, a privilege escalation exploit is required in order to run code as root.

Luckily, we identified a vulnerable service called vpnTimer, which runs as root, and exposes a socket on the local loopback interface (on UDP/9999). This service receives data on this socket and passes it insecurely to a system command string. As such, if an attacker can run lower-privileged code on an RV34X device, they would be able to then send a crafted UDP packet to, which will run an arbitrary command with root privileges.

vpnTimer is simply a Perl script, which waits for connections on UDP/9999. process_timer() is the main function of this script, and runs in a loop as follows (with some extraneous code snipped):

sub process_timer() { 
  while(1) { 
    @sockets_ready = $select->can_read(1); 
    if (! scalar(@sockets_ready)) { 
    } else { 
      #print("$cur_min : $cur_sec\n"); 
      foreach $socket_new (@sockets_ready) { 
        if (! recv($socket_new, $message, 1024, 0)) { 
          print "Error reading from socket: $!\n"; 
        } else { 
          my $temp=substr($message,1,); 

          if (index(substr($message,0,1),"+") == 0){ 
            my $isTVPNC=`uci get strongswan.$temp`; 
           chomp $isTVPNC; 
           if ($isTVPNC eq "client"){ 
             system("tvpnc_timer $temp &"); 
           } else { 
             my $interval=`uci get strongswan.$temp.keep_alive_interval`; 
             chomp $interval; 

Highlighted here are the key components. The $message is read from the socket. $temp is initialized to contain the contents of $message without the first character (removed with this call to substr).

The first character of $message is then checked, to see if it is a “+” character. If it is, the value of $temp is passed to a statement within two separate backtick strings. In Perl, statements within backticks are executed as a system shell command. Since the vpnTimer service is running as root, the command will be run as root.

As such, sending a packet to UDP/ with the content “+;touch /tmp/test;“ will result in command uci get strongwan.;touch /tmp/test; being run, and the file /tmp/test being written to the filesystem by the root user.

How Long Was This Bug There?

We thought it might be interesting to see if we could quickly figure out how long this bug has been affecting the Cisco RV34X devices. Often, our assumption might be that a script with a 2015-dated copyright string at the top has not been thought about or actively changed since 2015. However, assumptions are always good to challenge.

With our API, it’s relatively simple to script a set of GraphQL queries, and spit out a list of file hashes for all version of vpnTimer for all available RV34X firmware images:

vpnTimer hashes over time.

We can very easily see that between firmware versions (released on the 19th October 2018) and (released 1st January 2019), the vpnTimer script was actually slightly edited.

The changes were not significant, mainly adding a signal_handler() function, and fixing a couple of typos:

vpnTimer diff

New function and logging lines added.

vpnTimer diff

A typo being fixed.

But it does illustrate that this script was actively developed in the past couple of years, and that a bunch of small extra functionalities were added. This script may not have necessarily been thought about deeply, but it was certainly not a forgotten relic. This info does also show that this bug in the vpnTimer script has been present since at least the first firmware update package of the RV34X series (February 2017).

Key Takeaways

When implementing different privilege levels, it’s always important to follow the principle of least privilege. Does the component need root privileges, or is it possible to run it with a more limited set? In a well-hardened system, an attacker would be hard-pressed to come across a component running as root, which does not absolutely require root privileges. In more complex systems, you may even consider implementing SELinux (well) to provide an even more granular set of permissions to each process.

Despite all this, since so many embedded devices run everything with root privileges, it’s still heartening to see when privilege separation is at least attempted in a device. Thanks for the challenge, Cisco!


ONEKEY is the leading European specialist in Product Cybersecurity & Compliance Management and part of the investment portfolio of PricewaterhouseCoopers Germany (PwC). The unique combination of an automated Product Cybersecurity & Compliance Platform (PCCP) with expert knowledge and consulting services provides fast and comprehensive analysis, support, and management to improve product cybersecurity and compliance from product purchasing, design, development, production to end-of-life.

Critical vulnerabilities and compliance violations in device firmware are automatically identified in binary code by AI-based technology in minutes – without source code, device, or network access. Proactively audit software supply chains with integrated software bill of materials (SBOM) generation. “Digital Cyber Twins” enable automated 24/7 post-release cybersecurity monitoring throughout the product lifecycle.

The patent-pending, integrated Compliance Wizard™ already covers the upcoming EU Cyber Resilience Act (CRA) and existing requirements according to IEC 62443-4-2, ETSI EN 303 645, UNECE R 155 and many others.

The Product Security Incident Response Team (PSIRT) is effectively supported by the integrated automatic prioritisation of vulnerabilities, significantly reducing the time to remediation.

Leading international companies in Asia, Europe and the Americas already benefit from the ONEKEY Product Cybersecurity & Compliance Platform and ONEKEY Cybersecurity Experts.



Sara Fortmann

Marketing Manager


euromarcom public relations GmbH

+49 611 973 150