Meraki RCE: When Red Team and Vulnerability Research fell in love. Part 2

Published:
By: Alberto García Illera


This is the second post where I explain how I compromised a Meraki device. The first post can be found here.

Binary attack surface

In this next phase, I did some recon to identify binaries listening in fixed ports. I identified two custom binaries that looked interesting enough to reverse-engineer: /usr/bin/poder_agent /usr/bin/test_tcp_server -p -l 3 7751

In addition, I found the CGIs that can be reached through the web server. The list of CGIs was obtained after understanding that Lighttpd was using a Linux socket tied with the fastcgi binary. Every reachable CGI is contained within fastcgi binary. The full list of CGIs is:

As you can see the CGI names alone reveal some information about interesting actions that can be performed. Most of them can be accessed without any kind of authentication, but we can use the mf_test credentials obtained earlier to access the rest.

Setup reversing environment

After using the command file in one of the binaries present on the system, I realized that the processor architecture was PowerPC and that the gnu debugger gdb was not present in the system. This meant a couple of things:

  • I needed to learn a new instruction set.
  • I needed to cross-compile gdb for PowerPC.

Thankfully I only needed to do the first one since gdbserver is conveniently present in the system. I’m an IDA Pro fan, so much so that I’m the kind of person that even uses IDA for debugging, not just disassembling. I tried to use IDA through the Remote GDB debugger connecting to the gdbserver. Unfortunately, IDA does not behave well while remotely debugging PowerPC. The reversing process was almost impossible because setting up breakpoints and stepping through the assembly instructions didn’t work as expected. I finally used GDB to do remote debugging and it worked perfectly.

Vulnerabilities

DNS control

A good attack vector, useful to steal user credentials is controlling the DNS servers to redirect users to fake sites. We can do so by using the mf_test credentials and accessing the /configure path:

Secrets disclosure

Given Meraki’s convenient management portal on the web, there must be some kind of authentication between the devices you own and the Meraki servers. A key is used to perform mutual authentication. However, there is a clear lack of privacy to access sensitive information due to the nature of some CGIs. I could use the unauth /stats/ps.cgi to list all the process running in the Meraki device and get the mtunnel token that is used to authenticate against the Meraki cloud. In doing so, I was able to flood the Meraki cloud with fake information.

Firmware update RCE

Another interesting CGI is /configure/raw_upgrade.cgi, which can be used to perform a firmware update. This is a very interesting attack vector since we can totally own the device by updating it using a malicious firmware. The CGI requires authentication but we can again use the mf_test credentials. The problem is that we don’t have a valid firmware file we can base our modification on. Luckily, after skimming a bunch of configuration files, I was able to find the URL where the vmlinuz file(gzipped linux kernel) is retrieved from: http://firmware.meraki.net:7734/firmware/node?mac=${mac}&key=${key}&desired_version=x86-wired-8-124331-files/vmlinuz At this point I have all the elements to get RCE in the device.

Shell execute RCE

One of the CGIs that grabbed my attention was run_shell.cgi. I could access it far too easily, without any kind of authentication:

It seemed to be expecting some kind of authentication to move forward, so it was time to use GDB to reverse engineer it. The CGI is expecting two parameters:

  • cmd: command you want to execute in the device
  • key: sha1(Meraki_SERIAL+command+fixed_salt)

In the next screenshot, you can see how the Meraki serial is prepended to the command ls followed by the hardcoded serial common in all Meraki devices:

We needed to create a different key for each command we wanted to run. I wrote a Python script to automate this process, and tested it in the MX80 and in a MX400. As I mentioned earlier, a Dropbear SSH server was listening at port 22, but password authentication was disabled. Still, we were able to add our public key to the list of authorized keys using this command:

echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgwC/tzx9gU7mr5KCC5rVORXoIPiFQEvDjve7GlVWH49IBm+RBSVFGTrkCdxLF8VZP40rmBnr549tNezcKIoRtdwIg/xzV/6UHS8IqWQQF8TD19E8uuTQ/AmLi91pfE2+zNDx0jrCBFBv8wwMRYLhSslXxu01UOPF3P7ZXyalmuCYBsjT > /etc/dropbear/authorized_keys

After that, simply using the private key for that previous public one was all it took to SSH into the Meraki device and create a reverse SSH connection to my C2 server.

Meraki in a VM

Eventually I noticed that the Meraki MX400 present in my target company was using Intel x86_64 architecture. Way more convenient than reversing a PowerPC! Using some details obtained earlier, I downloaded the firmware for Intel architecture from the Meraki cloud. I then used binwalk to get the filesystem and mount it using chroot.

With that, I was in possession of the full firmware, and had it mounted and working in a virtual machine.

Further reversing work was much easier from there on. This was because the architecture is Intel-based and is running in an Ubuntu 12.04 system with no restriction for hardware breakpoints as I had run into when reversing the binaries in the PowerPC device. In the next screenshot we can clearly see where the code is validating for the provided key in run_shell.cgi:

Conclusion

This Meraki switch turned out to be a vital attack vector into the target company, allowing us access to video camera systems, authentication portals, and other backend components. Red Teaming and Research are two things usually done independently. With this post I hope I was able to demonstrate how Research time is totally worthwhile during a Red Team engagement, and shouldn’t be limited to taking place only before or after the exercise. Great fun!

CVEs

Reporting timeline

  • First contact with vendor: 08/9/2014
  • Vendor first response: 08/9/2014
  • Vendor acknowledge the vulnerabilities: 09/29/2014
  • Vendor provide fix: 12/12/2014