Lucene search

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

Samsung SmartThings Hub video-core AWSELB Cookie Code Execution Vulnerability(CVE-2018-3925)

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

0.001 Low

EPSS

Percentile

41.8%

Summary

An exploitable buffer overflow vulnerability exists in the remote
video-host communication of video-core’s HTTP server of Samsung
SmartThings Hub. The video-core process insecurely parses the AWSELB
cookie while communicating with remote video-host servers, leading to a
buffer overflow on the heap. An attacker able to impersonate the remote
HTTP servers could 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

8.5 - CVSS:3.0/AV:N/AC:H/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 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 a PUT request for the
/cameras/<camera-id>/streams/<stream-type> path, it’s possible to make
the hub to start streaming the camera’s video (specified by the
“camera-id”) towards the remote servers. The “stream-type” can have
multiple values and represent the kind of stream requested, for example
it could be set to “hls1080p”. The following is an example of such
request:

$ curl "http://127.0.0.1:3000/cameras/<camera-id>/streams/hls1080p" -d '{"streamClass":"hls2segs","oauthToken":"Bearer <oauth-token>"}'

Note that the “oauth-token” is an OAuth 2.0 Bearer Token (canonical
UUID), provided by auth-global.api.smartthings.com. Such a request is
handled by function sub_4B078, which in turn calls sub_4CDC4 for
setting up the communication with a remote video-host server and
providing the remote streaming feature:

