硬件安全 · 2022年8月31日 0

SP605 DMA攻击复现

基于Xilinx SP605开发板的DMA攻击工具环境搭建及工具使用过程。

# 开发板基本组成

入门手册见:https://docs.xilinx.com/v/u/en-US/ug525

完整用户手册见:https://www.xilinx.com/support/documentation/boards_and_kits/ug526.pdf

完整组成为:

image-20220901093036165

我们需要关注的几个组件:

image-20220901093052106

SPI接口

SP605开发板搭载一个SPI接口,可通过连接JTAG接口,用Xilinx iMPACT配置工具进行固件读写。具体配置方式见:

https://www.xilinx.com/support/documents/boards_and_kits/sp605_PCIe_Gen1_x1_pdf_xtp065_13.4.pdf

外接编程器编程方法

其存储芯片为Winbond W25Q64BVSFIG,下面是SP605上的SPI引脚定义:

image-20220901093003624

根据用户指南,要使用外部SPI跳线J17来编程SPI芯片的话,需要安装J46跳线:

image-20220920111258556

安装下面红框中的跳线:

image-20220920155546198

连接J17引脚(除VCC外)和编程器,使用开发板本身供电:image-20230113150445398

用编程器直接烧录s6_pcie_microblaze.bin内容。

USB-to-UART接口

开发板包含一个Silicon Labs CP2103GM USB-to-UART bridge(U4)设备,可以通过USB线连接到主机进行调试输出。

image-20220901092936948

LED指示灯

LED灯定义表如下:

image-20220901092928938

ISE安装

安装Xilinx ISE 14.7版本,下载地址:https://china.xilinx.com/support/download/index.html/content/xilinx/zh/downloadNav/vivado-design-tools/archive-ise.html

image-20220901105504746

下载解压完成后运行xsetup.exe进行安装。

如果选择的是Win10版本,将会安装虚拟机,在虚拟机中运行ISE。

安装完成后,运行桌面的Project Navigator即可运行:

image-20220901111946511

虚拟机默认用户ise,密码xilinx

安装时可以选择共享文件夹,也可以安装完成后安装VBox的增强功能,运行./autorun.sh脚本:

image-20220901113129671

安装完成后重启虚拟机即可在设备->菜单下设置共享文件夹、拖放文件、共享粘贴板功能了。

安装License,打开Project Navigator,选择Help->Manage License...

image-20220901113426994

Load License...,选择xilinx ise 14.7 license.lic文件即可激活许可证:

image-20220901114016266

激活完成后即可打开项目进行编写了:

image-20220906091658747

项目编译

在Start界面点击Open Project...,选择s6_pcie_microblaze.xise文件来打开项目。

  1. 重新生成s6_pcie_v2_4fifo_generator_v8_4的IP核:

打开项目后,在Design界面下双击fifo_generator_v8_4

image-20220906092706985

弹出Fifo生成器,点击Generate生成即可:

image-20220906092821022

同样,双击s6_pcie_v2_4重新生成IP核:

image-20220906093107360
  1. 选择microblaze_top下的microblaze_i实例,然后双击运行Export Hardware Design To SDK with Bitstream
image-20220906093501237

如出现以下错误:

image-20220906100038459

TODO 解决此处错误

命令行输入下面的命令:

cd ./s6_pcie_microblaze-master/ipcore_dir/s6_pcie_v2_4/s6_pcie_v2_4/implement
./implement.sh > implement.log 2>&1

该脚本会在目录下生成一系列编译文件:

image-20220920154049156

iMPACT配置工具写入固件

用USB线连接USB JTAG接口和工作机:

image-20220901093009119

要从板载SPI闪存芯片加载比特流,需要把SW1开关设置为1-ON2-OFF,S1设置为0000:

image-20220920144838507

J46跳线需要设置:

打开iMPACT程序,创建一个新项目:

image-20220920145250953

选择Prepare a PROM File:

image-20220920145321583

点ok进入下一步,设置PROM文件格式,第一步选择SPI Flash – Configure Single FPGA,然后点绿箭头进入下一步,Storage Device(bits)选择64M,点击Add Storage Device,然后下一步选择输出文件名和输出文件夹,点OK完成配置:

image-20220920151015447

要求添加设备,选择刚刚编译生成的./s6_pcie_microblaze-master/ipcore_dir/s6_pcie_v2_4/s6_pcie_v2_4/implement/results/routed.bit文件:

image-20220920154229425

点击菜单的Operations -> Generate File… 生成mcs文件:

image-20220920154602574

生成完成后双击Boundary Scan:

image-20220920154647337

菜单选择File->Initialize Chain:

image-20220920154728814

右键点”SPI/BPI?”,点Add SPI/BPI Flash:

image-20220920155005409

选择生成的mcs文件:

image-20220920155110117

选择SPI PROM、W25Q64BV/CV、Data Width: 4

image-20220920154915767

右键flash图标,点Program:

image-20220920155301967

编程选项不用改,直接默认配置:

image-20220920154929950

等待编程完成:

image-20220920155456513
image-20220920161131178

写入SPI Flash的比特流文件包括为MicroBlaze core定制的bootloader,这个bootloader可以配置板子的选项,可通过UART接口将main程序写入linear flash中。

下面是将main程序写入linear flash的方法:

  1. 板子连接上电源,按住SW4按钮,并打开SW2电源开关,等待DS6 LED灯亮起后松开SW4按钮,进入更新模式。
  2. 将USB线连接到UART接口,输入下面的命令:
# sudo pip install pyserial
# sudo python2 ./python/bootloader_ctl.py /dev/ttyUSB0 --flash sdk/main_0/Debug/main_0.srec

