Cisco IP Phone WebUI Remote Code Execution Vulnerability

27 March 2019












9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)




Cisco Systems






10.3(1)SR5 for Unified IP Conference Phone 8831

11.0(4)SR3 for Wireless IP Phone 8821 and 8821-EX

12.5(1)SR1 for the rest of the IP Phone 7800 and 8800 Series















This vulnerability allows remote attackers to execute arbitrary code on vulnerable Cisco IP Phones.

This is due to an exploitable buffer overflow vulnerability that exists in the web-based interface on firmware versions 10.3, 11.5, 12.5. The web service implementation incorrectly handles HTTP basic authentication header for requests to “LineInfo”, ”CallInfo” and “ModeInfo” functions, leading to stack based buffer overflow.

The firmware does implement ASLR mitigation however, it's not applied to the LIBC library, which results in having the same memory addresses and gives an attacker the possibility to use RetToLibc exploitation technique.

Tested versions:

  • cmterm-78xx.10-3-1-12
  • cmterm-78xx.11-5-1-18
  • cmterm-78xx.12-1-1SR1-4








Cisco IP Phone firmware provides a web interface based on JAVA UI and a native library which implements HTTP web server functionality. An attacker with access to the data network of IP Phone could gain access to the web interface with logging and  device information. According to firmware code, the pages “LineInfo”, “CallInfo” and “ModeInfo” are protected with HTTP Authorization.

The library contains function `extractUserNameAndPassword` which extracts authentication data from base64 encoding. This function initiates a buffer on the stack to store decoded password parameter with maximum size 0x101:


.text:0000F368                 SUB             R3, R11, #-neg_0x11c        <--------------

Buffer init in stack - [r11-11c], buffer size 0x101

.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



Then the "j_decodeUserPasswd" function writes 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 the maximum 0xFFFC number of bytes in the allocated buffer with size 0x101.


Writing loop init: 


.text:000179F8 loc_179F8                               ; CODE XREF:


.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

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

.text:00017A0C                 B               loc_17B4C                    <--------------

Jump to Loop End to check step



Decode and write to buffer functionality (for first two bytes): 


.text:00017A10 loc_17A10                               ; CODE XREF:


.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

.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:


.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 loc_17B4C                               ; CODE XREF:


.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







Sending a malformed request with a basic authorization field size more than 351 symbol will overflow the buffer and corrupt the stack.

This proof of concept demonstrates this vulnerability by causing a crash. The phone will reboot and possibly allow the user to read a crash report on the phone showing the memory corruption. 




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

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









05/12/2018 - Vulnerability discovered

13/12/2018 - Vulnerability details reported to Cisco PSIRT

14/12/2018 - Obtained Cisco Bug ID number - CSCvn67624

06/03/2018 - Obtained CVE number - CVE-2019-1716

20/03/2018 - Cisco official publication of CVE-2019-1716 






Apply patches provided by Cisco:

  • 3(1)SR5 and later for Cisco Unified IP Conference Phone 8831
  • 0(4)SR3 and later for Cisco Wireless IP Phone 8821 and 8821-EX
  • 12.5(1)SR1 and later for the rest of the Cisco IP Phone 7800 Series and 8800 Series 



Denys Vozniuk - xen1thLabs - Software Labs