.text:0004CDC4     sub_4CDC4
.text:0004CDC4
.text:0004CDC4     var_228= -0x228
.text:0004CDC4     var_224= -0x224
.text:0004CDC4     var_220= -0x220
.text:0004CDC4     var_21C= -0x21C
.text:0004CDC4     var_218= -0x218
.text:0004CDC4     var_214= -0x214
.text:0004CDC4     var_210= -0x210
.text:0004CDC4     ptr    = -0x20C
.text:0004CDC4     s      = -0x208
.text:0004CDC4
.text:0004CDC4 000        STMFD           SP!, {R4-R11,LR}
.text:0004CDC8 024        MOV             R3, #0
.text:0004CDCC 024        SUB             SP, SP, #0x204
.text:0004CDD0 228        MOV             R7, R1
.text:0004CDD4 228        MOV             R4, R0
.text:0004CDD8 228        STR             R2, [SP,#0x228+var_220]
.text:0004CDDC 228        STR             R3, [SP,#0x228+var_210]
.text:0004CDE0 228        STR             R3, [SP,#0x228+ptr]
.text:0004CDE4 228        BL              http_resp_packer__buffer_init
.text:0004CDE8 228        MOV             R1, #:lower16:aStreamclassHls    ; "{\"streamClass\": \"hls2segs\"}"
.text:0004CDEC 228        MOV             R9, R0
.text:0004CDF0 228        MOVT            R1, #:upper16:aStreamclassHls    ; "{\"streamClass\": \"hls2segs\"}"
.text:0004CDF4 228        BL              http_build_answer                ; [1]
...
.text:0004CE98 228        BL              http_stream_curl_request         ; [2]
...
.text:0004CEDC 228        ADD             R1, R7, #0x1200
.text:0004CEE0 228        STR             R3, [R4,#0x8F4]
.text:0004CEE4 228        ADD             R2, R7, #0xC
.text:0004CEE8 228        ADD             R1, R1, #0x10
.text:0004CEEC 228        LDR             R0, [SP,#0x228+var_218]
.text:0004CEF0 228        BL              sub_4C570                        ; [3]

At [1], the function starts to build an answer for the request that is
being handled. The answer is composed by a JSON string, which will be
filled by the answer from the request at [2]. The request [2] is a
remote request toward a video-host server: the server’s address is
stored in video-core’s database, and in the hub that we tested this
address is “https://vh-na04-useast2.connect.smartthings.com:8300”.

The communication generated at [2] is the following:

- video-core --> https://vh-na04-useast2.connect.smartthings.com:8300
PUT /cameras/<camera-id>/streams/hls1080p HTTP/1.1
Host: vh-na04-useast2.connect.smartthings.com:8300
Accept: */*
Content-Type: application/json
Authorization: Bearer <oauth-token>
Content-Length: 27
Connection: close

{"streamClass": "hls2segs"}

- https://vh-na04-useast2.connect.smartthings.com:8300 --> video-core
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, OPTIONS, DELETE
Access-Control-Allow-Origin: *
Cache-control: no-cache="set-cookie"
Content-Type: text/html; charset=utf-8
ETag: W/"5T7hZ36v7ulr9v0HTY4E2g=="
Server: nginx/1.12.0
Set-Cookie: AWSELB=4D83E80E23DA7677A73134EC01A12610C0D45FFDF9389B9D15CD82A43087013F829D09859E3CA0909290FDFFE8AEEB654FC7CEE34F9A088ABB9A8D69753700706BCB37AE10;PATH=/;MAX-AGE=1800
X-Powered-By: Express
Content-Length: 1288
Connection: Close

<json-with-streaming-information>

The HTTP body in the response contains a series of parameters that allow
for pushing the camera stream remotely. Moreover, we can see that a
cookie with name “AWSELB” is set. At [3], function sub_4C570 parses
the cookies, extracting the value of “AWSELB” if present.

.text:0004C570     sub_4C570
.text:0004C570
.text:0004C570     var_210= -0x210
.text:0004C570     var_20C= -0x20C
.text:0004C570     var_208= -0x208
.text:0004C570     save_ptr= -0x204
.text:0004C570     s      = -0x200
.text:0004C570
.text:0004C570 000        STMFD           SP!, {R4-R9,LR}
.text:0004C574 01C        MOV             R8, #debug_log
.text:0004C57C 01C        MOV             R9, R2
.text:0004C580 01C        MOV             R2, #0
.text:0004C584 01C        SUB             SP, SP, #0x1F4
.text:0004C588 210        LDR             R3, [R8]
.text:0004C58C 210        MOV             R4, R0
.text:0004C590 210        MOV             R6, R1
.text:0004C594 210        STR             R2, [R9]
.text:0004C598 210        CMP             R3, #2
.text:0004C59C 210        BHI             loc_4C6CC
.text:0004C5A0
.text:0004C5A0     loc_4C5A0
.text:0004C5A0 210        MOV             R1, #:lower16:0x40001C
.text:0004C5A4 210        MOV             R0, R4
.text:0004C5A8 210        MOVT            R1, #:upper16:0x40001C      ; CURLINFO_COOKIELIST
.text:0004C5AC 210        ADD             R2, SP, #0x210+var_208
.text:0004C5B0 210        BL              curl_easy_getinfo           ; [4]
.text:0004C5B4 210        CMP             R0, #0
.text:0004C5B8 210        BNE             loc_4C71C
.text:0004C5BC 210        LDR             R7, [SP,#0x210+var_208]
.text:0004C5C0 210        CMP             R7, #0
.text:0004C5C4 210        BEQ             loc_4C6A4
.text:0004C5C8
.text:0004C5C8     loc_4C5C8
.text:0004C5C8 210        MOV             R1, #:lower16:asc_C6C8C     ; " \t"
.text:0004C5CC 210        LDR             R0, [R7]
.text:0004C5D0 210        MOVT            R1, #:upper16:asc_C6C8C     ; " \t"
.text:0004C5D4 210        ADD             R2, SP, #0x210+save_ptr
.text:0004C5D8 210        BL              __strtok_r                  ; [5]
.text:0004C5DC 210        SUBS            R4, R0, #0
.text:0004C5E0 210        BEQ             loc_4C698
.text:0004C5E4
.text:0004C5E4     loc_4C5E4
.text:0004C5E4 210        MOV             R0, R4
.text:0004C5E8 210        BL              strlen
.text:0004C5EC 210        CMP             R0, #6
.text:0004C5F0 210        MOV             R1, R4
.text:0004C5F4 210        MOVCC           R2, R0
.text:0004C5F8 210        MOV             R0, #:lower16:aAwselb       ; "AWSELB"
.text:0004C5FC 210        MOVCS           R2, #6
.text:0004C600 210        MOVT            R0, #:upper16:aAwselb       ; "AWSELB"
.text:0004C604 210        BL              strncmp                     ; [6]
.text:0004C608 210        MOV             R1, #:lower16:asc_C6C8C     ; " \t"
.text:0004C60C 210        MOV             R5, R0
.text:0004C610 210        ADD             R2, SP, #0x210+save_ptr
.text:0004C614 210        MOV             R0, #0
.text:0004C618 210        MOVT            R1, #:upper16:asc_C6C8C     ; " \t"
.text:0004C61C 210        BL              __strtok_r
.text:0004C620 210        SUBS            R4, R0, #0
.text:0004C624 210        BEQ             loc_4C698
.text:0004C628 210        CMP             R5, #0
.text:0004C62C 210        BNE             loc_4C5E4
.text:0004C630 210        MOV             R1, R4
.text:0004C634 210        MOV             R0, R6
.text:0004C638 210        BL              strcpy                      ; [7]
.text:0004C63C 210        MOV             R0, R6
.text:0004C640 210        BL              strlen
.text:0004C644 210        LDR             R3, [R8]
.text:0004C648 210        STR             R0, [R9]
.text:0004C64C 210        CMP             R3, #2
.text:0004C650 210        BLS             loc_4C5E4

At [4] the function curl_easy_getinfo is called for extracting the
list of cookies, which will be stored in var_208. Then, by using
strtok [5], the function loops over all the cookies’ values in the
response, and if any one of them starts with the string “AWSELB” [6],
its value is copied using strcpy [7] into the heap buffer passed as
parameter, which has a size of 512 bytes.

Since the cookies are controlled by the remote server and there is no
restriction on the length of the copy operation, anyone able to
impersonate a video-host server could be able to overflow the heap
buffer and execute arbitrary code.

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

0.001 Low

EPSS

Percentile

41.8%