Talos Vulnerability Report

TALOS-2018-0580

Yi Technology Home Camera 27US cloudAPI SSID Code Execution Vulnerability

October 31, 2018
CVE Number

CVE-2018-3910

Summary

An exploitable code execution vulnerability exists in the cloud OTA setup functionality of Yi Home Camera 27US 1.8.7.0D. A specially crafted SSID can cause a command injection, resulting in code execution. An attacker can cause a camera to connect to this SSID to trigger this vulnerability. Alternatively, an attacker can convince a user to connect their camera to this SSID.

Tested Versions

Yi Technology Home Camera 27US 1.8.7.0D

Product URLs

https://www.yitechnology.com

CVSSv3 Score

8.8 - CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H

CWE

CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)

Details

Yi Home Camera is an IoT home camera sold globally. The 27US version is one of the newer models sold in the US, and is the most basic model out of the Yi Technology camera lineup. It still, however, includes all the functionality that one would expect from an IoT device: the ability to view the video from anywhere, offline and subscription-based cloud storage, and ease of setup.

During the network configuration stage of the setup, the Yi camera prompts the user to show it a QR code that is generated by the app running on the user’s phone. The user types in the SSID and password of the network that they wish for the camera to connect to, and then the app communicates to https://api.us.xiaoyi.com, generating a QR code containing the SSID and an encrypted password of the access point. Once the camera is connected to the internet, it then proceeds to sync up with the application, and also notifies the Yi servers that it is online, with the following cloudAPI command:

[./cloud][4/9/15:6:9:476]: cmd = /home/app/cloudAPI -c 138 
-url 	"https://api.us.xiaoyi.com/v4/ipc/on_line" 
-key <redact> 
-keySec <redact>
-uid <redact>
-version 1.8.7.0D_201708091510 
-ssid "maSSID" 	
-mac B0:D5:9D:11:22:33
-ip 10.10.69.69
-signal_quality 100 
-packetloss 0 
-p2pconnect 0 
-p2pconnect_success 0 
-tfstat 10000

That ends up generating a request that looks like the following:

req_info=https://api.us.xiaoyi.com/v4/ipc/on_line?hmac=<redact>	%3D&seq=9&uid=<redact>&password=<redact>&
version=1.8.7.0D_201708091510&model=0&port=0&
mac=B0:D5:9D:11:22:33&packetloss=0&p2pconnect=0&
p2pconnect_success=0&tfstat=10000&timestamp=1523286369&
ext_info=%7B%22p2p_encrypt%22%3A%22true%22%2C%22
ssid%22%3A%22maSSID%22%2C%22mac%22%3A%22B0%3AD5%3A9D	%3A11%3A22%3A33%22%2C%22ip%22%3A%2210.10.69.69
%22%2C%22signal_quality%22%3A%22100%22%7D

More interesting, though, is how the above command is put together in the first place. Examining the cloud binary that utilizes this cloudAPI shows us the following string containing “on_line”:

aSC138UrlSV4Ipc DCB "%s -c 138 -url ",0x22,"%s/v4/ipc/on_line",0x22," -key %s -keySec"
.rodata:0001A12C                                         ; DATA XREF: webapi_do_login+1F4↑o
.rodata:0001A12C                                         ; .text:off_10BBC↑o
.rodata:0001A12C                 DCB " %s -uid %s -version %s -ssid ",0x22,"%s",0x22," 
.rodata:0001A12C		DCB “-mac %s -ip %s "
.rodata:0001A12C                 DCB "-signal_quality %d -packetloss %d -p2pconnect %d 
				-p2pconnect_success %d -tfstat %d ",0

This command string gets sent directly to popen and eventually evaluated with a sh -c <cmd>:

// cloud.c: webapi_do_login@~0x10864
MOV     R1, #0x800      ; maxlen
LDR     R2, =aSC138UrlSV4Ipc ; "%s -c 138 -url \"%s/v4/ipc/on_line\" -k"...
LDR     R3, =aHomeAppCloudap ; "/home/app/cloudAPI"
BL      snprintf		//[1]
STR     R6, [SP,#0x15F8+also_key_sec]
LDR     R0, =aCloudC    ; "cloud.c"
LDR     R1, =aWebapiDoLogin_0 ; "webapi_do_login"
LDR     R2, =0x856
LDR     R3, =aCmdS      ; "cmd = %s\n"   
BL      dump_string	//[2]
MOV     R4, #3
[…]
MOV     R1, #0x800
MOV     R3, R`1
MOV     R2, #0
MOV     R0, R5
BL      memset_s
MOV     R1, R5 	
MOV     R2, #0x800
MOV     R3, #0xA
MOV     R0, R6
BL      path_to_bin_sh  ; (cmd, res_dst, res_len, timeout?) //[3]

At [1], we see the command being built on the stack, with R0 pointing to [stackbase -0x1028]. At [2], the cause of the previous log message above is shown, and at [3], the resulting call to path_to_bin_sh is given, with R0 once again pointing to [stackbase-0x1028]. And for brevity, path_to_bin_sh does just go straight into popen:

EXPORT path_to_bin_sh
path_to_bin_sh

CMP     R1, #0
CMPNE   R0, #0
STMFD   SP!, {R4-R10,LR}
MOV     R5, R1
SUB     SP, SP, #0x90
MOVEQ   R4, #1
MOVNE   R4, #0
BEQ     loc_151B0 ; not taken

LDR     R1, =(aSyncFinishRegi+0x14) ; modes
MOV     R9, R2
MOV     R6, R3
MOV     R8, R0
BL      popen

Thus, if someone connects their own camera, or convinces someone else to connect their camera to an SSID with any sort of command injection strings, it will simply be evaluated as a command. If we have an SSID named TotesLegit$(echo asdf>/lol.txt), the resulting on_line packet sent to https://api.us.xiaoyi.net is as such:

req_info=https://api.us.xiaoyi.com/v4/ipc/on_line?hmac=<redact>	%3D&seq=9&uid=<redact>&password=<redact>&
version=1.8.7.0D_201708091510&model=0&port=0&
mac=B0:D5:9D:11:22:33&packetloss=0&p2pconnect=0&
p2pconnect_success=0&tfstat=10000&timestamp=1523286369&
ext_info=%7B%22p2p_encrypt%22%3A%22true%22%2C%22
ssid%22%3A%22TotesLegit%22%2C%22mac%22%3A%22B0%3AD5%3A9D	%3A11%3A22%3A33%22%2C%22ip%22%3A%2210.10.69.69
%22%2C%22signal_quality%22%3A%22100%22%7D

//decoded ext_info:
ext_info={"p2p_encrypt":"true","
ssid":"TotesLegit","mac":"B0:D5:9D:11:22:33","ip":"10.10.69.69”
,"signal_quality":"100"}

The command injection is not included, as it has been evaluated and ran as a command:

~ # ls -la /lol.txt && cat /lol.txt
-rw-r--r--    1 root     root            10 Apr  9 15:06 /lol.txt
asdf

It should be noted that SSID’s are limited in length (32 bytes), and that the camera does not have wget or curl or netcat natively on the box, so options are limited for the actual payload. Enterprising individuals might take advantage of the cloudAPI binary’s network functionality to gain a foothold, however.

Timeline

2018-05-01 - Vendor disclosure
2018-09-03 - Vendor submitted build to Talos for testing
2018-09-05 - Talos confirmed issue patched
2018-10-22 - Vendor released new firmware
2018-10-31 - Public release

Credit

Discovered by Lilith Q(‘.’Q) of Cisco Talos.