Yi Technology Home Camera 27US CRCDec denial-of-service vulnerability


### Summary An exploitable code execution vulnerability exists in the UDP network functionality of Yi Home Camera 27US A specially crafted set of UDP packets can allocate unlimited memory, resulting in denial of service. An attacker can send a set of packets to trigger this vulnerability. ### Tested Versions Yi Technology Home Camera 27US ### Product URLs <https://www.yitechnology.com> ### CVSSv3 Score 7.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H ### CWE CWE-400: Uncontrolled Resource Consumption ### Details Yi Home Camera is an internet-of-things home camera sold globally. The 27US version is one of the newer models sold in the U.S., and is the most basic model out of the Yi Technology camera lineup. It still, however, includes all the functionality that one would expect from an IoT device such as the ability to view the video from anywhere, offline and subscription-based cloud storage, and ease of setup. When the Yi Camera communicates with the ‘Yi Home’ phone app, in order to provide video feeds and status updates, the network daemon in charge is the `p2p_tnp` binary. This daemon provides network discovery, authorization, and also settings manipulation functionality, all over UDP. The custom protocol handling this is rather simple to start, and a basic overview is given below: | Magic Byte | Opcode Byte | MsgLen Short | Message (max 0x500) | \xF1 | \x00-\xFF | <len of msg> | <msg> If the camera and the phone running the ‘Yi Home’ app are on the same subnet, a handshake occurs with the custom TNP protocol before any other operations can happen. The phone sends a `MSG_LAN_SEARCH` (\x30) packet to UDP port 31208, to which the phone will respond with an `MSG_LAN_NOTIFY` (\x31) packet from a new source port. It should be noted that this `MSG_LAN_SEARCH` can be sent to a broadcast address or a single IP address, and also that the `MSG_LAN_SEARCH` response contains the Device ID (DID) of the camera, which is needed to pass certain checks. A sample DID consists of a prefix, serial and suffix, for example: `TNPUSAC-112233-NMEDP`. After the initial packet exchange, the thread controlling this socket enters the `PPPP_thread_recv_Proto_device` function, which contains a jumptable for dealing with a subset of the possible `TNP` opcodes. Of interest for this bug is the `MSG_DEV_LGN_ACK_CRC` opcode, which seems to validate a response from remote servers by utilizing a complex CRC algorithm. Throughout testing, this message has not been seen naturally on the wire, so the theory is that this is artifact code that has not been removed. The relevant disassembly follows below: LDR R3, =0xFFFFF6C0 ADD R2, SP, #0x998+memcpy_base_ptr LDRH R1, [R2,R3] //[1] STR R1, [SP,#0x998+size_of_inp] ADD R11, R1, #4 MOV R0, R11 BL malloc LDR R1, [SP,#0x998+size_of_inp] MOV R3, R11 MOV R9, R0 MOV R2, R9 //[2] MOV R0, R10 BL tnp::PPPP_CRCDec //[3] At [1], the size of the input buffer data is taken and added to 0x4 before using that as the size of the input malloc buffer, which is stored into R2 eventually [2]. At 3, a call to `tnp::PPPP_CRCDec` is made, with the following approximation of parameters: tnp::PPPP_CRCDec(udpbuff, inp_malloc, inp_malloc_size, udpbuff_size, crc_IV) // udpbuff => data of our packet // udpbuff_size = inp_malloc_size + 0x4. // crc_IV => Empty. Once inside of `CRCDec`, a quick stub is called to load the `CRC_IV`, which doesn’t actually load anything, and then we step into the main body. To summarize the main functionality, it allocates a new buffer of size `size_of_inp` \- 0x4, does a bunch of CRC operations on our input buffer, and throws that into the buffer that was just allocated. Interestingly, approximately only the first 0xD0 bytes are actually CRC’d, the rest are just copied over from the UDP buffer to the malloc’d buffer. After this, the code walks backward from the end of the CRC’d bytes and replaces all “\x43”/”C” bytes with null bytes, until it hits the end of the buffer-4. If the function finds a byte that is not a “C”, the function returns an error, after freeing the inner buffer. If the function only finds “CCCC” however, the CRC’d data will be memcpy’d from the buffer malloc’d inside the CRCDec function to the buffer that was malloc’d and then passed in as the `inp_malloc` parameter. After this, the program will free the inner malloc buffer. When the `CRCDec` function returns, if the CRC checksum “CCCC” was not found and CRCDec returned an error, `PPPP_thread_recv_Proto_device` will just free the buffer allocated before `CRCDec`, and return to processing new packets: .text:00026EC4 MOV R0, R9 ; ptr .text:00026EC0 BL free .text:00026EC4 B loc_25B0C ; jumptable 00025BFC default case Unfortunately, if there was no error, the login status is updated, and nothing else really occurs. The buffer malloc’d before `CRCDec` is never freed, allowing an arbitrary amount of memory to be allocated by the `p2p_tnp process, causing quite a few unintended consequences. Depending on the amount of these packets sent, and also the size of the data allocated, different outcomes can be achieved by an unauthenticated attacker with network connectivity. For testing purposes, the following buffer was used: `”A”*0x4A0+”CCCC”. If one sends approximately 0xC00 packets, the device’s LED will eventually start blinking and the camera’s owners will no longer be able to reach the device from their Yi Home phone apps, even though it maintains network connectivity. The camera must then be physically rebooted in order to regain functionality. It is theorized that only the `tnp_p2p` service is crashing at this point, rendering the UDP network comms disabled. If one sends approximately 0x1000 packets, then the device LED also starts blinking, but this time, the `cloud`, `p2p_tnp`, `wpa_supplicant` and `udhcp` services all crash, causing a complete network disconnect. After a certain amount of time, the `dispatch` binary will realize that `wpa_supplicant` has crashed, and will promptly reboot the device. Thus, depending on the goals of the attacker, a camera reboot can also be propagated with this vulnerability. ### Timeline 2018-06-13 - Vendor disclosure 2018-09-03 - Vendor submitted build to Talos for testing 2018-09-05 - Talos confirmed issue patched 2018-10-22 - Vendor released new firmware 2018-10-31 - Public release