As part of quality assurance, the research team regularly collects random firmware from the Internet and performs “triage” on firmware analysis executed by the ONEKEY platform to validate results and identify potential areas of improvement for our analysis capabilities. This process is comparable to a risk assessment of firmware of ICT products that any organization in scope of the Digital Operational Resilience Act (DORA) or the new Network and Information Security (NIS2) Directive is obliged to conduct to manage supply chain risks.

In some rare occasions, we end up looking at really weird bugs that we can’t really trace back to their root cause.

Recent examples include an object symbol referencing a string that started with a null byte, and a function symbol referencing a Thumb-2 function with an address without the LSB set (this means that if a binary would have imported that library and called that specific function, it would have crashed).

We’re in a peculiar position where we can see the effects of the bugs but cannot trace them back to their origins since we don’t have access to the build toolchain, or the source code to reproduce these unique bugs affecting what I personally call “transient dependencies” (e.g., compilers, linkers, builders).

On top of those toolchain bugs with observable effects, the platform can report vulnerabilities affecting binaries that have no legitimate reasons to be there. This is the story of our investigation into xftp, a binary that has nothing to do in Dahua firmwares.


Initially, the ONEKEY Product Cybersecurity & Compliance Platform automatically reported a command injection vulnerability affecting the xftp binary:

The service starts by opening a socket a TCP socket on IPv4 or IPv6 depending on the command line argument provided (-v4 or -v6) and binding it to port 19365. All of this is performed in function xftp_server_start.

Once the socket is opened and bound, the binary calls xftp_server_rec, providing the socket as argument:

socket = xftp_server_start(socket);
if (-1 < socket) {
    do {
        iVar10 = xftp_server_recv(socket);
        if (iVar10 < 0) {
            puts("server recv failed. ");
    } while( true );

The xftp_server_recv launch a busy loop with accept, waiting for incoming network connection. When a connection is established, the server calls xftp_recv:

while (sockfd_00 = accept(sockfd,(sockaddr *)0x0,(socklen_t *)0x0), sockfd_00 < 0) {
iVar1 = xftp_recv(sockfd_00, &buffer, &bufsize, &type);

The function reads a XFTP packet from the network. These packets have the following header structure:

typedef struct xftp_pktheader {
    int pkttype;
    int datalen;

So, the function reads 8 bytes from the socket to obtain the packet header. Then it performs an allocation according to datalen and reads datalen bytes from the socket.

int xftp_recv(int sockfd,char **buffer,int *bufsize,int *type) {
    int read;
    char* buf;

    read = recv(sockfd, &pktheader, 8, 0);
    buf = malloc(pktheader.datalen);
    read = recv(sockfd, buf, pktheader.datalen, 0);
    *type = pktheader.pkttype;
    *buffer = buf;
    *bufsize = pktheader.datalen;

Then, back in xftp_server_recv, if the type is 1 the binary will parse a null separated packet holding a filename, a status, and the file content. It will write the file content on disk using xftp_filewrite. If the status is set to TRUE, then the file execute permissions are set using chmod and the file is executed:

uint length;
int index;
char strcmd[512];
if ( type == 1) {
    // parsing of null separated packet holding filename, status, and file content
    char* filename;
    char* status;
    char* content;
    int content_length;
    iVar2 = xftp_writefile(filename, content, content_length);
    if(index_2 > 0) {
      if (strcmp("TRUE", status) == 0) {
        strcmd = "chmod +x";
        length = strlen(filename);
        strncpy(strcmd + 9, filename, length); // NOTE: potential stack buffer overflow through filename value
        length = strlen(filename);
        strcmd[length + 9] = '\0';
        iVar1 = system(strcmd); // NOTE: command injection through filename
        iVar1 = system(filename); // NOTE: command injection through filename
      // snip
      return 0;

By sending a request to the xftp server, a remote unauthenticated attacker can get the device to execute arbitrary code. Either by submitting its own code through the file content or by injecting commands through filename. The potential stack overflow is not exploitable since the strcmd buffer is 512 bytes long and the maximum allowed size for a filename on UNIX is 256 bytes.


All good, the vulns seems valid. However, something caught our attention. The binary is built for AARCH64:

But the whole firmware is built for ARM32 devices. Both the kernel and binaries (e.g., busybox) are built for ARM 32bit:

We looked around and found no indication that this binary is actually used. It’s referenced in the SigFileList, which means Dahua is aware of this binary and that it’s been explicitly packaged in the firmware.

Hunting for XFTP

We searched for the presence of XFTP in our firmware corpus and spotted it in other Dahua firmwares, including occurrences of ARM32 XFTP binaries in ARM32 firmwares:

   "arch" : "ARM",
   "bits" : "32",
   "fwid" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
   "machine" : "32",
   "magic" : "ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/, with debug_info, not stripped",
   "magic_mime" : "application/x-executable",
   "path" : "/_DH_IPC-HX8XXX-Nova_Eng_P_Stream3_V2.600.0000.14.R.20170830.bin.extracted/_romfs-x.squashfs.img.extracted/squashfs-root/usr/bin/xftp",
   "static" : "0",
   "stripped" : "0",
   "symlink" : "False",
   "type" : "ELF"

The binaries are never stripped and always hold debug info. Initially, we suspected that we had uncovered a hidden backdoor that could be activated when needed. However, after examining each firmware for signs of active use, we found none. Our hypothesis is that Dahua is probably shipping xftp within most of its firmware releases for security cameras, at the very least for its PFR5QI-E60 and IPC-HX8XXX product lines. We still have no idea why though.


Even if the binary itself is not launched, we still wanted to let Dahua know that they are releasing firmwares for ARM32 devices with vulnerable AARCH64 binaries in them. Our hope was that they would share some information on how and why it came to be. We were also curious about the exact purpose of xftp since it’s not referenced anywhere in Dahua administration guides.

We reached out to on multiple occasions since February 14th 2024, providing detailed information. We never heard back from them.

Key Takeaways

The fact that Dahua is releasing firmwares for ARM32 devices with vulnerable AARCH64 binaries in them should give their customers a few qualms about the trust they can put in their build pipeline.

With all that said, it’s just another occurrence of what we consider “unwanted software”. Any software that the device does not need under normal operation but that help attackers during research or once the device is compromised (e.g., tcpdump, gdb, netcat). These unwanted softwares are reported by the platform, and xftp will be added to the list so that our customers are aware of its existence.

Fundamentally, xftp is implementing a custom protocol layer over plain FTP allowing clients to perform upload-and-execute requests. An excellent C2 mechanism that, if you did not know about it, would probably not spot within network traces.