reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -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.
|
||||
@@ -0,0 +1,317 @@
|
||||
---
|
||||
name: performing-firmware-malware-analysis
|
||||
description: 'Analyzes firmware images for embedded malware, backdoors, and unauthorized
|
||||
modifications in routers, IoT devices, UEFI/BIOS, and embedded systems, covering
|
||||
firmware extraction, filesystem analysis, binary reverse engineering, and bootkit
|
||||
detection. Use for firmware security analysis, IoT malware investigation, UEFI
|
||||
rootkit detection, or embedded device compromise assessment.
|
||||
|
||||
'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware
|
||||
- firmware
|
||||
- IoT
|
||||
- UEFI
|
||||
- embedded-security
|
||||
version: 1.0.0
|
||||
author: mahipal
|
||||
license: Apache-2.0
|
||||
nist_csf:
|
||||
- DE.AE-02
|
||||
- RS.AN-03
|
||||
- ID.RA-01
|
||||
- DE.CM-01
|
||||
mitre_attack:
|
||||
- T1027
|
||||
- T1055
|
||||
- T1140
|
||||
- T1497
|
||||
- T1505.003
|
||||
---
|
||||
|
||||
# Performing Firmware Malware Analysis
|
||||
|
||||
## When to Use
|
||||
|
||||
- A compromised IoT device or router needs firmware analysis to identify implanted backdoors
|
||||
- Investigating UEFI/BIOS rootkits that persist across OS reinstallations
|
||||
- Analyzing firmware updates for supply chain compromise or malicious modifications
|
||||
- Extracting and examining embedded Linux filesystems from IoT device firmware images
|
||||
- Verifying firmware integrity after a suspected hardware or firmware-level compromise
|
||||
|
||||
**Do not use** for standard operating system malware; use PE/ELF analysis tools for OS-level malware on conventional systems.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- binwalk installed for firmware image analysis and extraction (`pip install binwalk`)
|
||||
- Ghidra with ARM/MIPS architecture support for embedded binary reverse engineering
|
||||
- UEFI Tool (UEFITool) for UEFI firmware parsing and analysis
|
||||
- Firmware Analysis Toolkit (FAT) or EMBA for automated firmware analysis
|
||||
- QEMU for emulating extracted firmware filesystems
|
||||
- Cross-compilation toolchains for ARM, MIPS, and other embedded architectures
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Extract and Identify Firmware Components
|
||||
|
||||
Analyze the firmware image structure and extract filesystems:
|
||||
|
||||
```bash
|
||||
# Identify embedded filesystems and compressed data
|
||||
binwalk firmware.bin
|
||||
|
||||
# Extract all identified components
|
||||
binwalk -e firmware.bin
|
||||
|
||||
# Recursive extraction with signature scanning
|
||||
binwalk -eM firmware.bin
|
||||
|
||||
# Output typically includes:
|
||||
# - Bootloader (U-Boot, GRUB, custom)
|
||||
# - Kernel image (Linux, RTOS)
|
||||
# - Root filesystem (SquashFS, JFFS2, CramFS, ext4)
|
||||
# - Configuration data
|
||||
# - Digital signatures or checksums
|
||||
|
||||
# Entropy analysis to find encrypted or compressed regions
|
||||
binwalk -E firmware.bin
|
||||
|
||||
# Identify specific filesystem types
|
||||
file _firmware.bin.extracted/*
|
||||
|
||||
# For SquashFS filesystems
|
||||
unsquashfs _firmware.bin.extracted/squashfs-root.img
|
||||
ls squashfs-root/
|
||||
```
|
||||
|
||||
### Step 2: Analyze the Extracted Filesystem
|
||||
|
||||
Search for malicious modifications in the firmware filesystem:
|
||||
|
||||
```bash
|
||||
# Directory structure analysis
|
||||
find squashfs-root/ -type f | head -50
|
||||
|
||||
# Search for suspicious files
|
||||
find squashfs-root/ -name "*.sh" -exec ls -la {} \;
|
||||
find squashfs-root/ -perm -4000 -type f # SUID binaries
|
||||
find squashfs-root/ -name "*.so" -newer squashfs-root/bin/busybox # Modified libraries
|
||||
|
||||
# Check startup scripts for backdoors
|
||||
cat squashfs-root/etc/init.d/rcS
|
||||
cat squashfs-root/etc/inittab
|
||||
ls -la squashfs-root/etc/rc.d/
|
||||
|
||||
# Search for hardcoded credentials
|
||||
grep -rn "password\|passwd\|secret\|key\|token" squashfs-root/etc/ 2>/dev/null
|
||||
grep -rn "root:" squashfs-root/etc/shadow 2>/dev/null
|
||||
|
||||
# Check for unauthorized SSH keys
|
||||
find squashfs-root/ -name "authorized_keys" -exec cat {} \;
|
||||
|
||||
# Network configuration backdoors
|
||||
cat squashfs-root/etc/hosts
|
||||
grep -rn "iptables\|nc\|netcat\|ncat" squashfs-root/etc/ squashfs-root/usr/bin/
|
||||
|
||||
# Check for reverse shells in cron
|
||||
find squashfs-root/ -name "crontab" -o -name "cron*" | xargs cat 2>/dev/null
|
||||
|
||||
# Identify all ELF binaries for analysis
|
||||
find squashfs-root/ -type f -exec file {} \; | grep ELF
|
||||
```
|
||||
|
||||
### Step 3: Reverse Engineer Suspicious Binaries
|
||||
|
||||
Analyze extracted binaries that may be backdoors:
|
||||
|
||||
```bash
|
||||
# Identify architecture and format
|
||||
file squashfs-root/usr/bin/suspicious_binary
|
||||
|
||||
# Extract strings for IOC discovery
|
||||
strings squashfs-root/usr/bin/suspicious_binary | grep -iE "http|ip|port|shell|connect|exec"
|
||||
|
||||
# Cross-reference against known firmware binaries
|
||||
# Compare SHA-256 hashes with known-good firmware
|
||||
sha256sum squashfs-root/usr/bin/* > current_hashes.txt
|
||||
# diff against baseline: diff baseline_hashes.txt current_hashes.txt
|
||||
|
||||
# Import into Ghidra for disassembly (select correct architecture)
|
||||
# ARM: ARM/AARCH64 (Little Endian for most IoT devices)
|
||||
# MIPS: MIPS/MIPS64 (Big or Little Endian depending on device)
|
||||
# x86: For UEFI modules
|
||||
|
||||
# Analyze with radare2 for quick triage
|
||||
r2 -A squashfs-root/usr/bin/suspicious_binary
|
||||
# Commands: afl (function list), pdf @main (disassemble main), iz (strings)
|
||||
```
|
||||
|
||||
### Step 4: UEFI/BIOS Firmware Analysis
|
||||
|
||||
Analyze system firmware for bootkits and implants:
|
||||
|
||||
```bash
|
||||
# Extract UEFI firmware volumes with UEFITool
|
||||
# GUI: UEFITool -> File -> Open -> Select firmware.rom
|
||||
# CLI: UEFIExtract firmware.rom
|
||||
|
||||
# Analyze UEFI firmware with chipsec (requires hardware access)
|
||||
python chipsec_main.py -m common.bios_wp # BIOS write protection
|
||||
python chipsec_main.py -m common.spi_lock # SPI flash lock
|
||||
python chipsec_main.py -m common.secureboot # Secure Boot status
|
||||
python chipsec_main.py -m common.uefi.s3bootscript # S3 resume script
|
||||
|
||||
# Dump UEFI firmware from live system
|
||||
python chipsec_util.py spi dump firmware_dump.rom
|
||||
|
||||
# Compare with known-good firmware
|
||||
sha256sum firmware_dump.rom
|
||||
# Compare against vendor-provided firmware hash
|
||||
|
||||
# Scan for known UEFI malware signatures
|
||||
yara -r uefi_malware_rules.yar firmware_dump.rom
|
||||
```
|
||||
|
||||
```
|
||||
Known UEFI Malware Families:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
LoJax: First in-the-wild UEFI rootkit (APT28/Fancy Bear)
|
||||
Modifies SPI flash to drop persistence agent
|
||||
MosaicRegressor: Modular UEFI framework dropping multiple payloads
|
||||
CosmicStrand: UEFI firmware rootkit modifying kernel during boot
|
||||
BlackLotus: UEFI bootkit bypassing Secure Boot on Windows 11
|
||||
ESPecter: ESP (EFI System Partition) bootkit modifying boot manager
|
||||
MoonBounce: SPI flash implant modifying CORE_DXE module
|
||||
FinSpy UEFI: Surveillance software with UEFI persistence
|
||||
```
|
||||
|
||||
### Step 5: Emulate Firmware for Dynamic Analysis
|
||||
|
||||
Run extracted firmware in an emulated environment:
|
||||
|
||||
```bash
|
||||
# Emulate ARM-based IoT firmware with QEMU
|
||||
# Mount the extracted filesystem
|
||||
sudo mount -o loop squashfs-root.img /mnt/firmware
|
||||
|
||||
# Chroot into the firmware with QEMU user-mode emulation
|
||||
sudo cp /usr/bin/qemu-arm-static /mnt/firmware/usr/bin/
|
||||
sudo chroot /mnt/firmware /bin/sh
|
||||
|
||||
# Or use firmadyne for automated firmware emulation
|
||||
# https://github.com/firmadyne/firmadyne
|
||||
python3 fat.py firmware.bin
|
||||
|
||||
# Network service analysis within emulated firmware
|
||||
# Scan for open ports and services
|
||||
nmap -sV localhost -p 1-65535
|
||||
|
||||
# Monitor network traffic from emulated firmware
|
||||
tcpdump -i tap0 -w firmware_traffic.pcap
|
||||
```
|
||||
|
||||
### Step 6: Document Firmware Analysis
|
||||
|
||||
Compile comprehensive firmware analysis findings:
|
||||
|
||||
```
|
||||
Analysis documentation should cover:
|
||||
- Firmware image metadata (vendor, model, version, build date)
|
||||
- Extraction results (filesystem type, kernel version, architecture)
|
||||
- Modified files compared to known-good baseline
|
||||
- Backdoor binaries discovered with reverse engineering findings
|
||||
- Hardcoded credentials and unauthorized access mechanisms
|
||||
- Network services and their security posture
|
||||
- UEFI/BIOS integrity verification results
|
||||
- Extracted IOCs (IPs, domains, file hashes, SSH keys)
|
||||
- Remediation recommendations (reflash, replace, update)
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
| Term | Definition |
|
||||
|------|------------|
|
||||
| **Firmware** | Software permanently stored in device hardware (flash memory, EEPROM) controlling low-level device operations and boot process |
|
||||
| **UEFI (Unified Extensible Firmware Interface)** | Modern system firmware replacing legacy BIOS; provides boot services, runtime services, and a modular driver architecture |
|
||||
| **SPI Flash** | Serial Peripheral Interface flash memory chip storing UEFI/BIOS firmware; can be read and modified for persistence |
|
||||
| **Secure Boot** | UEFI feature verifying digital signatures of boot components to prevent unauthorized code execution during startup |
|
||||
| **SquashFS** | Read-only compressed filesystem commonly used in embedded Linux firmware for space-efficient storage |
|
||||
| **Bootkit** | Malware infecting the boot process (MBR, VBR, UEFI) to load before the operating system and evade OS-level security |
|
||||
| **Firmware Emulation** | Running extracted firmware in a virtual environment (QEMU, firmadyne) to analyze behavior without physical hardware |
|
||||
|
||||
## Tools & Systems
|
||||
|
||||
- **binwalk**: Firmware analysis tool for scanning, extracting, and analyzing embedded file systems and compressed data in firmware images
|
||||
- **UEFITool**: Open-source UEFI firmware image parser and extractor for analyzing UEFI volumes, modules, and drivers
|
||||
- **chipsec**: Intel's open-source framework for platform security assessment including SPI flash, Secure Boot, and UEFI analysis
|
||||
- **firmadyne**: Automated firmware analysis and emulation platform for Linux-based embedded devices
|
||||
- **Ghidra**: NSA's reverse engineering tool with ARM, MIPS, and other embedded architecture support for firmware binary analysis
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario: Investigating a Compromised Router with Persistent Backdoor
|
||||
|
||||
**Context**: A network router continues to exhibit suspicious behavior (unexpected DNS resolutions, traffic to unknown IPs) even after factory resets. Firmware-level compromise is suspected.
|
||||
|
||||
**Approach**:
|
||||
1. Dump the firmware from the router using JTAG/UART debug interface or vendor management tools
|
||||
2. Extract the filesystem with binwalk and identify the Linux distribution and kernel version
|
||||
3. Compare file hashes against known-good firmware image from the vendor
|
||||
4. Search startup scripts (rcS, inittab, crontab) for backdoor entries
|
||||
5. Analyze any modified or new binaries with Ghidra (ARM/MIPS architecture)
|
||||
6. Check for hardcoded credentials, unauthorized SSH keys, and reverse shell scripts
|
||||
7. Emulate the firmware to observe network behavior and identify C2 communication
|
||||
|
||||
**Pitfalls**:
|
||||
- Not dumping firmware from the actual device (downloading from vendor site gives clean version, not the compromised one)
|
||||
- Ignoring modified shared libraries (.so files) that may hook system functions
|
||||
- Missing firmware modifications stored outside the main filesystem (bootloader, configuration partitions)
|
||||
- Not checking both the primary and backup firmware partitions (some devices have dual-bank flash)
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
FIRMWARE MALWARE ANALYSIS REPORT
|
||||
===================================
|
||||
Device: NetGear R7000 Router
|
||||
Firmware Version: V1.0.11.116 (modified)
|
||||
Architecture: ARM (Little Endian)
|
||||
Filesystem: SquashFS (Linux 3.4.103)
|
||||
Dump Method: UART debug console
|
||||
|
||||
INTEGRITY CHECK
|
||||
Vendor Firmware Hash: aaa111bbb222... (clean V1.0.11.116)
|
||||
Analyzed Firmware Hash: ccc333ddd444... (MISMATCH)
|
||||
Modified Files: 14 files differ from vendor baseline
|
||||
|
||||
BACKDOOR FINDINGS
|
||||
[!] /usr/bin/httpd_backdoor (new binary, not in vendor firmware)
|
||||
Architecture: ARM 32-bit
|
||||
Function: Reverse shell to 185.220.101[.]42:4444
|
||||
Persistence: Added to /etc/init.d/rcS
|
||||
|
||||
[!] /etc/shadow modified
|
||||
Root password changed to known hash
|
||||
New user 'admin2' added with UID 0
|
||||
|
||||
[!] /etc/crontab modified
|
||||
Added: */5 * * * * /usr/bin/httpd_backdoor
|
||||
|
||||
[!] /root/.ssh/authorized_keys (new file)
|
||||
Contains attacker's SSH public key
|
||||
|
||||
EXTRACTED IOCs
|
||||
C2 IP: 185.220.101[.]42
|
||||
C2 Port: 4444
|
||||
SSH Key: ssh-rsa AAAA... attacker@control
|
||||
Backdoor Hash: eee555fff666...
|
||||
|
||||
REMEDIATION
|
||||
1. Flash clean vendor firmware via TFTP recovery mode
|
||||
2. Change all device credentials
|
||||
3. Update to latest firmware version
|
||||
4. Enable firmware integrity checking if available
|
||||
5. Monitor for re-compromise indicators
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
# API Reference: Firmware Malware Analysis
|
||||
|
||||
## binwalk CLI
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `binwalk <firmware>` | Scan and display embedded file signatures |
|
||||
| `binwalk -e <firmware>` | Extract identified components |
|
||||
| `binwalk -eM <firmware>` | Recursive extraction with signature scanning |
|
||||
| `binwalk -E <firmware>` | Entropy analysis for encrypted/compressed regions |
|
||||
| `binwalk -A <firmware>` | Scan for executable opcode signatures |
|
||||
|
||||
## binwalk Python API
|
||||
|
||||
```python
|
||||
import binwalk
|
||||
for module in binwalk.scan("firmware.bin", signature=True, extract=True):
|
||||
for result in module.results:
|
||||
print(f"0x{result.offset:X} {result.description}")
|
||||
```
|
||||
|
||||
## chipsec CLI (UEFI Analysis)
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `python chipsec_main.py -m common.bios_wp` | Check BIOS write protection |
|
||||
| `python chipsec_main.py -m common.spi_lock` | Check SPI flash lock status |
|
||||
| `python chipsec_main.py -m common.secureboot` | Verify Secure Boot configuration |
|
||||
| `python chipsec_util.py spi dump <output>` | Dump UEFI firmware from SPI flash |
|
||||
|
||||
## Python Libraries
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `subprocess` | stdlib | Execute binwalk, file, and strings commands |
|
||||
| `hashlib` | stdlib | SHA-256 hashing for firmware integrity |
|
||||
| `re` | stdlib | Pattern matching for IOC extraction |
|
||||
|
||||
## References
|
||||
|
||||
- binwalk: https://github.com/ReFirmLabs/binwalk
|
||||
- Firmadyne: https://github.com/firmadyne/firmadyne
|
||||
- UEFITool: https://github.com/LongSoft/UEFITool
|
||||
- chipsec: https://github.com/chipsec/chipsec
|
||||
- EMBA firmware analyzer: https://github.com/e-m-b-a/emba
|
||||
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for performing firmware malware analysis.
|
||||
|
||||
Automates firmware extraction with binwalk, filesystem analysis,
|
||||
string extraction, entropy analysis, and IOC identification.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class FirmwareAnalysisAgent:
|
||||
"""Automates firmware image analysis and malware detection."""
|
||||
|
||||
def __init__(self, firmware_path, output_dir):
|
||||
self.firmware_path = Path(firmware_path)
|
||||
self.output_dir = Path(output_dir)
|
||||
self.output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def compute_hash(self):
|
||||
"""Compute SHA-256 hash of the firmware image."""
|
||||
sha256 = hashlib.sha256(self.firmware_path.read_bytes()).hexdigest()
|
||||
return {"sha256": sha256, "size": self.firmware_path.stat().st_size}
|
||||
|
||||
def run_binwalk_scan(self):
|
||||
"""Scan firmware with binwalk to identify embedded components."""
|
||||
result = subprocess.run(
|
||||
["binwalk", str(self.firmware_path)],
|
||||
capture_output=True, text=True,
|
||||
timeout=120,
|
||||
)
|
||||
return {"output": result.stdout, "returncode": result.returncode}
|
||||
|
||||
def run_binwalk_extract(self):
|
||||
"""Extract firmware components with binwalk recursive extraction."""
|
||||
extract_dir = self.output_dir / "extracted"
|
||||
result = subprocess.run(
|
||||
["binwalk", "-eM", "-C", str(extract_dir), str(self.firmware_path)],
|
||||
capture_output=True, text=True,
|
||||
timeout=120,
|
||||
)
|
||||
return {"extract_dir": str(extract_dir), "returncode": result.returncode}
|
||||
|
||||
def run_entropy_analysis(self):
|
||||
"""Run binwalk entropy analysis to detect encrypted/compressed regions."""
|
||||
result = subprocess.run(
|
||||
["binwalk", "-E", str(self.firmware_path)],
|
||||
capture_output=True, text=True,
|
||||
timeout=120,
|
||||
)
|
||||
return {"output": result.stdout}
|
||||
|
||||
def find_filesystem_root(self):
|
||||
"""Locate extracted filesystem root directory."""
|
||||
extract_dir = self.output_dir / "extracted"
|
||||
for root, dirs, files in os.walk(str(extract_dir)):
|
||||
if "squashfs-root" in dirs:
|
||||
return Path(root) / "squashfs-root"
|
||||
if "etc" in dirs and "bin" in dirs:
|
||||
return Path(root)
|
||||
return None
|
||||
|
||||
def search_hardcoded_credentials(self, fs_root):
|
||||
"""Search filesystem for hardcoded credentials."""
|
||||
findings = []
|
||||
patterns = [
|
||||
(r"password|passwd|secret|api_key|token", "credential_keyword"),
|
||||
(r"root:\$[0-9a-zA-Z\$\.\/]+", "password_hash"),
|
||||
(r"ssh-rsa\s+[A-Za-z0-9+/=]+", "ssh_key"),
|
||||
]
|
||||
|
||||
search_dirs = ["etc", "usr/bin", "usr/sbin", "home", "root", "var"]
|
||||
for search_dir in search_dirs:
|
||||
target = fs_root / search_dir
|
||||
if not target.exists():
|
||||
continue
|
||||
for filepath in target.rglob("*"):
|
||||
if not filepath.is_file():
|
||||
continue
|
||||
try:
|
||||
content = filepath.read_text(errors="ignore")
|
||||
for pattern, finding_type in patterns:
|
||||
matches = re.findall(pattern, content, re.IGNORECASE)
|
||||
if matches:
|
||||
findings.append({
|
||||
"file": str(filepath.relative_to(fs_root)),
|
||||
"type": finding_type,
|
||||
"match_count": len(matches),
|
||||
"samples": matches[:3],
|
||||
})
|
||||
except (PermissionError, OSError):
|
||||
continue
|
||||
return findings
|
||||
|
||||
def check_startup_scripts(self, fs_root):
|
||||
"""Analyze startup scripts for backdoor entries."""
|
||||
scripts = []
|
||||
startup_paths = [
|
||||
"etc/init.d", "etc/rc.d", "etc/inittab", "etc/rcS",
|
||||
"etc/crontab", "etc/cron.d",
|
||||
]
|
||||
suspicious_patterns = [
|
||||
r"nc\s+-[el]", r"netcat", r"bash\s+-i", r"wget\s+http",
|
||||
r"curl\s+http.*\|.*sh", r"telnetd", r"/dev/tcp/",
|
||||
]
|
||||
|
||||
for spath in startup_paths:
|
||||
target = fs_root / spath
|
||||
if target.is_file():
|
||||
scripts.append(self._analyze_script(target, fs_root, suspicious_patterns))
|
||||
elif target.is_dir():
|
||||
for f in target.iterdir():
|
||||
if f.is_file():
|
||||
scripts.append(self._analyze_script(f, fs_root, suspicious_patterns))
|
||||
return [s for s in scripts if s]
|
||||
|
||||
def _analyze_script(self, filepath, fs_root, patterns):
|
||||
"""Analyze a single script for suspicious content."""
|
||||
try:
|
||||
content = filepath.read_text(errors="ignore")
|
||||
except (PermissionError, OSError):
|
||||
return None
|
||||
suspicious = []
|
||||
for pattern in patterns:
|
||||
if re.search(pattern, content, re.IGNORECASE):
|
||||
suspicious.append(pattern)
|
||||
return {
|
||||
"file": str(filepath.relative_to(fs_root)),
|
||||
"size": filepath.stat().st_size,
|
||||
"suspicious_patterns": suspicious,
|
||||
"is_suspicious": len(suspicious) > 0,
|
||||
}
|
||||
|
||||
def find_elf_binaries(self, fs_root):
|
||||
"""Identify all ELF binaries in the extracted filesystem."""
|
||||
binaries = []
|
||||
for filepath in fs_root.rglob("*"):
|
||||
if not filepath.is_file():
|
||||
continue
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["file", "--brief", str(filepath)],
|
||||
capture_output=True, text=True,
|
||||
timeout=120,
|
||||
)
|
||||
if "ELF" in result.stdout:
|
||||
binaries.append({
|
||||
"file": str(filepath.relative_to(fs_root)),
|
||||
"type": result.stdout.strip(),
|
||||
"size": filepath.stat().st_size,
|
||||
"sha256": hashlib.sha256(filepath.read_bytes()).hexdigest(),
|
||||
})
|
||||
except (PermissionError, OSError):
|
||||
continue
|
||||
return binaries
|
||||
|
||||
def extract_strings_iocs(self, fs_root):
|
||||
"""Extract IOCs (IPs, URLs, domains) from firmware binaries."""
|
||||
iocs = {"ips": set(), "urls": set(), "domains": set()}
|
||||
ip_pattern = re.compile(r"\b(?:\d{1,3}\.){3}\d{1,3}\b")
|
||||
url_pattern = re.compile(r"https?://[^\s\"'<>]+")
|
||||
domain_pattern = re.compile(r"\b[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.[a-z]{2,}\b")
|
||||
|
||||
for filepath in fs_root.rglob("*"):
|
||||
if not filepath.is_file() or filepath.stat().st_size > 10_000_000:
|
||||
continue
|
||||
try:
|
||||
content = filepath.read_bytes().decode("utf-8", errors="ignore")
|
||||
iocs["ips"].update(ip_pattern.findall(content))
|
||||
iocs["urls"].update(url_pattern.findall(content))
|
||||
iocs["domains"].update(domain_pattern.findall(content))
|
||||
except (PermissionError, OSError):
|
||||
continue
|
||||
|
||||
private_ips = {"127.0.0.1", "0.0.0.0", "255.255.255.255"}
|
||||
iocs["ips"] -= private_ips
|
||||
return {k: sorted(v) for k, v in iocs.items()}
|
||||
|
||||
def generate_report(self):
|
||||
"""Run full firmware analysis and generate a report."""
|
||||
report = {"firmware": str(self.firmware_path), "hash": self.compute_hash()}
|
||||
report["binwalk_scan"] = self.run_binwalk_scan()
|
||||
self.run_binwalk_extract()
|
||||
|
||||
fs_root = self.find_filesystem_root()
|
||||
if fs_root:
|
||||
report["credentials"] = self.search_hardcoded_credentials(fs_root)
|
||||
report["startup_scripts"] = self.check_startup_scripts(fs_root)
|
||||
report["elf_binaries"] = self.find_elf_binaries(fs_root)[:50]
|
||||
report["iocs"] = self.extract_strings_iocs(fs_root)
|
||||
else:
|
||||
report["filesystem"] = "No filesystem root found"
|
||||
|
||||
report_path = self.output_dir / "firmware_analysis_report.json"
|
||||
with open(report_path, "w") as f:
|
||||
json.dump(report, f, indent=2, default=list)
|
||||
print(json.dumps(report, indent=2, default=list))
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: agent.py <firmware_image> <output_dir>")
|
||||
sys.exit(1)
|
||||
agent = FirmwareAnalysisAgent(sys.argv[1], sys.argv[2])
|
||||
agent.generate_report()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user