CVE-2018-4025
An exploitable denial-of-service vulnerability exists in the XML_GetRawEncJpg
Wi-Fi command of the NT9665X Chipset firmware, running on the Anker Roav A1 Dashcam, version “RoavA1_SW_V1.9”. A specially crafted packet can cause an invalid memory dereference, resulting in a device reboot.
Anker Roav A1 Dashcam RoavA1_SW_V1.9
https://goroav.com/products/roav-dash-cam-a1
7.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE-477: Use of Obsolete Function
The Novatek NT9665X SOC is a chipset used in an large number of consumer camera devices, particularly in dashboard cameras. The chip provides default firmware that is a fork of the Embedded Configurable Operating System (eCOS) project, which is found within the Roav A1 Dashcam,the product we are focusing on in this advisory.
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 they can control the camera remotely. 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 firmware-specific subset of commands are implemented on any given device, the list of which can be found by accessing http://192.168.1.254/?custom=1&cmd=3012
.
For the following vulnerability, the XML_GetRawEncJpg
command (2018) will be discussed. Like all the other Wi-Fi commands, the prototype for this function is:
XML_GetRawEncJpg(char *URLPath,
char *QueryStr,
char *POSTData,
size_t PostDataLen, //[0]
???,
???);
For the purposes of this vulnerability, we are focusing on the PostDataLen
field at [0], which represents the length of the string inside of the POSTdata
parameter. If we look at the first basic block of the XML_GetRawEncJpg
function, the following occurs:
ROM:80223C34 XML_GetRawEncJpg:
ROM:80223C34 addiu $sp, -0x50
ROM:80223C38 lui $a1, 0x8047
ROM:80223C3C sw $fp, 0x50+var_8($sp)
ROM:80223C40 move $fp, $sp
ROM:80223C44 sw $s0, 0x50+var_24($sp)
ROM:80223C48 sw $ra, 0x50+var_4($sp)
ROM:80223C4C sw $s6, 0x50+var_C($sp)
ROM:80223C50 sw $s5, 0x50+var_10($sp)
ROM:80223C54 sw $s4, 0x50+var_14($sp)
ROM:80223C58 sw $s3, 0x50+var_18($sp)
ROM:80223C5C sw $s2, 0x50+var_1C($sp)
ROM:80223C60 sw $s1, 0x50+var_20($sp)
ROM:80223C64 lw $s6, 0x50+arg_10($fp) //[1]
ROM:80223C68 sw $zero, 0x50+var_38($fp)
ROM:80223C6C lw $s2, 0x50+arg_14($fp)
ROM:80223C70 lw $s1, 0($a3) //[2]
Everything up to [1] is standard MIPS function prolog code, and we only really care about what happens at [2], which happens to dereference $a3
into $s1
. As shown in the XML_GetRawEncJpg
function prototype, $a3
is the PostDataLen
field, which is not a pointer that can be dereferenced. This leads the function to crash no matter what value is $a3
, since it was heuristically found that the maximum possible PostDataLen
is 0x8000. Also, due to how the NT9665X firmware loads, the lowest readable address is 0x80000000, so one cannot upload an extremely large file that would cause a valid dereference to an address greater than 0x80000000.
It is thought that this is leftover code from a previous Novatek firmware version that just never got updated, as the Roav Cam phone app does not actually include any mention of this command, and also that it seems to crash due to a prototype mismatch.
WifiCmd_DispatchCmd(): cmd:2018 evt:0 par:0 CB:80223c34 wait:0
WifiCmd_DispatchCmd(): ret 0
*** CPU Exception!!! cause 0x02: TLB exception (load or instruction fetch)
epc - 0x80223c70
$ra - 0x80356d4c
$sp - 0x80d58c08
$fp - 0x80d58c08
general registers:
$zero : 0x40240000 $at : 0xfffffffe $v0 : 0x80223c34 $v1 : 0x00000002
$a0 : 0x80d5653c $a1 : 0x80470000 $a2 : 0x80d43028 $a3 : 0x00008000
$t0 : 0x00000008 $t1 : 0x01010101 $t2 : 0x80d56da0 $t3 : 0x00000008
$t4 : 0x807d2bb4 $t5 : 0x00000014 $t6 : 0x80d56da0 $t7 : 0x80aed92c
$s0 : 0x80470000 $s1 : 0x80d5693d $s2 : 0x00000000 $s3 : 0x80d5653c
$s4 : 0x80d43028 $s5 : 0x00008000 $s6 : 0x00000000 $s7 : 0x00000000
$t8 : 0x06050014 $t9 : 0x00000001 null : 0x805a7f80 null : 0x80d58c60
gp : 0x8060f540 sp : 0x80d58c08 fp : 0x80d58c08 ra : 0x80356d4c
co-processor registers:
entrylo : 0x00000002 status : 0x00000008 vector : 0x0100c403 epc : 0x80223c70
cause : 0x00000000 badvaddr : 0x00800008 hwrena : 0x00000400 prid : 0x00019655
entrylo : 0x01645792
Thread(id) :
hfs data thread(261)
stack :
range(0x80d56d80 - 0x80d58d80)
call stack :
0 frame(0x80d58c08 - 0x80d58c58) ............................ $pc : 0x80223c70
+ 0x80d58c00 : 0x80670000 0x8059a7cc
+ 0x80d58c10 : 0x8059a92c 0x00000000 0x00000000 0x00000000
+ 0x80d58c20 : 0x00000000 0x00000000 0x00000000 0x80d3cdc0
+ 0x80d58c30 : 0x80470000 0x80470000 0x80d5693d 0x00000000
+ 0x80d58c40 : 0x80d5653c 0x80d43028 0x00008000 0x00000000
+ 0x80d58c50 : 0x80d58c58 0x80356d4c
1 frame(0x80d58c58 - 0x80d58cc0) ............................ $pc : 0x80356d44
+ 0x80d58c50 : 0x00000001 0x8009f850
+ 0x80d58c60 : 0x80d58c80 0x80808080 0x00000000 0x00000000
+ 0x80d58c70 : 0x00008000 0x00000000 0x00000000 0x00000001
+ 0x80d58c80 : 0x000007e2 0x00000000 0x80223c34 0x06050017
+ 0x80d58c90 : 0x80d58d20 0x8009ff34 0x80d42ffc 0x80d42ff4
+ 0x80d58ca0 : 0x80d3cdc0 0x06050013 0x06050014 0x06050015
+ 0x80d58cb0 : 0x06050016 0x06050017 0x80d58d20 0x803ca60c
2 frame(0x80d58cc0 - 0x80d58ce0) ............................ $pc : 0x803ca604
+ 0x80d58cc0 : 0x80d58d20 0x800b6784 0x06050016 0x8009cc1c
+ 0x80d58cd0 : 0x00000000 0x00000000 0x80d42ffc 0x803ca758
3 frame(0x80d58ce0 - 0x80d58d08) ............................ $pc : 0x803ca750
+ 0x80d58ce0 : 0x800a0000 0x06050011 0x06050012 0x8009cd00
+ 0x80d58cf0 : 0x00000000 0xdeadbeef 0x80d42ef8 0x06050011
+ 0x80d58d00 : 0x06050012 0x800990d8
4 frame(0x80d58d08 - 0x80d58d20) ............................ $pc : 0x800990d0
+ 0x80d58d00 : 0xdeadbeef 0xdeadbeef
+ 0x80d58d10 : 0xdeadbeef 0xdeadbeef 0x06050010 0x800990ac
5 frame(0x80d58d20 - 0x80d58d38) ............................ $pc : 0x800990a4
+ 0x80d58d20 : 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
+ 0x80d58d30 : 0xdeadbeef 0xdeadbeef
end
2018-10-29 - Talos contacts vendor
2018-11-02 - Report disclosed to vendor
2018-12-04 - 30 day follow up
2019-01-18 - 60 day follow up - Talos reaches out to TWNCERT for assistance reaching vendor (Novatek)>br>
2019-01-22 - TWNCERT contacted Novatek and advised Novatek will check emails for reports
2019-03-06 - 90+ day follow up - Talos asks TWNCERT for direct point of contact for Novatek
2019-03-27 - Talos sends follow up to TWNCERT
2019-04-02 - Talos sends copies of email correspondence and reports to TWNCERT
2019-04-18 - Suggested pubic disclosure date of 2019-05-13 (171 days after initial disclosure)
2019-04-19 - Vendor fixed issue and provided patch to their IDH
2019-05-13 - Public disclosure
Discovered by Lilith [<_<] of Cisco Talos.