Talos Vulnerability Report


Novatek NT9665X XML_GetRawEncJpg denial-of-service vulnerability

May 13, 2019
CVE Number



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.

Tested Versions

Anker Roav A1 Dashcam RoavA1_SW_V1.9

Product URLs


CVSSv3 Score

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_” 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 firmware-specific subset of commands are implemented on any given device, the list of which can be found by accessing

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.

Crash Output

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


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.