[+] Opening device "/dev/ttyUSB0"...
[+] Flasing 447284 bytes from "sdk/main_0/Debug/main_0.srec"...
Erasing flash...
Writing 0x100 bytes at 0x00100000
Writing 0x100 bytes at 0x00100100
Writing 0x100 bytes at 0x00100200
Writing 0x100 bytes at 0x00100300
Writing 0x100 bytes at 0x00100400
Writing 0x100 bytes at 0x00100500
Writing 0x100 bytes at 0x00100600
...
Writing 0x100 bytes at 0x0016d000
Writing 0x100 bytes at 0x0016d100
Writing 0x100 bytes at 0x0016d200
Writing 0x34 bytes at 0x0016d300
[+] DONE
  1. 使用下面的命令设置IP:
# sudo python2 ./python/bootloader_ctl.py /dev/ttyUSB0 --config 192.168.2.247:255.255.255.0:192.168.2.1:28472

[+] Opening device "/dev/ttyUSB0"...
[+] Updating board settings...

Address: 192.168.2.247
Netmask: 255.255.255.0
Gateway: 192.168.2.1
  Port: 28472

Erasing flash...
Writing 0x12 bytes at 0x00000000
[+] DONE
  1. 网线连接攻击机和开发板,退出更新模式,从linear flash中启动mian MicroBlaze程序:
# sudo python2 ./python/bootloader_ctl.py /dev/ttyUSB0 --boot
[+] Opening device "/dev/ttyUSB0"...
[+] Exitting from update mode...

SREC Bootloader
Loading SREC image from flash at address: 42000000
Executing program starting at address: 00000000
main()
Loading settings from flash...
[+] Address: 192.168.2.247
[+] Netmask: 255.255.255.0
[+] Gateway: 192.168.2.1
auto-negotiated link speed: 100
Option ROM support is present
Initializing DMA...
Initializing interrupts...
start_application(): TCP server is started at port 28472
  1. 将SP605插入目标机的PCI-E插槽,打开开发板电源开关,待DS5 LED灯亮起后打开目标机电源,可以看到DS3、DS4 LED灯亮起,说明PCI-E成功连接:image-20230113153205223
  2. 目标机上运行lspci命令,可以看到Xilinx PCI-E设备:
image-20220920173019181

开发工具包使用

基本使用

安装依赖:python2 -m pip install pefile

在攻击机上配置python\pcie_lib_config.py文件中的IP和端口,与上述更新模式中配置的IP一致即可:


DEVICE_TYPE_TCP             = 1
DEVICE_TYPE_SERIAL         = 2
DEVICE_TYPE_UIO             = 3
DEVICE_TYPE_DRIVER         = 4
DEVICE_TYPE_DRIVER_DIRECT   = 5

class Conf:

   device_type = DEVICE_TYPE_TCP

   #
   # DEVICE_TYPE_SERIAL options
   #

   # serial port device
   device = '/dev/ttyUSB0'

   # serial port baudrate
   baud = 115200

   #
   # DEVICE_TYPE_TCP options
   #

   # board IP address and port
   addr = ( '192.168.2.247', 28472 )

#
# EoF
#

工具包提供两个环境变量可覆盖某些选项的默认值:

DEBUG_TLP : 设置为1,则打印TX、RX TLP数据包到屏幕输出中
TARGET_ADDR: <ip addr>:<port>,该环境变量可覆盖pcie_lib_config.py文件中的配置

攻击机上运行命令python2 pcie_cfg.py,可查看PCI-E设备的配置空间寄存器:

image-20230113153840172

使用pcie_mem.py程序可读取目标机的物理内存,下例为从0x0地址开始,读取0x80个字节的物理内存:

DEBUG_TLP=1 python2 pcie_mem.py 0x0 0x80
image-20230113154101135

也可将物理内存转储到文件中:

python2 pcie_mem.py 0x18000000 0x200 dump.bin
image-20230113154322267

DMA预引导攻击

uefi_backdoor_simple.pyuefi_backdoor_hv.pyuefi_backdoor_boot.pyuefi_backdoor_boot_shell.py支持两种不同的方式来传递执行到注入的UEFI DXE驱动镜像:

  • EFI_SYSTEM_TABLE劫持 – 从物理地址0xF0000000到0向下扫描系统内存,每次0x10000字节,通过EFI系统表的签名找到EFI_SYSTEM_TABLE,并patch LocateProtocol()函数地址。可以使用SCAN_FROM和SCAN_STEP环境变量来覆盖内存扫描选项。
  • PROTOCOL_ENTRY劫持 – 从物理地址0x76000000到0xA0000000向上扫描系统内存,每次0x1000字节,找到CPU I/O 2协议的EFI_CPU_IO2_PROTOCOL结构,然后patch该结构中的一个函数。可以使用SCAN_FROM、SCAN_TO和SCAN_STEP环境变量来覆盖内存扫描选项。

默认情况下,所有四个程序都使用EFI系统表劫持方法,如果要使用PROTOCOL_ENTRY方法,可以使用--inj-prot命令行选项。 为了减少执行攻击所需的时间,可以在EFI_SYSTEM_TABLE劫持时使用--system-table选项指定先前找到的EFI_SYSTEM_TABLE结构地址,或在PROTOCOL_ENTRY劫持时使用--prot-entry选项指定PROTOCOL_ENTRY结构地址。

另外,所有四个Python程序都有--test命令行选项,这个选项用于进行内存扫描,找到所需的结构地址,但不执行实际的劫持流程。在首次运行时,可以用--test选项运行所需的程序来找到所需的地址,第二次运行时再用--system-table--prot-entry选项运行相同的程序来指定该地址。