Cisco Finally Patches 0-Day Exploit – CVE-2017-3881

Cisco Systems has finally released an update for its IOS and IOS XE software to address a critical vulnerability, disclosed nearly two months back in the CIA Vault 7 leak, that affects more than 300 of its switch models.

The company identified the vulnerability in its product while analyzing “Vault 7” dump — thousands of documents and files leaked by Wikileaks, claiming to detail hacking tools and tactics of the U.S. Central Intelligence Agency (CIA).

As previously reported, the vulnerability (CVE-2017-3881) resides in the Cluster Management Protocol (CMP) — which uses Telnet or SSH to deliver signals and commands on internal networks — in Cisco IOS and Cisco IOS XE Software.

The vulnerability can be exploited remotely by sending “malformed CMP-specific Telnet options while establishing a Telnet session with an affected Cisco device configured to accept Telnet connections,” researchers say.

The company warned users on April 10 that an exploit targeting the flaw had been made public (here’s a proof-of-concept (PoC) exploit) and provided some mitigation advice, but patched the issue this week only.

Once exploited, an unauthenticated, remote attacker can remotely execute malicious code on a device with elevated privileges to take full control of the device or cause a reboot of the affected device.

The vulnerability is in the default configuration of the affected Cisco devices and affects 264 Catalyst switches, 51 industrial Ethernet switches, and 3 other devices if they are running IOS and are configured to accept Telnet connections.

The affected Cisco switch models include Catalyst switches, Embedded Service 2020 switches, IE Industrial Ethernet switches, ME 4924-10GE switch, Enhanced Layer 2/3 EtherSwitch Service Module, Enhanced Layer 2 EtherSwitch Service Module, RF Gateway 10, SM-X Layer 2/3 EtherSwitch Service Module, and Gigabit Ethernet Switch Module for HP (check the list of affected models here).

The vulnerability was given a score of 9.8 (higher level of risk) based on the Common Vulnerability Scoring System, which means the issue is truly bad.

The only mitigation available for users was to disable the Telnet connection to the switch devices in favor of SSH, but now since the company has patched the issue, administrators are strongly advised to install the patch as soon as possible.

CVE-2017-3881 Cisco Catalyst RCE Proof-Of-Concept

Do you still have telnet enabled on your Catalyst switches? Think twice, here’s a proof-of-concept remote code execution exploit for Catalyst 2960 switch with latest suggested firmware. Check out the exploit code here. What follows is a detailed write-up of the exploit development process for the vulnerability leaked from CIA’s archive on March 7th 2017 and publicly disclosed by Cisco Systems on March 17th 2017. At the time of writing this post there is no patch available. Nonetheless there is a remediation – disable telnet and use SSH instead.

Vault 7 CIA leak

A series of CIA’s documents were leaked on March 7th 2017 and published on WikiLeaks. Among other publications there was an interesting preauth code execution vulnerability that affected multiple Cisco switches. This vulnerability is code-named ROCEM in the leaked documents. Although very few technical details were mentioned, few things stand out.

The Vault 7’s documents shed a light on the testing process for the actual exploit. No exploit source code is available in the leak. Two use cases are highlighted there – the tool can be launched in either interactive mode or set mode. The interactive mode sends the payload via telnet and immediately presents the attacker with command shell in the context of the same telnet connection. Quote from the doc:


Set mode. Modify switch memory in order to make any
subsequent telnet connections passwordless. Quote from the doc:


One piece of information being useful for me in researching this vulnerability was a telnet debug output. Quote from the doc:


Note the

option received by the service on the last line. This proved to be an important string.

Cisco advisory

On March 17th 2017 Cisco Systems disclosed a vulnerability present in their switches. This disclosure was based on the documents from Vault 7:

A vulnerability in the Cisco Cluster Management Protocol (CMP) processing code in Cisco IOS and Cisco IOS XE Software could allow an unauthenticated, remote attacker to cause a reload of an affected device or remotely execute code with elevated privileges.

Not much details were available at the time of writing this article, except for the following paragraph:

The Cluster Management Protocol utilizes Telnet internally as a signaling and command protocol between cluster members. The vulnerability is due to the combination of two factors:

  • The failure to restrict the use of CMP-specific Telnet options only to internal, local communications between cluster members and instead accept and process such options over any Telnet connection to an affected device, and
  • The incorrect processing of malformed CMP-specific Telnet options.

Long story short, the vulnerability allows the attacker to exploit telnet service to gain remote code execution on the target switch. But in order to make any use of this advisory I needed more information on the matter. So I decided dig deeper into Cisco Cluster Management Protocol.

Switch clustering

All right! I had two Catalyst 2960 switches for researching this vulnerability. Clustering sets a master-slave relation between switches. Master switch is able to get a privileged command shell on the slave. As Cisco mentioned in its advisory, telnet is used as a command protocol between cluster members. Some info on clustering can be found here and here’s an example of setting up a cluster environment.

