DJI Drone Vulnerability

Research by: Oded Vanun, Dikla Barda and Roman Zaikin

DJI is the world’s leader in the civilian drone and aerial imaging technology industry.

Besides from consumers, though, it has also taken a large share of the corporate market, with customers coming from the critical infrastructure, manufacturing, agricultural, construction, emergency-management sectors and more. With so many customers worldwide, both consumer and corporate, DJI drones can obtain data and images from a wide range of viewpoints and across a large spectrum of subject matter.

In a recent investigation, Check Point Research discovered a vulnerability that, if exploited, would grant an attacker access to a user’s DJI account without the user being aware of it. This could have provided access to:

  • Flight logs, photos and videos generated during drone flights, if a DJI user had synced them with DJI’s cloud servers. (Flight logs indicate the exact location of a drone during its entire flight, as well as previews of photos and videos taken during the flight.)
  • A live camera view and map view during drone flights, if a DJI user were using DJI’s FlightHub flight management software.
  • Information associated with a DJI user’s account, including user profile information.

The vulnerability was accessed through DJI Forum, an online forum DJI runs for discussions about its products. A user who logged into DJI Forum, then clicked a specially-planted malicious link, could have had his or her login credentials stolen to allow access to other DJI online assets:

  • DJI’s web platform (account, store, forum)
  • Cloud server data synced from DJI’s GO or GO 4 pilot apps
  • DJI’s FlightHub (centralized drone operations management platform)

We notified DJI about this vulnerability in March 2018 and DJI responded responsibly. The vulnerability has since been patched. DJI classified this vulnerability as high risk but low probability, and indicated there is no evidence this vulnerability was ever exploited by anyone other than Check Point researchers.

Diagram: A simplified view of the three potential attack flows.

A Demo Video of the Attack
(Please note: screenshots of flight paths and images seen in this video or above diagram were taken with thanks to Airdata, who was not involved in this research and was not affected by this vulnerability.)

 

Technical Analysis

Our research below explains how we were able to gain access to sensitive DJI drone flight information, as well as sensitive user data, across all three DJI platforms of Website, Mobile App and FlightHub.

First, though, we will explain where the vulnerability resides and how it works.

 

The Vulnerability

In brief, the vulnerability resides in the DJI identification process.

DJI uses a cookie that the attacker can obtain to identify a user and create tokens, or tickets, to access their platforms. Through the use of this cookie, an attacker is able to simply hijack any user’s account and take complete control over any of the user’s DJI Mobile Apps, Web Account or DJI FlightHub account.

We started our research by investigating the login process of the DJI website as we first wanted to understand how a user is identified by the DJI back-end and which parameters or cookies are important to the login process. So we took a look at all the traffic going through the client (browser) and the DJI backend.

We soon noticed that DJI uses a few sub-domains for the services that it offers:

  • forum.dji.com
  • account.dji.com
  • store.dji.com

In addition, the login between these domains uses the OAuth framework. As a result, we started to examine the traffic across these sub-domains.

From our analysis, we found that a request to the mobile.php URL gave us sensitive information about our DJI test user that contained data such as username, member_uid, token and much more.

This was interesting as it prompted us to investigate how the DJI backend identified our user and whether it used the same identifier ID. So we looked at the cookies used there and found that one cookie in particular, named ‘meta-key’, was the one responsible for user identification.

Figure 1: The mobile.php request

 

As our goal was now to get this ‘meta-key’ cookie by any means possible we had to find a sub-domain unprotected by an http-only attribute, for this would prevent JavaScript from leaking the cookie.

The sub-domain that suited our needs was forum.dji.com, so we started to look for vulnerabilities in this platform.

 

Discovering the Vulnerability

After a little searching around, we stumbled upon the following GET request: https://forum.dji.com/forum.php?mod=ajax&action=downremoteimg&message=

Here we saw that the message parameter was reflected in the response. But there were two obstacles:

  1. There was the “addslashes” function which adds a slash to the following characters ” ‘ /
  2. The XSS payload injection occurred in an undefined function called “updateDownImageList” which was imported from some other JavaScript code that we did not have in our context.

We assumed that the response to our GET request looked something like the following pseudo code:

So, to begin with the function escape we started with a backslash and a single quote like this:

parent.updateDownImageList(‘ \’ ‘);

Then “addslahes”  would also add a backslash which would escape our backslash and change it to a string like this:

parent.updateDownImageList(‘ \\ ‘  ‘);

So we then now had to deal with the remaining characters ‘); and the unidentified function, “updateDownImageList”.

To deal with the remaining characters we added a simple html comment like this <!– which created the following payload:

parent.updateDownImageList(‘ \'<!–  ‘);

Now all we had left was to deal with the unidentified function. In order to overcome the fact that this function was undefined we had to define it by ourselves.

So, our payload eventually looked like this:

\’ alert(document.cookie); function updateDownImageList (data) {} <!– 

Figure 3: Cookies we received by using our payload.

An attacker could then create a payload that would send that meta-key cookie to his website. This kind of XSS would not be blocked by any XSS Auditor because it resides in the JavaScript itself and not consist of scripts or events.

To trigger this XSS attack all the attacker need do is to write a simple post in the DJI forum which would contain the link to the payload. After all, DJI limits links to content that reside in the forum itself and so in this way it is impossible to send a link to a malicious website.

Figure 4: Example of malicious site linked to by a post from a potential attacker in the DJI forum.

As our XSS resides in the forum itself we were able to bypass the link restriction. Furthermore, as there are hundreds of thousands of users communicating DJI’s forum the attacker would not even need to share the malicious link as this would be done by the users themselves as they forward on the message and link.

After we acquired the meta-key we moved on to examine the login process and tested how the DJI backend processes the login in each DJI platform, starting with the DJI website.

 

DJI Website

To gain access to any user’s account on the DJI website all we needed was their “meta-key”, which is called “mck” on the sub-domain, account.dji.com.

We started by creating a DJI account and logging into it. By analyzing the login process, we found that it uses OAuth to authenticate the user between subdomains, for example between accounts.dji.com to forum.dji.com and back to dji.com.

So, every time DJI wants to authenticate a user it sends initData.do with a “mck” cookie and the response will be callback url with a ticket.

By navigating to the url the user will thus be authenticated without credentials.

So, in order to hijack an account, we needed to:

  1. Login as an attacker to dji.com, then click on DJI.COM which will redirect us to dji.com.
  2. In the initData.do request, replace the “mck” cookie value with the victim’s “mck”(which we obtained from the XSS vulnerability).
  3. Continue with the login process and access the victim’s account.

Below is the initData.do request:

Figure 5: initData.do Request

 

The DJI App

In order to hijack an account in a DJI mobile application, we had to bypass some mitigations that where implemented in the application itself.

We had to intercept the requests going from the application to the DJI backend in order to investigate the login process. But here we encountered an SSL pining mechanism, which prevented us from intercepting application traffic and investigating it.

So we tried to decompile the application to understand how to bypass the SSL pining mechanism. Unfortunately, decompliation did not succeed because DJI’s mobile app uses SecNeo (a Mobile App security company) protection.

According to SecNeo the following protections are provided:

  • Source code reversing prevention and sensitive data protection.
  • App tampering, repacking and debugging prevention with anti-hooking features.
  • Dynamic code injection and decompilation/disassembly preventions.

As a result, we tried to bypass these limitations by using Frida. In fact, we tried to attach to the dji.go.v4 application but without any success.

We then check why we could not attach to the dji.go.v4 process and started with the command: ‘frida-ps –U’ to get a list of all processes running on our mobile device.

Upon running this command we noticed there was only one dji.go.v4 process. However, after a few seconds we saw another dji.go.v4 process appeared.

By looking at /proc/11194/status we can see that the new spawned process is attached to the first process and actually debugging it. This is why we couldn’t debug the process with Frida – its already being debugged.

Figure 6: The newly spawned process attached to the first dji.go.v4 process as seen in Frida.

We found that the first process that started is not the debugger but rather the actual application. The debugger had actually attached to the real application and started protecting it. This meant there was a race condition that we could exploit and attach our hooks to the application process and detach it before the debugger process is started.

In order to bypass this, we copied our Burp Suit certificate to the mobile phone and spawned the DJI application ourselves. This started the application in suspended mode (before the debugger initialized).

Then we created a Frida script that used the following logic:

  1. Open our Burp Suit Certificate and cast it to X509Certificate.
  2. Load a KeyStore and put the certificate inside.
  3. Create TrustManagerFactory and initialize it with the KeyStore we just created that contains our Burp Suit certificate.
  4. Overload the SSLContext and hook the TrustManager with our TrustManager.

After the hook was complete, we resumed the suspended application and detached from it. Now the debugger could start its protection after we had finished with all our hooks.

In this way we bypassed the SSL pinning and the traffic then appeared in our Burp Suit.

Figure 7: The traffic as seen in Burp Suit after bypassing the SSL pinning.

After bypassing the SSL pining, we then set up a proxy which allowed us to intercept the Mobile application traffic.

By analyzing the web application’s login process we found that once the user inserts his credentials the mobile application sends a request to /apis/apprest/v1/email_login. The response received looks like this:

{“code”:0,”message”:”ok”,”data”:{“nick_name”:”XXXXXXXXX”,”cookie_name”:”_meta_key”,”cookie_key“:”NTUxNjM2ZTXXXXXXXXXXXXXXNmI2NjhmYTQ5NGMz“,”active”:false,”email”:”XXXXXXXX@gmail.com”,”token“:”XXXXXXXXX2139“,”validity”:15275XXXXX,”user_id”:”9629807625XXXXXX”,”register_phone”:””,”area_code”:””,”inner_email”:false,”subscription”:false,”vipLevel”:null,”vipInfos”:[]}}

 

The two important parameters to notice here are:

  • “cookie_key” – This is the meta-key/mck that we are by now already familiar with from the DJI forum.
  • “token” – This parameter we can get from the request mobile.php which we described at the beginning of this research publication.

 

The Account Hijack Process

The process to hijack an account is:

  1. First the attacker needs a meta-key and a token to replace with their own. So he sends the meta-key he wants to hack to mobile.php and receives a corresponding token.
  2. The attacker then enters his credentials and a login request is sent.
  3. Once a response from Step 2 is received, the attacker replaces the cookie_key value with the victim’s meta-key and his token with the token from Step 1.
  4. The attacker now has full access to the victim’s account.

By exploiting the DJI vulnerability, as described above, the attacker could take over the victim’s account and gain access to all of their synced recorded flights, drone photos, and more.

We also carried out further research and found that by parsing flight logs files we can get much more information such as location and angle of every picture taken during the drone’s flight, the drone’s home location, last known location and more.

In order to get access to the flight log files, all the attacker need do is synchronize the flight records with his phone and all flight logs which had been manually uploaded to DJI cloud servers would be saved locally on his phone. He can then simply browse to the folder ‘DJI/dji.go.v4/FlightRecord’ and find all the flight’s files, upload them to the site and view a large amount of information about the user’s flight data.

(Please note: the screenshots of flight paths and images above were taken with thanks to Airdata, who was not involved in this research and was not affected by this vulnerability.)

DJI-FlightHub

DJI-FlightHub is a web-based application developed to give enterprise users complete visuals and management over the operations of their drones. In fact, it allows users to view their drone operation in real-time from anywhere in the world by including a map view, a live camera view with the ability to hear sound and allow users to see the exact location of each of their drones in order to coordinate missions.

DJI-FlightHub has a desktop application to access the management control panel, a pilot application to fly the drone, and, luckily for us, a web portal to access the management control. The web portal can be found at the following URL : www.dji-flighthub.com.

In DJI-FlightHub there is an admin, captain and a pilot. Admins are in charge of the DJI-FlightHub account and access the DJI-FlightHub platform, view flight data, and create new captains or pilots. Captains can also login to the DJI-FlightHub platform and create new pilots. Pilots are the ones flying the drone with the pilot apps and bind the drone to the DJI-FlightHub account.

With this in mind, if we could gain access to the admin or captain account we would be able to view a drone’s operations in real time.  In order to hijack a DJI account of an Administrator or Captain, we needed to understand DJI-FlightHub’s login process.

Figure 8: The DJI-FlightHub Login page.

We found that when you click on ‘login’ an initData.do request is sent, but in the response a ticket is not received (similar to what we received in the account.dji.com portal). Instead, we only received a ticket in the login.do response when the user enters his credentials. As this is not the same as the regular account.dji.com that we used to hijack an account through the web portal, we had to think of another way to hijack an account in DJI-FlightHub.

Although we knew that a ticket can be generated by the initData.do request, for some reason this was not the case in DJI-FlightHub. So we looked at the request to understand why and notice that in DJI-FlightHub the initData.do request has an appId of DJI-FlightHub, which is why we didn’t get a ticket in the response. With this in mind, we thought we could perhaps replace the appId  to  something we knew could work in order to get a ticket. Once a ticket was received all we now had to do is check if the ticket of another appid would also work here.

The steps needed be taken then were:

  1. Send an initdata.do request of appId=store with the mck of the Admin aiming to be hijacked and acquire a ticket in the response.
  2. When logging in to FlightHub, intercept the request, change the mck in the login.do request and in the response switch to the corresponding ticket received in the inidata.do request. The attacker will then be redirected to the admin/victim’s account.

In addition, the admin would not receive any notification that an attacker has accessed their account. Meanwhile, the attacker would have completely uninhibited access to login and view the drone’s camera during live operations of any flights currently in progress, or download records of previously recorded flights that had been uploaded to the FlightHub platform.