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, 云资产清单, 内联执行, 固件仿真, 固件分析, 固件提取, 嵌入式安全, 测试用例, 硬件安全, 网络安全, 身份验证强制, 逆向工具, 逆向工程, 隐私保护