CVE-2018-4014
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.
Anker Roav A1 Dashcam RoavA1_SW_V1.9
https://goroav.com/products/roav-dash-cam-a1
8.0 - CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H
CWE-121: Stack-based Buffer Overflow
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 “Roav_A1_
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).
*** 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
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
Discovered by Lilith ¯\_(ツ)_/¯ of Cisco Talos.