reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,222 @@
---
name: hunting-bootkits-in-efi-system-partition
description: Baseline the EFI System Partition and hunt malicious EFI binaries such as ESPecter, BlackLotus, Bootkitty, and Glupteba by mounting the ESP, hashing and verifying boot loaders, scanning with YARA, and flagging anomalous non-EFI files or out-of-band bootloader changes. Use during proactive threat hunts for firmware/bootkit persistence (MITRE ATT&CK T1542.003) or when investigating suspected UEFI-level compromise that survives OS reinstall.
domain: cybersecurity
subdomain: hardware-firmware-security
tags:
- bootkit
- uefi
- efi-system-partition
- secure-boot
- firmware-forensics
- threat-hunting
- yara
- measured-boot
version: '1.0'
author: mahipal
license: Apache-2.0
nist_csf:
- DE.CM-01
mitre_attack:
- T1542.003
---
# Hunting Bootkits in the EFI System Partition
## Overview
The EFI System Partition (ESP) is a small FAT32-formatted partition that the platform firmware reads at power-on to locate and execute the operating system's boot loader. Because it executes *before* the operating system, kernel, and any EDR agent, the ESP is one of the most coveted persistence locations for advanced adversaries. UEFI bootkits that live on the ESP survive OS reinstallation, disk reformatting of the OS partition, and most endpoint defenses.
This skill follows the detection research published by **Eclypsium** ("Enhanced Threat Detection: Bootloaders, Bootkits, and Secure Boot", and the *Bootkitty* and *Glupteba* analyses) and aligns with the ESP-hunting methodology Rapid7 documented for Velociraptor (`Windows.Forensics.UEFI`, `Windows.Detection.Yara.UEFI`). The threat context is concrete and current:
- **ESPecter** (ESET, 2021) — a UEFI bootkit that persists on the ESP as a patched Windows Boot Manager (`bootmgfw.efi`) plus malicious kernel-mode drivers. It marked the move of UEFI threats *from SPI flash to the ESP*, where they are far easier to deploy.
- **BlackLotus** (2023) — the first in-the-wild UEFI bootkit able to bypass Secure Boot on fully patched Windows 11 by exploiting CVE-2022-21894 ("baton drop") and staging a vulnerable signed `bootmgfw.efi` on the ESP.
- **Bootkitty** (2024) — the first UEFI bootkit targeting Linux, dropped onto the ESP.
- **Glupteba** — commodity malware whose UEFI variant replaces software on the EFI partition.
The core detection insight from Eclypsium and Rapid7 is that the bootloader normally changes **only** during a vendor or OS update; an out-of-band change to ESP binaries, an unsigned or untrusted-signed boot loader, or any file in the ESP root that is *not* under the `EFI/` directory is a high-fidelity indicator of compromise. This skill builds that baseline and hunts deviations from it.
## When to Use
- During proactive threat hunts for firmware/bootkit persistence (MITRE ATT&CK T1542.003 — Pre-OS Boot: Bootkit)
- After an incident where an adversary achieved SYSTEM/root and may have established below-OS persistence
- When validating Secure Boot posture across a fleet and confirming boot-chain integrity
- As a periodic integrity check, comparing the current ESP contents against a trusted golden baseline
- When triaging hosts that show measured-boot (TPM PCR) mismatches
## Prerequisites
- Administrative/root access to the target host (mounting and reading the ESP requires elevation)
- Linux analysis tooling — install on Debian/Ubuntu:
```bash
sudo apt-get update
sudo apt-get install -y sbsigntool pesign efitools efibootmgr binwalk yara
pip install pefile
```
- `UEFITool` for inspecting firmware/binaries (download from https://github.com/LongSoft/UEFITool/releases)
- A trusted **golden baseline** of EFI binary hashes for the OS/vendor versions in scope (build it once on a known-clean, freshly imaged host)
- For Windows targets: WinPE or a forensic boot environment, or Velociraptor with the `Windows.Forensics.UEFI` artifact
## Objectives
- Mount and enumerate the ESP read-only without altering evidence
- Inventory every EFI binary and compute cryptographic hashes
- Verify Secure Boot signatures on each boot loader against trusted keys
- Compare contents against a golden baseline to surface out-of-band changes
- YARA-scan ESP binaries for known bootkit signatures
- Flag anomalies: files outside `EFI/`, unsigned loaders, modified `bootmgfw.efi`/`grubx64.efi`, and tampered boot entries
- Confirm measured-boot (TPM PCR 0/2/4) integrity where TPM is present
## MITRE ATT&CK Mapping
| ID | Name | Relevance |
|----|------|-----------|
| T1542.003 | Pre-OS Boot: Bootkit | Adversaries place malicious boot loaders on the ESP to execute before the OS and EDR, achieving stealthy, resilient persistence. This skill hunts exactly that artifact. |
## Workflow
### Step 1: Identify and mount the ESP read-only
The ESP is a FAT32 partition, usually flagged `EF00` (GPT) or `esp,boot`. Locate it and mount read-only to preserve evidence.
```bash
# Identify the ESP (type code EF00 / "EFI System")
sudo lsblk -o NAME,FSTYPE,PARTTYPENAME,MOUNTPOINT
sudo fdisk -l | grep -i "EFI System"
# Mount the ESP read-only (replace /dev/sda1 with the identified partition)
sudo mkdir -p /mnt/esp
sudo mount -o ro,umask=077 /dev/sda1 /mnt/esp
# Confirm the canonical layout: EFI/ should be the only top-level dir
ls -la /mnt/esp
```
### Step 2: Detect anomalous top-level entries (high-fidelity hunt)
Per Rapid7/Velociraptor guidance, the ESP root should contain **only** the `EFI/` directory (and possibly a vendor `System Volume Information`). Anything else is suspicious.
```bash
# Any path in the ESP root NOT under EFI/ is a red flag
find /mnt/esp -maxdepth 1 -mindepth 1 ! -name 'EFI' ! -iname 'System Volume Information'
# Hunt for boot binaries dropped outside expected vendor folders
find /mnt/esp -type f \( -iname '*.efi' -o -iname '*.sys' -o -iname '*.dll' \) -printf '%p\t%s bytes\t%TY-%Tm-%Td\n'
```
### Step 3: Inventory and hash every EFI binary
Compute SHA-256 of all boot binaries for baseline comparison and threat-intel lookup.
```bash
# Recursively hash all EFI/PE binaries on the ESP
find /mnt/esp -type f \( -iname '*.efi' -o -iname '*.sys' \) -print0 \
| xargs -0 sha256sum | tee /tmp/esp_hashes.txt
# Quick triage on the primary loaders
sha256sum /mnt/esp/EFI/Microsoft/Boot/bootmgfw.efi 2>/dev/null
sha256sum /mnt/esp/EFI/Boot/bootx64.efi 2>/dev/null
sha256sum /mnt/esp/EFI/*/grubx64.efi /mnt/esp/EFI/*/shimx64.efi 2>/dev/null
```
Submit unknown hashes to VirusTotal / the LOLDrivers and Binarly catalogs to identify known-vulnerable or malicious loaders (e.g., the BlackLotus-abused `bootmgfw.efi` builds).
### Step 4: Verify Secure Boot signatures on each loader
A legitimate loader is signed by Microsoft UEFI CA (Windows/shim) or the distro vendor. Use `sbverify` to list/verify signatures and `pesign` for the certificate chain.
```bash
# List embedded signatures on a loader
sbverify --list /mnt/esp/EFI/Microsoft/Boot/bootmgfw.efi
# Verify against the platform's db certificate (export it first)
sudo efi-readvar -v db -o /tmp/db.esl # dump Secure Boot db
sbverify --cert /path/to/MicrosoftUEFICA.pem /mnt/esp/EFI/Boot/bootx64.efi
# Inspect the PE certificate chain
pesign -S -i /mnt/esp/EFI/Microsoft/Boot/bootmgfw.efi
```
An **unsigned** loader, a loader signed by an unexpected/self-signed certificate, or a known-vulnerable signed binary staged by an attacker (BlackLotus technique) is a confirmed finding.
### Step 5: Compare against the golden baseline
Diff the live ESP hash inventory against a trusted baseline captured from a clean image of the same OS/vendor build.
```bash
# Sort both inventories on the hash column and diff
awk '{print $1}' /tmp/esp_hashes.txt | sort > /tmp/live.sha256
sort baseline_esp_hashes.sha256 > /tmp/base.sha256
# Hashes present live but absent from the baseline = unexpected/new binaries
comm -23 /tmp/live.sha256 /tmp/base.sha256
```
Because the bootloader changes only during legitimate updates, any new hash that does not correspond to a known patch is an actionable lead.
### Step 6: YARA-scan ESP binaries for bootkit signatures
Run YARA rules for known bootkits (ESPecter, BlackLotus, Bootkitty, CosmicStrand) across the ESP — the same approach as Velociraptor's `Windows.Detection.Yara.UEFI`.
```bash
# Scan all ESP files recursively with a bootkit ruleset
yara -r -w bootkit_rules.yar /mnt/esp/
# Example: scan only the binaries collected in Step 3
yara -r bootkit_rules.yar /mnt/esp/EFI/
```
Source rules from the YARA-Rules project, Eclypsium/Binarly publications, and ESET's bootkit reports.
### Step 7: Inspect and validate UEFI boot entries
ESPecter-class bootkits manipulate the boot order/entries. Enumerate NVRAM boot variables and confirm each points to an expected, signed loader.
```bash
# List boot entries and the current order (Bootkitty/ESPecter tamper here)
sudo efibootmgr -v
# Confirm Secure Boot is enabled and look for revoked hashes in dbx
mokutil --sb-state
sudo efi-readvar -v dbx -o /tmp/dbx.esl
```
A boot entry referencing a file outside `\EFI\` or a loader whose hash appears in `dbx` (revoked) but is still present indicates tampering.
### Step 8: Validate measured boot against TPM PCRs (where available)
Measured boot records the boot-chain components into TPM PCRs (notably PCR 0, 2, 4). A bootkit that alters loaders changes these measurements.
```bash
# Read PCRs that cover firmware and the boot loader
sudo tpm2_pcrread sha256:0,2,4,7
# Parse the TCG event log to see what was measured into each PCR
sudo tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements
```
Compare measured values against the host's known-good attestation baseline; an unexplained PCR 4 change correlates with a modified boot loader.
### Step 9: Document findings and preserve evidence
```bash
# Make a forensic image of the ESP for offline analysis before remediation
sudo dd if=/dev/sda1 of=/evidence/esp_$(hostname)_$(date +%F).img bs=4M conv=noerror,sync
sha256sum /evidence/esp_*.img > /evidence/esp_image.sha256
sudo umount /mnt/esp
```
Record every anomalous binary (path, hash, signature status, baseline diff result, YARA match) in the case file before any cleanup.
## Tools and Resources
| Tool | Purpose | Source |
|------|---------|--------|
| sbsigntool (`sbverify`) | List/verify Secure Boot signatures on EFI binaries | https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git |
| pesign | Inspect PE/COFF signatures and certificate chains | https://github.com/rhboot/pesign |
| efitools (`efi-readvar`) | Dump Secure Boot variables (db/dbx/KEK/PK) | https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git |
| efibootmgr / mokutil | Enumerate boot entries and Secure Boot state | https://github.com/rhboot/efibootmgr |
| UEFITool | Parse and inspect UEFI binaries/firmware | https://github.com/LongSoft/UEFITool |
| YARA | Signature-scan ESP binaries for bootkits | https://github.com/VirusTotal/yara |
| tpm2-tools | Read PCRs and TCG event log for measured boot | https://github.com/tpm2-software/tpm2-tools |
| Velociraptor `Windows.Forensics.UEFI` | Scale ESP hunting across a fleet | https://docs.velociraptor.app/ |
| Eclypsium bootkit research | Threat context and detection methodology | https://eclypsium.com/blog/threat-detection-bootloaders-bootkits-secureboot/ |
| Rapid7 UEFI hunting blog | ESP hunting with Velociraptor artifacts | https://www.rapid7.com/blog/post/2024/02/29/how-to-hunt-for-uefi-malware-using-velociraptor/ |
## Known Bootkit Indicators
| Bootkit | ESP Artifact / Behavior | Reference |
|---------|-------------------------|-----------|
| ESPecter | Patched `bootmgfw.efi` + kernel drivers on ESP | ESET WeLiveSecurity 2021 |
| BlackLotus | Vulnerable signed `bootmgfw.efi` staged to bypass Secure Boot (CVE-2022-21894) | ESET 2023 |
| Bootkitty | Malicious EFI loader on ESP targeting Linux | ESET / Eclypsium 2024 |
| Glupteba (UEFI) | Replaces software on the EFI partition | Eclypsium |
| CosmicStrand | UEFI firmware implant hooking the boot chain | Eclypsium / Kaspersky |
## Validation Criteria
- [ ] ESP located and mounted read-only without modifying evidence
- [ ] Top-level ESP contents enumerated; any non-`EFI/` entries flagged
- [ ] All EFI binaries inventoried with SHA-256 hashes
- [ ] Secure Boot signatures verified on every boot loader
- [ ] Live inventory diffed against a trusted golden baseline
- [ ] YARA bootkit ruleset run across the ESP with no unexplained matches
- [ ] Boot entries (`efibootmgr`) validated; no references outside `\EFI\`
- [ ] Secure Boot confirmed enabled; no present binary matches a `dbx`-revoked hash
- [ ] TPM PCR 0/2/4 measurements compared to baseline (where TPM present)
- [ ] Forensic ESP image preserved and all findings documented

View File

@@ -0,0 +1,66 @@
# Command Reference — ESP Bootkit Hunting
## ESP discovery and mounting
| Command | Purpose |
|---------|---------|
| `lsblk -o NAME,FSTYPE,PARTTYPENAME,MOUNTPOINT` | List partitions with type names to find the ESP |
| `fdisk -l \| grep -i "EFI System"` | Identify the ESP partition device |
| `mount -o ro,umask=077 /dev/sdXN /mnt/esp` | Mount the ESP read-only (evidence-safe) |
| `umount /mnt/esp` | Unmount after analysis |
## sbverify (sbsigntool) — Secure Boot signatures
| Command | Purpose |
|---------|---------|
| `sbverify --list <binary.efi>` | List all embedded signatures on an EFI binary |
| `sbverify --cert <ca.pem> <binary.efi>` | Verify a binary against a known-good signing certificate |
| `sbverify --detached <sig> <binary.efi>` | Verify a detached signature |
## pesign — PE/COFF signature inspection
| Command | Purpose |
|---------|---------|
| `pesign -S -i <binary.efi>` | Show signatures / certificate chain on a PE binary |
| `pesign -h -i <binary.efi>` | Print the PE authenticode hash |
## efitools / efibootmgr / mokutil — Secure Boot state
| Command | Purpose |
|---------|---------|
| `efi-readvar -v db -o db.esl` | Dump the Secure Boot allow-list (db) |
| `efi-readvar -v dbx -o dbx.esl` | Dump the Secure Boot revocation list (dbx) |
| `efibootmgr -v` | List boot entries and boot order with loader paths |
| `mokutil --sb-state` | Report whether Secure Boot is enabled |
| `mokutil --list-enrolled` | List enrolled Machine Owner Keys |
## YARA — bootkit scanning
| Command | Purpose |
|---------|---------|
| `yara -r -w <rules.yar> /mnt/esp/` | Recursively scan the ESP, suppress warnings |
| `yara -r -s <rules.yar> /mnt/esp/EFI/` | Scan with matched-string output |
## tpm2-tools — measured boot
| Command | Purpose |
|---------|---------|
| `tpm2_pcrread sha256:0,2,4,7` | Read firmware/boot-loader/Secure-Boot PCRs |
| `tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements` | Parse the TCG measured-boot event log |
## Hashing and baseline diff
| Command | Purpose |
|---------|---------|
| `find /mnt/esp -type f \( -iname '*.efi' -o -iname '*.sys' \) -print0 \| xargs -0 sha256sum` | Inventory and hash all boot binaries |
| `comm -23 live.sha256 base.sha256` | Show hashes present live but absent from baseline |
| `dd if=/dev/sdXN of=esp.img bs=4M conv=noerror,sync` | Forensically image the ESP |
## Velociraptor artifacts (fleet hunting)
| Artifact | Purpose |
|----------|---------|
| `Windows.Forensics.UEFI` | Parse the ESP partition table and FAT to enumerate files |
| `Windows.Detection.Yara.UEFI` | YARA-scan ESP contents at scale |
| `Generic.System.EfiSignatures` | Collect EFI signature data |
| `Windows.Forensics.UEFI.BootApplication` | Parse Measured Boot TCG logs |

View File

@@ -0,0 +1,22 @@
# Standards Mapping — Hunting Bootkits in the EFI System Partition
## MITRE ATT&CK
| ID | Name | Rationale |
|----|------|-----------|
| T1542.003 | Pre-OS Boot: Bootkit | Adversaries install malicious boot loaders on the ESP to execute before the OS and security tooling; this skill hunts and validates those ESP boot artifacts. |
## NIST Cybersecurity Framework (CSF 2.0)
| ID | Name | Rationale |
|----|------|-----------|
| DE.CM-01 | Networks and network services are monitored to find potentially adverse events (extended here to host boot-chain integrity monitoring) | Continuous baselining and integrity monitoring of ESP boot binaries detects out-of-band bootkit persistence. |
## Supporting References
- Eclypsium — "Enhanced Threat Detection: Bootloaders, Bootkits, and Secure Boot": https://eclypsium.com/blog/threat-detection-bootloaders-bootkits-secureboot/
- Eclypsium — "Bootkitty and Linux Bootkits": https://eclypsium.com/blog/bootkitty-linux-bootkit/
- ESET — "UEFI threats moving to the ESP: Introducing ESPecter bootkit": https://www.welivesecurity.com/2021/10/05/uefi-threats-moving-esp-introducing-especter-bootkit/
- Rapid7 — "How To Hunt For UEFI Malware Using Velociraptor": https://www.rapid7.com/blog/post/2024/02/29/how-to-hunt-for-uefi-malware-using-velociraptor/
- NSA — "UEFI Secure Boot Customization" guidance
- UEFI Specification — EFI System Partition layout (`\EFI\` directory structure)

View File

@@ -0,0 +1,174 @@
#!/usr/bin/env python3
"""
esp_bootkit_hunter.py — Baseline and hunt malicious EFI binaries on the EFI System Partition.
Mounts (or reads an already-mounted) ESP, inventories EFI/PE boot binaries, computes
SHA-256 hashes, verifies Secure Boot signatures with sbverify, flags files outside the
canonical EFI/ directory, diffs against a golden baseline, and optionally YARA-scans.
Real tooling used: sbverify (sbsigntool), yara, sha256 hashing. No placeholders.
Usage:
sudo python3 esp_bootkit_hunter.py --esp /mnt/esp --baseline baseline.sha256
sudo python3 esp_bootkit_hunter.py --device /dev/sda1 --mount --yara bootkit.yar
"""
import argparse
import hashlib
import json
import os
import shutil
import subprocess
import sys
import tempfile
EFI_EXTENSIONS = (".efi", ".sys", ".dll")
def run(cmd):
"""Run a command, return (returncode, stdout, stderr)."""
try:
p = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
return p.returncode, p.stdout, p.stderr
except FileNotFoundError:
return 127, "", f"binary not found: {cmd[0]}"
except subprocess.TimeoutExpired:
return 124, "", "timeout"
def mount_esp(device, mountpoint):
os.makedirs(mountpoint, exist_ok=True)
rc, _, err = run(["mount", "-o", "ro,umask=077", device, mountpoint])
if rc != 0:
sys.exit(f"[!] Failed to mount {device}: {err.strip()}")
print(f"[+] Mounted {device} read-only at {mountpoint}")
def sha256_file(path):
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""):
h.update(chunk)
return h.hexdigest()
def find_efi_binaries(esp_root):
found = []
for dirpath, _, files in os.walk(esp_root):
for name in files:
if name.lower().endswith(EFI_EXTENSIONS):
found.append(os.path.join(dirpath, name))
return found
def detect_anomalous_root(esp_root):
"""Per Velociraptor/Rapid7: EFI/ should be the only top-level dir on the ESP."""
allowed = {"efi", "system volume information"}
anomalies = []
for entry in os.listdir(esp_root):
if entry.lower() not in allowed:
anomalies.append(os.path.join(esp_root, entry))
return anomalies
def verify_signature(path):
"""Use sbverify --list to confirm the binary carries a Secure Boot signature."""
if not shutil.which("sbverify"):
return "sbverify-missing"
rc, out, _ = run(["sbverify", "--list", path])
if rc != 0:
return "UNSIGNED-or-invalid"
# sbverify --list prints 'signature N' lines for each embedded signature
return "signed" if "signature" in out.lower() else "UNSIGNED"
def load_baseline(path):
baseline = set()
if not path or not os.path.exists(path):
return baseline
with open(path) as f:
for line in f:
tok = line.strip().split()
if tok:
baseline.add(tok[0].lower())
return baseline
def yara_scan(rules, esp_root):
if not shutil.which("yara"):
return "yara-missing"
rc, out, err = run(["yara", "-r", "-w", rules, esp_root])
return out.strip() or ("(no matches)" if rc == 0 else err.strip())
def main():
ap = argparse.ArgumentParser(description="Hunt bootkits on the EFI System Partition.")
ap.add_argument("--esp", default="/mnt/esp", help="ESP mountpoint")
ap.add_argument("--device", help="ESP block device to mount (e.g. /dev/sda1)")
ap.add_argument("--mount", action="store_true", help="Mount --device read-only first")
ap.add_argument("--baseline", help="Golden baseline sha256 file to diff against")
ap.add_argument("--yara", help="YARA ruleset to scan the ESP with")
ap.add_argument("--json", help="Write findings to this JSON path")
args = ap.parse_args()
if os.geteuid() != 0:
print("[!] Warning: ESP access typically requires root.", file=sys.stderr)
if args.mount:
if not args.device:
sys.exit("--mount requires --device")
mount_esp(args.device, args.esp)
if not os.path.isdir(args.esp):
sys.exit(f"[!] ESP path not found: {args.esp}")
report = {"esp": args.esp, "binaries": [], "root_anomalies": [],
"baseline_new": [], "yara": None}
# Step 2: anomalous root entries
report["root_anomalies"] = detect_anomalous_root(args.esp)
for a in report["root_anomalies"]:
print(f"[!] ANOMALY: non-EFI entry in ESP root -> {a}")
# Steps 3-4: inventory, hash, verify signatures
baseline = load_baseline(args.baseline)
for path in find_efi_binaries(args.esp):
try:
digest = sha256_file(path)
except OSError as e:
print(f"[!] Cannot read {path}: {e}", file=sys.stderr)
continue
sig = verify_signature(path)
new = bool(baseline) and digest.lower() not in baseline
entry = {"path": path, "sha256": digest, "signature": sig, "new_vs_baseline": new}
report["binaries"].append(entry)
flag = ""
if sig.startswith("UNSIGNED"):
flag += " [UNSIGNED]"
if new:
flag += " [NOT-IN-BASELINE]"
report["baseline_new"].append(digest)
print(f"[+] {digest} {sig:18s} {path}{flag}")
# Step 6: YARA
if args.yara:
report["yara"] = yara_scan(args.yara, args.esp)
print(f"[+] YARA results:\n{report['yara']}")
# Summary
n_unsigned = sum(1 for b in report["binaries"] if b["signature"].startswith("UNSIGNED"))
print(f"\n[=] {len(report['binaries'])} EFI binaries | "
f"{n_unsigned} unsigned | {len(report['baseline_new'])} new vs baseline | "
f"{len(report['root_anomalies'])} root anomalies")
if args.json:
with open(args.json, "w") as f:
json.dump(report, f, indent=2)
print(f"[+] Wrote findings to {args.json}")
# Non-zero exit if anything suspicious was found (CI/hunt automation friendly)
if n_unsigned or report["baseline_new"] or report["root_anomalies"]:
sys.exit(2)
if __name__ == "__main__":
main()