firmadyne/firmadyne
GitHub: firmadyne/firmadyne
用于对基于 Linux 的嵌入式固件进行自动化模拟和动态分析的系统平台。
Stars: 2047 | Forks: 360
# 目录
- [目录](#table-of-contents)
- [简介](#introduction)
- [安装设置](#setup)
- [提取器](#extractor)
- [数据库](#database)
- [二进制文件](#binaries)
- [QEMU](#qemu)
- [使用方法](#usage)
- [常见问题](#faq)
- [run.sh 未生成](#runsh-is-not-generated)
- [日志以 "Kernel panic - not syncing: No working init found" 结束](#log-ends-with-kernel-panic---not-syncing-no-working-init-found)
- [进程崩溃,例如 do_page_fault() #2: sending SIGSEGV for invalid read access from 00000000](#a-process-crashed-eg-do_page_fault-2-sending-sigsegv-for-invalid-read-access-from-00000000)
- [如何调试模拟的固件?](#how-do-i-debug-the-emulated-firmware)
- [从源码编译](#compiling-from-source)
- [工具链](#toolchain)
- [console](#console)
- [libnvram](#libnvram)
- [内核](#kernel)
- [ARM](#arm)
- [MIPS](#mips)
- [数据库](#database-1)
- [数据](#data)
- [架构](#schema)
- [论文](#paper)
# 简介
FIRMADYNE 是一个用于执行基于 Linux 的嵌入式固件的模拟和动态分析的自动化且可扩展的系统。它包括以下组件:
* 修改版内核(MIPS:[v2.6](https://github.com/firmadyne/kernel-v2.6),
ARM:[v4.1](https://github.com/firmadyne/kernel-v4.1),
[v3.10](https://github.com/firmadyne/kernel-v3.10))用于固件执行的插桩;
* 一个用户空间的 [NVRAM 库](https://github.com/firmadyne/libnvram)用于模拟硬件 NVRAM 外设;
* 一个 [提取器](https://github.com/firmadyne/extractor)用于从下载的固件中提取文件系统和内核;
* 一个小型的 [console](https://github.com/firmadyne/console) 应用程序,用于生成一个额外的 Shell 以便调试;
* 以及一个 [爬虫](https://github.com/firmadyne/scraper),用于从 42 个以上不同的供应商下载固件。
我们还使用 FIRMADYNE 系统编写了以下三个基本的自动化分析。
* 可访问的网页:此脚本遍历固件镜像文件系统中似乎由 Web 服务器提供的每个文件,并根据它们是否需要认证来汇总结果。
* SNMP 信息:此脚本在不使用凭据的情况下,将 `public` 和 `private` SNMP v2c community 的内容转储到磁盘。
* 漏洞检查:此脚本使用来自 Metasploit 的 exploit 测试 60 个已知漏洞是否存在。此外,它还检查我们发现的 14 个以前未知的漏洞。
有关更多信息,包括受影响的产品和 CVE,请参阅 [analyses/README.md](https://github.com/firmadyne/firmadyne/blob/master/analyses/README.md)。
在我们 2016 年的 [网络与分布式系统安全研讨会 (NDSS)](http://www.internetsociety.org/events/ndss-symposium) 论文中,题为 [Towards Automated Dynamic Analysis for Linux-based Embedded Firmware](https://github.com/firmadyne/firmadyne/blob/master/paper/paper.pdf),我们在包含 23,035 个固件镜像的数据集上评估了 FIRMADYNE 系统,其中我们能够提取 9,486 个。使用来自 [Metasploit Framework](https://github.com/rapid7/metasploit-framework) 的 60 个 exploit 以及我们发现的 14 个以前未知的漏洞,我们表明 1,971 个固件镜像中有 846 个 (43%) 至少容易受到一种 exploit 的攻击,我们估计这会影响 89 种以上不同的产品。有关更多详细信息,请参阅上面链接的论文。
**注意**:该项目是一个研究工具,目前尚未达到生产就绪状态。特别是,某些组件还相当不成熟和粗糙。我们建议在虚拟机中运行该系统。我们不提供支持,但非常感谢 Pull Request,无论是文档、测试还是代码!
# 安装设置
首先,递归克隆此仓库并安装其依赖项。
1. `sudo apt-get install busybox-static fakeroot git dmsetup kpartx netcat-openbsd nmap python-psycopg2 python3-psycopg2 snmp uml-utilities util-linux vlan`
2. `git clone --recursive https://github.com/firmadyne/firmadyne.git`
## 提取器
提取器依赖于 [binwalk](https://github.com/ReFirmLabs/binwalk) 工具,因此我们需要安装它及其依赖项。
1. `git clone https://github.com/ReFirmLabs/binwalk.git`
2. `cd binwalk`
3. `sudo ./deps.sh`
4. `sudo python ./setup.py install`
* 对于 Python 2.x,`sudo apt-get install python-lzma`
4. `sudo -H pip install git+https://github.com/ahupp/python-magic`
5. `sudo -H pip install git+https://github.com/sviehb/jefferson`。
6. (可选)代替 [upstream sasquatch](https://github.com/devttys0/sasquatch),
可以使用我们的 [sasquatch fork](https://github.com/firmadyne/sasquatch),通过将错误设为致命错误来防止误报。
## 数据库
接下来,安装、设置并配置数据库。
1. `sudo apt-get install postgresql`
2. `sudo -u postgres createuser -P firmadyne`,密码为 `firmadyne`
3. `sudo -u postgres createdb -O firmadyne firmware`
4. `sudo -u postgres psql -d firmware < ./firmadyne/database/schema`
## 二进制文件
要下载我们为所有组件预构建的二进制文件,请运行以下脚本:
* `cd ./firmadyne; ./download.sh`
或者,参考[下面](#compiling-from-source)的说明从源码编译。
## QEMU
要使用您发行版提供的 [QEMU](http://wiki.qemu.org/Main_Page):
* `sudo apt-get install qemu-system-arm qemu-system-mips qemu-system-x86 qemu-utils`
请注意,目前不支持模拟基于 x86 的固件,但安装 `qemu-system-x86` 可以解决某些基于 Debian 的发行版上的打包问题。
或者,使用我们的 [qemu-linaro](https://git.linaro.org/?p=qemu/qemu-linaro.git) 的[修改版本](https://github.com/firmadyne/qemu-linaro),用于某些具有 `alphafs` Web 服务器且假定固定内存映射的固件(不推荐),或使用 [upstream qemu](https://github.com/qemu/qemu)。
# 使用方法
1. 在 `firmadyne.config` 中设置 `FIRMWARE_DIR` 以指向此仓库的根目录。
2. 下载一个固件镜像,例如 [Netgear WNAP320](https://www.netgear.com/support/product/WNAP320.aspx) 的 [v2.0.3](http://www.downloads.netgear.com/files/GDC/WNAP320/WNAP320%20Firmware%20Version%202.0.3.zip)。
* `wget http://www.downloads.netgear.com/files/GDC/WNAP320/WNAP320%20Firmware%20Version%202.0.3.zip`
3. 使用提取器仅恢复文件系统,不提取内核 (`-nk`),不并行操作 (`-np`),使用 `Netgear` 品牌 (`-b`) 填充位于 `127.0.0.1` 的 SQL 服务器中的 `image` 表 (`-sql`),并将压缩包存储在 `images` 中。
* `./sources/extractor/extractor.py -b Netgear -sql 127.0.0.1 -np -nk "WNAP320 Firmware Version 2.0.3.zip" images`
4. 识别固件 `1` 的架构并将结果存储在数据库的 `image` 表中。
* `./scripts/getArch.sh ./images/1.tar.gz`
5. 将固件 `1` 的文件系统内容加载到数据库中,填充 `object` 和 `object_to_image` 表。
* `./scripts/tar2db.py -i 1 -f ./images/1.tar.gz`
6. 为固件 `1` 创建 QEMU 磁盘镜像。
* `sudo ./scripts/makeImage.sh 1`
7. 推断固件 `1` 的网络配置。内核消息记录到 `./scratch/1/qemu.initial.serial.log`。
* `./scripts/inferNetwork.sh 1`
8. 使用推断出的网络配置模拟固件 `1`。这将通过创建 TAP 设备并添加路由来修改主机系统的配置。
* `./scratch/1/run.sh`
9. 系统应该可以通过网络访问,并准备好进行分析。内核消息被镜像到 `./scratch/1/qemu.final.serial.log`。固件 `1` 的文件系统可以使用 `./scripts/mount.sh 1` 和 `./scripts/umount.sh 1` 挂载到 `scratch/1/image` 和从该位置卸载。
* `./analyses/snmpwalk.sh 192.168.0.100`
* `./analyses/webAccess.py 1 192.168.0.100 log.txt`
* `mkdir exploits; ./analyses/runExploits.py -t 192.168.0.100 -o exploits/exploit -e x` (需要 Metasploit Framework)
* `sudo nmap -O -sV 192.168.0.100`
10. 默认控制台应自动连接到终端。您也可以使用 `root` 和 `password` 登录。请注意,`Ctrl-c` 被发送到客户机;使用 QEMU monitor 命令 `Ctrl-a + x` 终止模拟。
# 常见问题
## `run.sh` 未生成
这是当无法推断网络配置时遇到的常见错误。请按照下面的清单找出原因。
1. `inferNetwork.sh`:此脚本是否找到了任何网络接口(例如 `Interfaces: [br0, 192.168.0.1]`)?如果是,这是一个 bug;请报告。否则,请继续下面的步骤。
2. `qemu.initial.serial.log`:此文件是否以 `Unable to mount root fs on unknown-block(8,1)` 结尾?如果是,则初始文件系统镜像未使用 `kpartx` 正确生成。尝试删除此固件镜像对应的 scratch 目录,并从 `makeImage.sh` 重新开始。否则,初始模拟未产生任何有用的插桩信息。尝试将 `inferNetwork.sh` 中的超时时间从 `60` 增加到 `120` 并从 `inferNetwork.sh` 重新开始。
3. `qemu.initial.serial.log`:`init` 进程是否崩溃,并且在此之前是否有 NVRAM 操作失败(例如 `nvram_get_buf: Unable to open key `)?如果是,请参阅下面的常见问题解答条目。
## 日志以 "Kernel panic - not syncing: No working init found" 结束
固件使用了具有不常见名称的初始化进程。您需要手动检查文件系统以识别正确的进程,然后通过将内核启动参数 `init=` 附加到 QEMU 来修改脚本以指定其完整路径。
## 进程崩溃,例如 `do_page_fault() #2: sending SIGSEGV for invalid read access from 00000000`
这很可能是因为进程请求了一个 FIRMADYNE 没有默认值的 NVRAM 条目。可以通过手动向 `libnvram` 中的 `NVRAM_DEFAULTS_PATH` 添加 NVRAM 条目的来源、向 `NVRAM_DEFAULTS` 添加条目或向 `OVERRIDE_POINT` 添加文件来解决此问题。有关更多详细信息,请参阅 [libnvram 文档](https://github.com/firmadyne/libnvram)。请注意,前两个选项涉及修改 `config.h`,这将需要重新编译 `libnvram`。
## 如何调试模拟的固件?
1. 对于全系统 QEMU 模拟,为目标架构编译一个静态链接的 `gdbserver`,将其复制到文件系统中,将其附加到目标进程,然后使用 `gdb-multiarch` 进行远程连接。您需要一个交叉编译工具链;可以使用 Debian/Ubuntu 提供的 `crossbuild-essential-*` 软件包,使用例如 `buildroot` 从头开始构建,或者在线查找 GPL 源代码和/或预编译的二进制文件。如果您有 IDA Pro,则可以使用 IDA 的预编译调试服务器(位于安装目录的 `dbgsrv` 子目录中),尽管它们与 GDB 不兼容。
2. 对于全系统 QEMU 模拟,将 `-s -S` 参数传递给 QEMU,并使用 `gdb-multiarch` 中的 `target remote localhost:1234` 连接到存根。但是,调试器不会自动知道内核和用户空间在内存中的位置,因此您可能需要在 `gdb` 中手动执行 `add-symbol-file` 并在内核中的 `try_to_run_init_process()` 附近设置断点。
3. 对于用户模式 QEMU 模拟,`chroot` 进入固件镜像(可选),将 `LD_LIBRARY_PATH` 设置为包含 FIRMADYNE libnvram,并将 `-L` 参数与固件 `/lib` 目录的正确路径以及目标二进制文件一起传递给 QEMU。这最容易调试,因为您可以使用 `gdb-multiarch` 直接附加到进程,并与进程直接交互,但由于使用的是主机内核,系统状态可能不准确。这也有些不安全,因为模拟的固件可以访问主机文件系统并与主机内核交互。
# 从源码编译
如果您希望从头开始编译整个 FIRMADYNE 系统
而不使用我们预构建的二进制文件,请按照以下步骤操作。
## [工具链](https://github.com/GregorR/musl-cross)
为了 FIRMADYNE 使用的任何二进制文件,您需要以下架构三元组的三个交叉编译工具链。仅使用 [musl libc](http://www.musl-libc.org) 作为工具链的 C 运行时库;其他的尚未经过测试。
* arm-linux-musleabi
* mipseb-linux-musl
* mipsel-linux-musl
为了简化使用 musl 构建交叉编译工具链的过程,我们
推荐使用 [musl-cross](https://github.com/GregorR/musl-cross) 项目。
请按照以下步骤从源代码构建这些工具链,或者
点击[这里](https://zenodo.org/record/4922202)下载我们预构建的工具链。
1. `git clone https://github.com/GregorR/musl-cross.git`
2. 修改或设置 `defs.sh` 中的以下变量
* `BINUTILS_URL=http://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2`
* `GCC_VERSION=5.3.0`
* `GMP_VERSION=6.0.0a`
* `MPC_VERSION=1.0.2`
* `MPFR_VERSION=3.1.3`
* `LIBELF_VERSION=master`
* `MUSL_DEFAULT_VERSION=1.1.12`
* `MUSL_GIT_VERSION=615629bd6fcd6ddb69ad762e679f088c7bd878e2`
* `LANG_CXX=no`
* `GCC_BUILTIN_PREREQS=yes`
3. 修改或设置 `config.sh` 中的以下变量
* `CFLAGS="-fPIC"`
4. 对于小端 MIPS,请执行以下操作:
* 在 `config.sh` 中设置 `TRIPLE=mipsel-linux-musl`
* 在 `defs.sh` 中设置 `LINUX_HEADERS_URL=https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.4.tar.xz`
* 运行 `./clean.sh` 以清除任何先前的构建
* 运行 `./build.sh` 以构建工具链并将其安装到 `/opt/cross`
5. 对于大端 MIPS,请执行以下操作:
* 在 `config.sh` 中设置 `TRIPLE=mipseb-linux-musl`
* 在 `defs.sh` 中设置 `LINUX_HEADERS_URL=https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.4.tar.xz`
* 运行 `./clean.sh` 以清除任何先前的构建
* 运行 `./build.sh` 以构建工具链并将其安装到 `/opt/cross`
6. 对于小端 ARM,请执行以下操作:
* 在 `config.sh` 中设置 `TRIPLE=arm-linux-musleabi`、`GCC_BOOTSTRAP_CONFFLAGS="--with-arch=armv6 --with-float=softfp"` 和 `GCC_CONFFLAGS="--with-arch=armv6 --with-float=softfp"`
* 在 `defs.sh` 中设置 `LINUX_HEADERS_URL=https://kernel.org/pub/linux/kernel/v4.x/linux-4.1.17.tar.xz`
* 运行 `./clean.sh` 以清除任何先前的构建
* 运行 `./build.sh` 以构建工具链并将其安装到 `/opt/cross`
7. 您应该拥有以下目录,或者您安装工具链的任何位置:
* `/opt/cross/arm-linux-musleabi`
* `/opt/cross/mipseb-linux-musl`
* `/opt/cross/mipsel-linux-musl`
## [console](https://github.com/firmadyne/console)
1. `cd ./firmadyne/sources/console`
2. `make clean && CC=/opt/cross/arm-linux-musleabi/bin/arm-linux-musleabi-gcc make && mv console ../../binaries/console.armel`
3. `make clean && CC=/opt/cross/mipseb-linux-musl/bin/mipseb-linux-musl-gcc make && mv console ../../binaries/console.mipseb`
4. `make clean && CC=/opt/cross/mipsel-linux-musl/bin/mipsel-linux-musl-gcc make && mv console ../../binaries/console.mipsel`
## [libnvram](https://github.com/firmadyne/libnvram)
1. `cd ./firmadyne/sources/libnvram`
2. `make clean && CC=/opt/cross/arm-linux-musleabi/bin/arm-linux-musleabi-gcc make && mv libnvram.so ../../binaries/libnvram.so.armel`
3. `make clean && CC=/opt/cross/mipseb-linux-musl/bin/mipseb-linux-musl-gcc make && mv libnvram.so ../../binaries/libnvram.so.mipseb`
4. `make clean && CC=/opt/cross/mipsel-linux-musl/bin/mipsel-linux-musl-gcc make && mv libnvram.so ../../binaries/libnvram.so.mipsel`
## 内核
### [ARM](https://github.com/firmadyne/kernel-v4.1)
1. `git clone https://github.com/firmadyne/kernel-v4.1.git && cd kernel-v4.1`
2. `mkdir -p build/armel`
3. `cp config.armel build/armel/.config`
4. `make ARCH=arm CROSS_COMPILE=/opt/cross/arm-linux-musleabi/bin/arm-linux-musleabi- O=./build/armel zImage -j8`
5. `cp build/armel/arch/arm/boot/zImage ../firmadyne/binaries/zImage.armel`
### [MIPS](https://github.com/firmadyne/kernel-v2.6)
1. `git clone https://github.com/firmadyne/kernel-v2.6.git && cd kernel-v2.6`
2. 对于大端 MIPS,请执行以下操作:
1. `mkdir -p build/mipseb`
2. `cp config.mipseb build/mipseb/.config`
3. `make ARCH=mips CROSS_COMPILE=/opt/cross/mipseb-linux-musl/bin/mipseb-linux-musl- O=./build/mipseb -j8`
4. `cp build/mipseb/vmlinux ../firmadyne/binaries/vmlinux.mipseb`
3. 对于小端 MIPS,请执行以下操作:
1. `mkdir -p build/mipsel`
2. `cp config.mipsel build/mipsel/.config`
3. `make ARCH=mips CROSS_COMPILE=/opt/cross/mipsel-linux-musl/bin/mipsel-linux-musl- O=./build/mipsel -j8`
4. `cp build/mipsel/vmlinux ../firmadyne/binaries/vmlinux.mipsel`
# 数据库
在开发过程中,数据库存储在 PostgreSQL 服务器上。
## 数据
尽管我们无法重新分发二进制固件,但用于我们实验的数据可在[此处](https://zenodo.org/record/4922202)获取。
## [Schema](https://github.com/firmadyne/firmadyne/blob/master/database/schema)
以下是 Schema 中表格的描述。
* `brand`:存储每个供应商的品牌名称。
| Column | Description |
| ------ | ----------- |
| id | Primary key |
| name | Brand name |
* `image`:存储关于每个固件镜像的信息。
| Column | Description |
| ---------------- | -------------------------------------------- |
| id | Primary key |
| filename | File name |
| brand_id | Foreign key to `brand` |
| hash | MD5 |
| rootfs_extracted | Whether the primary filesystem was extracted |
| kernel_extracted | Whether the kernel was extracted |
| arch | Hardware architecture |
| kernel_version | Version of the extracted kernel |
* `object`:存储文件系统中每个文件的信息。
| Column | Description |
| ---------------- | ---------------------- |
| id | Primary key |
| hash | MD5 |
* `object_to_image`:将唯一文件映射到其固件镜像。
| Column | Description |
| ---------------- | --------------------------- |
| id | Primary key |
| oid | Foreign key to `object` |
| iid | Foreign key to `image` |
| filename | Full path to the file |
| regular_file | Whether the file is regular |
| permissions | File permissions in octal |
| uid | Owner's user ID |
| gid | Group's group ID |
* `product`
| Column | Description |
| ------------ | ------------------------------ |
| id | Primary key |
| iid | Foreign key to `image` |
| url | Download URL |
| mib_filename | Filename of the SNMP MIB |
| mib_hash | MD5 of the SNP MIB |
| mib_url | Download URL of the SNMP MIB |
| sdk_filename | Filename of the source SDK |
| sdk_hash | MD5 of the source SDK |
| sdk_url | Download URL of the source SDK |
| product | Product name |
| version | Version string |
| build | Build string |
| date | Release date |
# 论文
我们的[论文](https://github.com/firmadyne/firmadyne/blob/master/paper/paper.pdf)中讨论的结果是使用以下组件的预发布版本生成的:
* toolchains:
* `BINUTILS_URL=http://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2`, `GCC_VERSION=4.9.3`, `GMP_VERSION=6.0.0a`, `MPC_VERSION=1.0.2`, `MPFR_VERSION=3.1.3`, `LIBELF_VERSION=71bf774909fd654d8167a475333fa8f37fbbcb5d`, `MUSL_DEFAULT_VERSION=1.1.10`, `MUSL_GIT_VERSION=996d148bf14b477b07fa3691bffeb930c67b2b62`, `LANG_CXX=no`
* ARM: `LINUX_HEADERS_URL=https://kernel.org/pub/linux/kernel/v3.x/linux-3.10.84.tar.xz`
* MIPS: `LINUX_HEADERS_URL=https://kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.32/linux-2.6.32.67.tar.xz`
* kernels:
* ARM: [firmadyne-v3.10.92](https://github.com/firmadyne/kernel-v3.10/tree/firmadyne-v3.10.92)
* MIPS: [firmadyne-v2.6.32.68](https://github.com/firmadyne/kernel-v2.6.32/tree/firmadyne-v2.6.32.68) 不包含 `e2b9f315547ea50a65baad4899a4780078ab273e` 和 `26bb3636c987fc7e145af73ddea6c10fa93bdae9`
* console: [`c36ae8553fa4e9c82e8a65752906641d81c2360c`](https://github.com/firmadyne/console/commits/c36ae8553fa4e9c82e8a65752906641d81c2360c)
* extractor: [`5520c64bfa8554c5c17ab671aaed0fdeec91bf19`](https://github.com/firmadyne/extractor/commits/5520c64bfa8554c5c17ab671aaed0fdeec91bf19)
* libnvram: [`b60e7d4d576b39dd46107058adb635d43e80e00d`](https://github.com/firmadyne/libnvram/commits/b60e7d4d576b39dd46107058adb635d43e80e00d)
* qemu-linaro: [`4753f5e8126a00cc0a8559bfd9b47d6340903323`](https://github.com/firmadyne/qemu-linaro/commits/4753f5e8126a00cc0a8559bfd9b47d6340903323)
* binwalk: [`f2ce2992695fae5477c46980148c89e9c91a5cce`](https://github.com/ReFirmLabs/binwalk/commits/f2ce2992695fae5477c46980148c89e9c91a5cce)
* jefferson: [`090a33be0be4aac8eee8d825447c0eb18dc8b51a`](https://github.com/firmadyne/jefferson/commits/090a33be0be4aac8eee8d825447c0eb18dc8b51a)
* sasquatch: [`287e4a8e059d3ee7a5f643211fcf00c292cd6f4d`](https://github.com/firmadyne/sasquatch/commits/287e4a8e059d3ee7a5f643211fcf00c292cd6f4d)
标签:Cutter, IoT安全, Linux固件, MIPS, NVRAM模拟, QEMU, 云资产清单, 内联执行, 固件仿真, 固件分析, 固件提取, 嵌入式安全, 测试用例, 硬件安全, 网络安全, 身份验证强制, 逆向工具, 逆向工程, 隐私保护