Now to look for cluster traffic between them. The following should be in the master switch config:


This will add a nearby switch as a cluster slave.

allows to get command interface on a slave switch from the master’s interface. This is expected by design.


Let’s look at the traffic generated by



Hey! Where da hell is telnet traffic? Advisory clearly states:

The Cluster Management Protocol utilizes Telnet internally as a signaling and command protocol between cluster members.

Ok, running

to see some more traffic:


Aha! Telnet traffic is actually being encapsulated into layer 2 LLC packet. If we look close enough we will notice IP packets inside with chopped MAC addresses at source and destination fields. Inside those “IP” packets reside valid TCP frames with a telnet session.

show version in cluster traffic

A telnet session is usually preceded by negotiating telnet options. Among them are: terminal size, terminal type etc. Take a look at the RFC for more info.

Right before being presented with the welcome

message an interesting telnet option is transfered to the server side:

cluster magic string option

Here you can see a telnet option “CISCO_KITS” sent from the master switch to the slave. The very same string present in the Vault 7 documents during the execution of exploit. Time to take a closer look at the switch internals.

Peeking at firmware

Firmware is located at

on the switch.


Built-in ftp client allows to transfer this firmware to an arbitrary ftp server. Ok, now to analyze and extract contents of the file with binwalk:


In order to facilitate static analysis of the resulting binary we better know the firmware load offset. This offset is printed to serial console during boot process:


Fire up IDA and let’s roll. CPU architecture is PowerPC 32-bit BigEndian. Load the binary at 0x3000:

ida offset

Discovering strings

Remember the

string in the cluster traffic I captured before? This was my starting point. After discovering most of the functions in IDA, I was able to see the cross-refrences to the strings located at the end of firmware.

ida cisco kits string

“CISCO_KITS” string is referenced by

function, which just returns this string as

. We will focus out attention on on the

function at

which calls


ida proximity

Because telnet code is rather symmetrical for client and server here we actually can see the format of the buffer that is being sent to the server side –

. This actually goes in line with the observed traffic where the sent buffer was


Notice something? There are two

string modifiers but only one string is actually present in the traffic sample which is

, the second one is empty and is confined between two

chars. Further observing the control flow of the very same function I noticed some funny behaviour when dealing with the second string (this time the server-side portion of the code):


The data we sent over in the second %s string is actually copied until

char without checking the destination boundaries while the target buffer resides on the stack. What does this look like? Correct! Buffalo buffer overflow!

buffalo overflow

Getting code execution

Getting control of the instruction pointer was easy as it was overwritten with the buffer I sent (btw I used IODIDE for debugging). The problem was that heap and stack (which resides on the heap) were not executable. My best bet is that this is actually the effect of data and instruction caches enabled. Here’s a slide from Felix Lindner’s presentation at BlackHat 2009:

powerpc caches

ROPing a way out

Since there wasn’t a way to execute code on the stack I had to use it as a data buffer and reuse existing code in the firmware. The idea is to chain function epilogs in a meaningful way to perform arbitrary memory writes. But wait, write what? Take a look at the decompiled function at



Interesting things happen here. First thing to emphasize is that both calls of


are made indirectly by referencing global variables. Check line at address

function address is being loaded from dword at

. In a similar way the address of

is being loaded from

register at

. At this point

contents is a dereferenced pointer residing at address


Indirect calls

If the

call returns non zero and

call returns a value that differs from -1 we will be presented with a telnet shell without the need to provide any credentials. Variable

is being checked for its value further down the code:

privilege level check

What if I could overwrite these function pointers to something that always return the desired positive value? Since stack and heap weren’t directly executable I had to reuse the existing code to performs such memory writes. The following ROP gadgets were used:



function pointer into

, load the value to overwrite this pointer into

. The value to overwrite is an address of a function that always returns 1:

return 1 function


Perform the actual write.


Previous two gadgets load a pointer of

function into

, and the value to overwrite it with into

. The target value is a function that returns 15 (could’ve used this function for both writes tho):

return 15 function


This epilog makes the final write and returns to the legitimate execution flow. Of course, stack frame should be formed accordingly to make this rop chain work. Check out the exploit source to see the actual stack layout for this chain to work as intended.

Running the exploit

At the end of the day I ended up with a tool with the ability to patch function pointers responsible for credless connection and privilege level. Note that the exploit code is heavily dependent on the exact firmware version used on the switch. Using exploit code for some different firmware most probably will crash the device.

I used the knowledge from static and dynamic analysis of an older firmware SE1 to build an exploit for the latest suggested firmware 12.2(55)SE11. All the difference between firmware versions is different functions and pointers offsets. Also, the way the exploit works makes it easy to revert the changes back. Example:


To unset this behaviour:


This RCE POC is available here for both firmware versions. DoS version of this exploit is available as a metasploit module, it might work for most models mentioned in the Cisco advisory.



Leave a Reply