An exploitable code execution vulnerability exists in the
XML_UploadFile 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 a stack-based buffer overflow, resulting in code execution.
Anker Roav A1 Dashcam RoavA1_SW_V1.9
10.0 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CWE-121: Stack-based Buffer Overflow
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 and 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 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. The camera accesses a set of commands when requesting any URL after 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 is found here: http://192.168.1.254/?custom=1&cmd=3012.
XML_UploadFile command (5001) is covered in this vulnerability. This particular command is not just found in the Roav line of dashcams, but seems to be a default command in the Novatek NT9665X firmware. Note, however, that while this command shows up in all the NT9665X devices, the device in question might not be vulnerable, as certain devices (e.g. The SJ6 Camera) contain extra checks to avoid the issue.
When using any of the Wi-Fi command functions on the Roav A1, the first parameter
$a0 is always the path provided by the user, with the current guess at the full prototype being:
wifiCmd(URLPath,QueryStr,POSTData,POSTDataLen,???,???). When utilizing the
XML_UploadFile command, the
URLPath of the HTTP request is passed into the function dubbed
fixup_path(src,dst) as the
src parameter. This function essentially just copies the data at
src to the buffer at
dst, as one would expect, but with the changes of prepending “A:,” and changing all forward slashes to backslashes. The relevant loop of the short function is:
ROM:80221BA0 addu $v0, $s1, $v0 ROM:80221BA4 li $a0, "/" ROM:80221BA8 li $a1, "\" ROM:80221BAC ROM:80221BAC loc_80221BAC: # CODE XREF: fixup_path+58↓j ROM:80221BAC beql $v1, $a0, loc_80221BB8 ROM:80221BB0 sb $a1, 0($v0) // ROM:80221BB4 sb $v1, 0($v0) // ROM:80221BB8 ROM:80221BB8 loc_80221BB8: # CODE XREF: fixup_path:loc_80221BAC↑j ROM:80221BB8 addiu $s0, 1 ROM:80221BBC lbu $v1, 0($s0) ROM:80221BC0 bnez $v1, loc_80221BAC // ROM:80221BC4 addiu $v0, 1
At  we see the char substitution, and at  where the non-slash characters are copied. Most importantly, at  we see a complete lack of bounds checking, and the function only returns upon finding a null byte.
The issue then lies in the exact type of buffer being filled. If we trace backward into the
XML_UploadFile function, we can see the following:
ROM:80221EA4 move $a0, $s5 // ROM:80221EA8 jal fixup_path # ROM:80221EAC move $a1, $s7
$s5 is the original HTTP
URLPath provided, and
$s7 is assigned to point to a size 0x80 buffer on the stack at:
ROM:80221EA0 addiu buff_0x80, $fp, 0xE8+Size_0x80_StackBuff
This allows an attacker to arbitrarily control code execution with a size 0x9E buffer, the last four bytes being the return address.
WifiCmd_DispatchCmd(): cmd:5001 evt:0 par:0 CB:80221be8 wait:0 WifiCmd_DispatchCmd(): ret 0 USB 1.5A CONNECT to CHARGER uiUsage=1 CHK: 2306, XML_UploadFile ERR:fs_interfopen() pathDeep:69(Limit:1~7), pathLeng:168(Limit:3~131) ERR:FileSys_SeekFile() pFile is NULL CHK: 2314, XML_UploadFile ERR:FileSys_SeekFile() pFile is NULL ERR:FST_CMDWriteFile() Invalid file handle 0x0 CHK: 2330, XML_UploadFile *** CPU Exception!!! cause 0x04: Address error exception (load or instruction fetch) epc - 0x39383736 $ra - 0x39383736 $sp - 0x80d424d0 $fp - 0x33333232 general registers: $zero : 0x00000000 $at : 0x00000008 $v0 : 0x00000000 $v1 : 0x0000000c $a0 : 0x806774c8 $a1 : 0xf0a3bde8 $a2 : 0xf0a3bde8 $a3 : 0x00000008 $t0 : 0x00000008 $t1 : 0x01010101 $t2 : 0x80d3ceb4 $t3 : 0x00000012 $t4 : 0x00000008 $t5 : 0x807d2bb4 $t6 : 0x00000017 $t7 : 0x00000002 $s0 : 0x61616161 $s1 : 0x61616161 $s2 : 0x62626261 $s3 : 0x62626262 $s4 : 0x63626262 $s5 : 0x64636363 $s6 : 0x65646464 $s7 : 0x32326565 $t8 : 0x80033e90 $t9 : 0x00003000 null : 0x5c5c5c5c null : 0x5c5c5c5c gp : 0x8060f540 sp : 0x80d424d0 fp : 0x33333232 ra : 0x39383736 co-processor registers: entrylo : 0x00000002 status : 0x00000010 vector : 0x0100c403 epc : 0x39383736 cause : 0x00000000 badvaddr : 0x10800010 hwrena : 0x39383736 prid : 0x00019655 entrylo : 0x01645792 Thread(id) : Hfs Session(260) stack : range(0x80d3ce94 - 0x80d42e94) call stack : : abort ($pc 39383736 is invalid address!) *** CPU Exception in Task! cause=0x00000004, addr=0x39383736
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.