本文翻译自:https://research.checkpoint.com/dji-drone-vulnerability/
最近Check Point研究人员发现大疆无人机漏洞。漏洞如果被利用,攻击者就会被授予访问用户DJI账户的权限。
漏洞是通过DJI论坛访问产生的,论坛主要讨论大疆的产品。当用户登陆DJI论坛,点击刻意植入的而已链接时,攻击者就可以获取其登陆凭证,并访问其他DJI在线资产,包括:
2018年3月,研究人员将该漏洞通报给了大疆,大疆对该漏洞进行了修复。大疆对该漏洞的评级为high risk
和low probability
。也就是说该来的被利用的可能性小。
攻击流图
下面解释如何获取DJI web平台、手机APP和FlightHub的敏感飞行数据、敏感用户数据的访问权限。
该漏洞位于DJI身份识别过程中。
DJI用cookie来识别用户和创建token/tickets
来访问平台,而cookie是攻击者可以获取的。通过使用cookie,攻击者可以劫持任意用户的账户,并完全控制用户的DJI Mobile Apps, Web账户或DJI FlightHub账户。
首先看一些DJI网站登录过程来了解DJI后台是如何识别用户,以及那些参数和cookie对登陆过程非常重要。研究人员分析了客户端与DJI后台的流量。
研究人员注意到DJI对以下子域名使用了该服务:
这些域名之间的登陆使用的是OAuth框架。
研究人员分析发现到URL mobile.php的请求暴露了用户账户的敏感信息,包括username, member_uid, token
等。然后研究人员发现这里用来进行用户识别的cookie是meta-key
。
图1: mobile.php请求
研究人员的目标是获取meta-key
cookie,因此必须要找到没有被http-only
保护的子域名,因为http-only
会防止JS泄露cookie。满足这一要求的域名是forum.dji.com,然后研究人员开始寻找和分析平台的漏洞。
研究人员发现了这样的请求:
https://forum.dji.com/forum.php?mod=ajax&action=downremoteimg&message=
响应中反映出了消息参数,但是有两个困难:
Addslashes
函数为字符串” ‘ /
增加了“斜杠”;updateDownImageList
中存在XSS payload注入。研究人员认为GET请求的response比较像下面的伪代码:
首先,用后斜杠和单引号来进行函数逃逸:
parent.updateDownImageList(‘ \’ ‘);
然后addslashes
会增加一个后斜杠,使后斜杠逃逸,并修改为这样的字符串:
parent.updateDownImageList(‘ \\ ‘ ‘);
然后处理剩下的字符‘)
和未定义的函数updateDownImageList
。
研究人员加入了一个简单的HTML注释<!–
,创建了下面的payload:
parent.updateDownImageList(‘ \'<!– ‘);
为了处理未定义的函数,需要做的就是自己定义该函数。
最终的payload为:
\’ alert(document.cookie); function updateDownImageList (data) {} <!–
图3: 使用payload获取的cookie
攻击者可以创建一个发送meta-key
cookie到网站的payload。这类XSS并不会被XSS过滤器过滤,因为不含有任何脚本或事件。
为了触发XSS攻击,攻击者需要做的就是在DJI论坛上发布一个帖子,帖子中需要包含一个链接到payload的链接。因为DJI会限制链接到论坛的内容,所以不能发送这样的链接到恶意站点。
图4: 链接到恶意网站的内容
因为XSS在论坛内,所以可以绕过对链接的限制。而且有成千上万的用户在DJI论坛上交流,因此用户会自己转发消息和链接,不需要用户分析恶意链接。在获取meta-key
后,就可以进行登陆测试DJI后台处理登陆的过程。
为了获取DJI网站用户账户的访问权限,就需要其meta-key,也就是子域名account.dji.com中的mck。首先创建DJI账户并登陆,通过分析登陆过程,研究人员发现后台使用OAuth来认证用户和子域名,比如从accounts.dji.com到forum.dji.com,再到dji.com。
每次DJI要认证用户的时候,就发送含有mck
cookie的initData.do
,然后响应就是一个含有ticket
的回调URL。通过导航到该url就可以在没有凭证的情况下认证用户。
因此,为了达到劫持账户的目的,需要:
mck
替换initData.do
请求中的mck
cookie值;下面是initData.do
请求:
图5: initData.do请求
要劫持DJI手机应用的账户,就需要绕过应用中实现的所有缓解措施:
拦截应用和DJI后台的请求数据来分析登陆过程。但研究人员发现应用使用了SSL校验证书绑定(ssl pinning) 技术,这妨碍了研究人员拦截应用流量和分析。因此,研究人员反编译了应用来找出如何绕过SSL pinning机制。但DJI手机应用使用了SecNeo保护,因此反编译过程也失败了。
SecNeo提供了以下保护:
了解了这些之后,研究人员决定使用Frida来绕过这些限制。事实上,研究人员在添加dji.go.v4应用时失败了。然后研究人员分析了添加失败的原因,并用frida-ps –U
命令来获取运行的所有进程列表。
运行该命令后,研究人员注意到只有一个dji.go.v4进程,过了几秒钟后,出现了另外一个dji.go.v4进程。
通过查看/proc/11194/status
,研究人员发现新出现的进程与第一个进程是有关联的,实际上是在调试这也就是为什么不能用Frida进行调试了,因为已经在调试了。
图6: 新创建的进程在Frida中与第一个dji.go.v4进程关联
研究人员发现第一个开启的进程并不是调试器,而是真实的应用。调试器并没有与真实应用相关联,这也就是说这里存在一个可以利用的竞争条件。
为了实现绕过,首先复制Burp Suit证书到手机APP,并复制DJI应用。这会开始处于挂起模式的应用。然后用以下逻辑创建一个Frida脚本:
Hook完成后,研究人员恢复挂起的应用。调试器在完成hook后就可以开始保护了。这样研究人员就成功地绕过了SSL pinning,在Burp Suit中就可以看到拦截的流量了。
图7: 绕过SSL pinning后在Burp Suit看到的流量
绕过SSL pining后,研究人员建立了一个拦截手机应用流量的代理。
在分析了web应用登陆过程后,研究人员发现用户插入凭证后,手机应用就会发送请求到/apis/apprest/v1/email_login
。接收到的响应如下:
{“code”:0,”message”:”ok”,”data”:{“nick_name”:”XXXXXXXXX”,”cookie_name”:”_meta_key”,”cookie_key“:”NTUxNjM2ZTXXXXXXXXXXXXXXNmI2NjhmYTQ5NGMz“,”active”:false,”email”:”[email protected]”,”token“:”XXXXXXXXX2139“,”validity”:15275XXXXX,”user_id”:”9629807625XXXXXX”,”register_phone”:””,”area_code”:””,”inner_email”:false,”subscription”:false,”vipLevel”:null,”vipInfos”:[]}}
`
这里有两个重要的参数:
meta-key/mck
。mobile.php
中获取的参数。劫持账户的过程如下:
meta-key
和token
来进行替换。所以需要发送meta-key
来黑掉mobile.php
并接收对应的token;利用DJI漏洞,攻击者可以获取受害者账户的完全访问权限,还可以访问同步的飞行记录、无人机拍摄的照片等信息。
为了访问飞行日志文件,攻击者需要用手机同步飞行记录,因为所有的飞行记录都手动上传到DJI云服务器了。然后浏览·DJI/dji.go.v4/FlightRecord·就可以看到飞行相关的文件,和相关的用户飞行数据。
DJI-FlightHub是一个web端的应用程序,可以帮助企业用户对无人机进行管理。DJI-FlightHub允许实时查看无人机的飞行状况,包括飞行地图、实时摄像头画面、以及无人机的准确位置信息等。
DJI-FlightHub有一个桌面应用程序来访问管理控制面板,该web门户位于www.dji-flighthub.com
。
在DJI-FlightHub中,一共有三个角色,分别是admin, captain和pilot。
也就是说,如果获取了admin或captain账户的访问权限,就可以查看无人机的实时操作和状态。为了劫持DJI的admin或captain账户,需要了解DJI-FlightHub的登陆过程。
图8: DJI-FlightHub登陆页面
研究人员发现点击login,会发送一个initData.do
请求,但是响应中并没有ticket
。当用户输入凭证时,只接收到login.do
响应的ticket
。这也之前通过web门户劫持account.dji.com
是不同的,因此需要重新考虑如何劫持DJI-FlightHub账户。
研究人员发现DJI-FlightHub的initData.do
请求中有一个DJI-FlightHub的appid
,这就是为什么在响应中没有获得ticket
的原因。因此研究人员替换了appid
来获取ticket
。接收到ticket
后,需要做的就是确定另一个appid
的ticket
在这里是否适用。
步骤如下:
appId=store
和Admin的mck
的initdata.do
请求,获取响应中的ticket
;login.do
请求中的mck
和对应的inidata.do
响应响应中的ticket
。然后攻击者会重定向到管理员或受害者账户。另外,admin不会接收到任何攻击者访问账户的通知。攻击者可以访问飞行数据,下载之前上传到FlightHub平台的飞行记录等。