Talos Vulnerability Report

TALOS-2018-0685

Anker Roav A1 Dashcam WifiCmd 9999 Code Execution Vulnerability

May 13, 2019
CVE Number

CVE-2018-4014

Summary

An exploitable code execution vulnerability exists in Wi-Fi Command 9999 of the Roav A1 Dashcam. A specially crafted packet can cause a stack-based buffer overflow, resulting in code execution. An attacker can send a packet to trigger this vulnerability.

Tested Versions

Anker Roav A1 Dashcam RoavA1SWV1.9

Product URLs

https://goroav.com/products/roav-dash-cam-a1

CVSSv3 Score

8.0 - CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H

CWE

CWE-121: Stack-based Buffer Overflow

Details

The Roav A1 Dashcam by Anker is a dashboard camera that allows users to connect using the Roav app for Android and iOS so that the users can toggle settings and download videos from the dashcam, along with a host of other features. In order to do this, users must first enable the “Wi-Fi AP” setting manually on the dashcam, and then connect to the “RoavA1” SSID, with the default password of “goroavcam.”

From here, the app interacts mainly with the dashcam via an eCOS webserver running on port 80 that requires no authentication. The standard HTTP POST, GET, and DELETE requests can be used to upload, download, or delete videos and pictures from the dashcam, but there’s also a separate interface used for configuration. When requesting any URL, a set of commands is accessed by providing the following HTTP query string: ?custom=1&cmd=<0000-9999>. It should be noted that only a subset of commands are implemented, the list of which can be found by accessing http://192.168.1.254/?custom=1&cmd=3012.

For the purposes of this writeup, only command 9999 will be discussed, which seems to take an input string in the query string and output a custom encoded string in the XML response. For example, using the URL of http://192.168.1.254/?custom=1&cmd=9999&str=boop, a response is given as follows:

<?xml version="1.0" encoding="UTF-8" ?>
<Function>
<Cmd>9999</Cmd>
<Status>0</Status>
<String>7tD/PQ==</String>
</Function>

The encoding function takes one parameter, the string to encode, and then actually encodes in place, one byte at a time, XORing against a value that stems from a hardcoded string.

Examining the disassembly of the call site, we can see:

ROM:802259F4       addiu   $s0, $fp, 0x78+tos_8  // [2]
ROM:802259F8       move    $a0, $s0              // [1]
ROM:802259FC       jal     vuln_encoding_func
ROM:80225A00       sw      $a3, 0x78+var_20($fp)
ROM:80225A04       move    $a0, $v0
ROM:80225A08       jal     strlen
ROM:80225A0C       move    $s0, $v0
ROM:80225A10       move    $a1, $v0

At [1], the string being encoded is at $s0, which points to a size 0x40 buffer on the stack [2]. For a better picture, here is the stack layout:

ROM:802259A8 Wifi_Cmd_9999:
ROM:802259A8
ROM:802259A8 tos             = -0x68
ROM:802259A8 tos_8           = -0x60
ROM:802259A8 after_0x40_buffer= -0x20
ROM:802259A8 var_14          = -0x14
ROM:802259A8 var_10          = -0x10
ROM:802259A8 var_C           = -0xC
ROM:802259A8 var_8           = -8
ROM:802259A8 var_4           = -4
ROM:802259A8 arg_10          =  0x10

Since the encoding happens in place, it becomes necessary to know what is there in the first place. In short, the contents of that buffer are populated with a call to a sprintf wrapper, resulting in sprintf(0x40_size_buffer,”%s”,<&str value>). This will result in a buffer overflow, since the value of the &str= query parameter is under user control.

However, since the Wifi_Cmd_9999 function does not return until after encoding, there are some extra constraints to exploitation — namely that buffer[0x44] must be a readable and writable address after encoding, and also that the overflowed return address is a valid executable return address (post-encoding).

Crash Output

*** CPU Exception!!! cause 0x02: TLB exception (load or instruction fetch)
epc  - 0x8022238c
$ra  - 0x80222394
$sp  - 0x80d42428
$fp  - 0x80d42428
general registers:
     $zero : 0x69666977       $at : 0x00000000       $v0 : 0x80d425c4       $v1 : 0x805f0000
       $a0 : 0x80d425c4       $a1 : 0x804691b8       $a2 : 0x80d42fc8       $a3 : 0xc2c2449c
       $t0 : 0x80584fe8       $t1 : 0x00000002       $t2 : 0x00c2c200       $t3 : 0x00000041
       $t4 : 0x0000008a       $t5 : 0xffffff00       $t6 : 0x00000008       $t7 : 0x80aed96c
       $s0 : 0x80d42fc8       $s1 : 0x80d42979       $s2 : 0xc2c2449c       $s3 : 0x80d42979
       $s4 : 0x8058502c       $s5 : 0x0000270f       $s6 : 0x80d42fc8       $s7 : 0x805a0000
       $t8 : 0x80d424a7       $t9 : 0x00000001      null : 0x61766f6e      null : 0x206b6574
        gp : 0x8060f540        sp : 0x80d42428        fp : 0x80d42428        ra : 0x80222394
co-processor registers:
   entrylo : 0xaaaaaad8    status : 0x00000008    vector : 0x0100c403       epc : 0x8022238c
     cause : 0x00000000  badvaddr : 0x80800008    hwrena : 0x00000400      prid : 0x00019655
   entrylo : 0x01205792
Thread(id) :

  Hfs Session(260)
stack      :
    range(0x80d3ce94 - 0x80d42e94)
call stack :
  0 frame(0x80d42428 - 0x80d42460) ............................ $pc : 0x8022238c
     + 0x80d42420 :                       0x40082c30 0x70706120
     + 0x80d42430 : 0x80d42428 0x206b6574 0x80d42478 0x80d42979
     + 0x80d42440 : 0x80d42478 0x80d42979 0x80d42fc8 0x80d42979
     + 0x80d42450 : 0x00000000 0x80d533db 0x80d42460 0x80225a38
  1 frame(0x80d42460 - 0x80d424d8) ............................ $pc : 0x80225a30
     + 0x80d42460 : 0x80d42490 0x805a0000 0x80d42478 0x80808080
     + 0x80d42470 : 0x80d425c4 0x000004ec 0x0cd1fecd 0x3f8b65c2
     + 0x80d42480 : 0xf420bd04 0x1094627f 0x7f1d0a74 0xcc98f51b
     + 0x80d42490 : 0xd907e049 0xc015b021 0xcba03e57 0xb8a58170
     + 0x80d424a0 : 0xf5bc2e10 0x911b4808 0x8beaaf16 0x0ac2988c
     + 0x80d424b0 : 0xafebd3a7 0x2f9d4d6a 0xc2c2449c 0x80d42900
     + 0x80d424c0 : 0x00000000 0x80470000 0x80d42968 0x80d42590
     + 0x80d424d0 : 0x80d424d8 0x803570cc

Timeline

2018-10-29 - Vendor Disclosure
2018-11-02 - 2nd vendor contact
2018-11-05 - Vendor acknowledged & created ticket reference
2019-01-03 - 60 day follow up; Vendor closed ticket and advised issue under review with Engineering team; Talos requested point of contact for Engineering team
2019-03-06 - 90 + day follow up
2019-03-27 - Final notice of public disclosure
2019-04-18 - Suggested public disclosure date (171 days after initial disclosure) 2019-05-13 - Public Release

Credit

Discovered by Lilith ¯\_(ツ)_/¯ of Cisco Talos.