CVE-2018-3880
An exploitable stack-based buffer overflow vulnerability exists in the database “find-by-cameraId” functionality of video-core
’s HTTP server of Samsung SmartThings Hub. The video-core
process incorrectly handles existing records inside its SQLite database, leading to a buffer overflow on the stack. An attacker can send an HTTP request to trigger this vulnerability.
Samsung SmartThings Hub STH-ETH-250 - Firmware version 0.20.17
https://www.smartthings.com/products/smartthings-hub
8.2 - CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
CWE-120: Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)
Samsung produces a series of devices aimed at controlling and monitoring a home, such as wall switches, LED bulbs, thermostats and cameras. One of those is the Samsung SmartThings Hub, a central controller which allows an end user to use their smartphone to connect to their house remotely and operate other devices through it. The hub board utilizes several systems on chips. The firmware in question is executed by an i.MX 6 SoloLite processor (Cortex-A9), which has an ARMv7-A architecture.
The firmware is Linux-based, and runs a series of daemons that interface with devices nearby via ethernet, ZigBee, Z-Wave and Bluetooth protocols. Additionally, the hubCore
process is responsible for communicating with the remote SmartThings servers via a persistent TLS connection. These servers act as a bridge that allows for secure communication between the smartphone application and the hub. End users can simply install the SmartThings mobile application on their smartphone to control the hub remotely.
One of the features of the hub is that it connects to smart cameras, configures them and looks at their livestreams. For testing, we set up the Samsung SmartCam SNH-V6414BN on the hub. Once done, the livestream can be displayed by the smartphone application by connecting either to the remote SmartThings servers, or directly to the camera, if they’re both in the same subnetwork.
Inside the hub, the livestream is handled by the video-core
process, which uses ffmpeg
to connect via RTSP to the smart camera in its same local network, and at the same time, provides a streamable link for the smartphone application.
The remote SmartThings servers have the possibility to communicate with the video-core
process by sending messages in the persistent TLS connection, established by the hubCore
process. These messages can encapsulate an HTTP request, which hubCore
would relay directly to the HTTP server exposed by video-core
. The HTTP server listens on port 3000, bound to the localhost address, so a local connection is needed to perform this request.
We identified a vulnerable request that can be exploited to achieve code execution on the video-core
process, which is running as root.
By sending an HTTP DELETE request for the /cameras/<camera-id>
path it’s possible to delete an existing smart camera which has the specified “camera-id”.
This request is handled by function sub_4A6C8
:
.text:0004A6C8 sub_4A6C8
.text:0004A6C8
.text:0004A6C8 dest = -0x2CDC
.text:0004A6C8 var_2CC0= -0x2CC0
.text:0004A6C8 var_2AC0= -0x2AC0
.text:0004A6C8 var_2040= -0x2040
.text:0004A6C8 var_2000= -0x2000
.text:0004A6C8 arg_0 = 4
.text:0004A6C8 arg_4 = 8
.text:0004A6C8
.text:0004A6C8 000 STMFD SP!, {R4-R6,R11,LR}
.text:0004A6CC 014 ADD R11, SP, #0x10
...
.text:0004A768 2CE8 SUB R2, R11, #-var_2040
.text:0004A76C 2CE8 MOV R0, R6
.text:0004A770 2CE8 MOV R1, R4
.text:0004A774 2CE8 SUB R2, R2, #0x18 ; [1]
.text:0004A778 2CE8 BL db_camera_by_id ; [2]
Soon after initialization, the function db_camera_by_id
is called [2], passing as parameters the “camera-id” specified in the request, the “camera-id” string length, and a buffer allocated on the stack [1] where all the information about the camera is expected to be stored.
.text:0001458C db_camera_by_id
.text:0001458C
...
.text:000145A4 000 STMFD SP!, {R4-R11,LR}
.text:000145A8 024 ADD R11, SP, #0x24+var_4
.text:000145AC 024 MOV R5, R1
.text:000145B0 024 SUB SP, SP, #0x14
.text:000145B4 038 MOV R4, R2
.text:000145B8 038 MOV R1, #0
.text:000145BC 038 STR R0, [R11,#-0x34]
.text:000145C0 038 MOV R0, R2
.text:000145C4 038 MOV R2, #0x2044
.text:000145C8 038 STR R1, [R11,#-0x30]
.text:000145CC 038 ADD R8, R4, #0x2040
.text:000145D0 038 BL memset
.text:000145D4 038 ADD R2, R5, #8
.text:000145D8 038 LDR R3, [R11,#-0x34]
.text:000145DC 038 LDR R12, [R11,#-0x30]
.text:000145E0 038 BIC R2, R2, #7
.text:000145E4 038 SUB SP, SP, R2
.text:000145E8 038 MOV R2, R5
.text:000145EC 038 MOV R1, R3
.text:000145F0 038 MOV R0, SP
.text:000145F4 038 LDR R6, =columnArr ; [3]
.text:000145F8 038 MOV R7, R12
.text:000145FC 038 MOV R10, SP
.text:00014600 038 MOV R9, R12
.text:00014604 038 ADD R8, R8, #8
.text:00014608 038 ADD R4, R4, #8
.text:0001460C 038 STRB R12, [SP,R5]
.text:00014610 038 BL memcpy ; [4]
.text:00014614
.text:00014614 loc_14614 ; [5] loop
.text:00014614 038 MOV R2, R6 ; [7]
.text:00014618 038 MOV R0, #0
.text:0001461C 038 MOV R1, R10
.text:00014620 038 SUB R3, R11, #0x28 ; [8]
.text:00014624 038 STR R9, [R11,#-0x28]
.text:00014628 038 ADD R6, R6, #0x84
.text:0001462C 038 BL db_find ; [6]
.text:00014630 038 CMN R0, #6
.text:00014634 038 BEQ loc_14674
.text:00014638 038 CMP R0, #0
.text:0001463C 038 BLT loc_14680
.text:00014640 038 LDR R5, [R11,#-0x28]
.text:00014644 038 ADD R7, R7, #1
.text:00014648 038 MOV R0, R5
.text:0001464C 038 BL strlen
.text:00014650 038 STR R0, [R4,#-4]
.text:00014654 038 MOV R0, R5 ; [8]
.text:00014658 038 BL strlen ; [9]
.text:0001465C 038 MOV R1, R5
.text:00014660 038 MOV R2, R0
.text:00014664 038 MOV R0, R4
.text:00014668 038 BL memcpy ; [10]
.text:0001466C 038 MOV R0, R5
.text:00014670 038 BL free
.text:00014674
.text:00014674 loc_14674
.text:00014674 038 ADD R4, R4, #0x204
.text:00014678 038 CMP R4, R8
.text:0001467C 038 BNE loc_14614 ; [5] loop
.text:00014680
.text:00014680 loc_14680
.text:00014680 038 CMP R7, #0
.text:00014684 038 BEQ loc_146A4
.text:00014688 038 CMP R7, #0xF
.text:0001468C 038 MOVGT R0, #0
.text:00014690 038 MOVLE R0, #1
.text:00014694
.text:00014694 loc_14694
.text:00014694 038 SUB SP, R11, #0x20
.text:00014698 024 LDMFD SP!, {R4-R11,PC}
The function searches for the camera with the given id in the database and saves each column in the buffer passed as third argument.
At [4] the first argument of the function (“camera-id”) is copied on the stack and is used by the db_find
function [6] as a filter on the database.
We can see that the function loops [5], and for each column of the table [7], pointed by the array at [3], a query is performed. Depending on [7], db_find
will execute the following query:
SELECT <third-argument> FROM camera WHERE cameraId='666f8370-05b7-424d-a5e2-28a2dc8477de'
The pointer to the string resulting from the query will be saved in the fourth argument [8].
Finally, if the query is successful, the result is saved using memcpy
[10] on the caller’s buffer [2]. Moreover, the length
parameter of the memcpy
is set from the strlen
[9] output of the source string itself. At high level this would be:
memcpy(stack_buffer, query_result, strlen(query_result));
Since the query_result
is directly fetched from the database, there is no restriction on the length of the copy operation, which allows for overflowing the stack buffer of the parent function and execute arbitrary code.
To get this data into the database, the vulnerability described in TALOS-2018-0556 could be used. Note that while we scored this vulnerability CVSS 8.2 on its own, it would constitute a CVSS 9.9 (CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) when combined with TALOS-2018-0556. This is demonstrated in the proof of concept below.
The following proof of concept shows how to crash the video-core
process:
1- Add a new camera with id $sCameraId in the "camera table" of the video-core database, using an overlong value in any other column. This is possible, for example, using using TALOS-2018-0556.
2- Send the DELETE request, using curl from inside the hub, but the same request could be sent using a SmartApp.
$ curl -X DELETE "http://127.0.0.1:3000/cameras/${sCameraId}"
2018-04-09 - Vendor Disclosure
2018-05-23 - Discussion with vendor/review of timeline for disclosure
2018-07-17 - Vendor patched
2018-07-26 - Public Release
Discovered by Claudio Bozzato of Cisco Talos.