从案例中学习 IoT 固件仿真——D-Link DIR-605L(FW_113) 运行环境修复
ve1kcon 发表于 北京 IoT安全 1319浏览 · 2024-12-03 15:57

提取文件系统

当我们需要对固件进行分析、分离等操作,以实现提取文件系统的目的时,Binwalk 这个工具能够有效帮助我们自动化地分析、提取和识别固件映像中的文件和组件

安装方式:下载压缩包 https://github.com/ReFirmLabs/binwalk/archive/refs/tags/v2.3.4.zi

sudo python3 setup.py install

检查安装是否成功,若环境搭建成功则显示如下内容

$ binwalk -h

Binwalk v2.3.3
Craig Heffner, ReFirmLabs
https://github.com/ReFirmLabs/binwalk

Usage: binwalk [OPTIONS] [FILE1] [FILE2] [FILE3] ...

这里贴一种可能的报错情况,网上很难找到解决方案

Traceback (most recent call last):
  File "/usr/local/bin/binwalk", line 4, in <module>
    __import__('pkg_resources').run_script('binwalk==2.3.3', 'binwalk')
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 656, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 1453, in run_script
    exec(code, namespace, namespace)
  File "/usr/local/lib/python3.10/dist-packages/binwalk-2.3.3-py3.10.egg/EGG-INFO/scripts/binwalk", line 2, in <module>
    from binwalk.__main__ import main
  File "/usr/local/lib/python3.10/dist-packages/binwalk-2.3.3-py3.10.egg/binwalk/__main__.py", line 24, in <module>
    import binwalk.modules
  File "/usr/local/lib/python3.10/dist-packages/binwalk-2.3.3-py3.10.egg/binwalk/modules/__init__.py", line 3, in <module>
    from binwalk.modules.disasm import Disasm
  File "/usr/local/lib/python3.10/dist-packages/binwalk-2.3.3-py3.10.egg/binwalk/modules/disasm.py", line 21, in <module>
    class Disasm(Module):
  File "/usr/local/lib/python3.10/dist-packages/binwalk-2.3.3-py3.10.egg/binwalk/modules/disasm.py", line 60, in Disasm
    Architecture(type=capstone.CS_ARCH_ARM64,
AttributeError: module 'capstone' has no attribute 'CS_ARCH_ARM64'. Did you mean: 'CS_ARCH_ARM'?

摸索一番后,解决方案如下

sudo pip3 uninstall capstone

D-Link DIR-605L(FW_113) 这个固件可以从 D-Link 官方技术支持网站获取,下载链接如下

https://support.dlink.com/resource/products/dir-605l/REVA/DIR-605L_FIRMWARE_1.13.ZIP

解压缩后得到固件 dir605L_FW_113.bin,使用 Binwalk 对固件中的文件系统进行提取

binwalk -Me dir605L_FW_113.bin

运行后,发现缺少因缺少 sasquatch 导致报错,无法提取出文件系统

需要安装 sasquatch,从 github 上下载这个项目 devttys0/sasquatch,执行 sudo ./build.sh

编译时出现报错

Hunk #1 succeeded at 32 with fuzz 1.
cc -g -O2  -I. -I./LZMA/lzma465/C -I./LZMA/lzmalt -I./LZMA/lzmadaptive/C/7zip/Compress/LZMA_Lib -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"gzip\" -Wall -Werror  -DGZIP_SUPPORT -DLZMA_SUPPORT -DXZ_SUPPORT -DLZO_SUPPORT -DXATTR_SUPPORT -DXATTR_DEFAULT   -c -o unsquashfs.o unsquashfs.c
unsquashfs.c: In function ‘read_super’:
unsquashfs.c:1835:5: error: this ‘if’ clause does not guard... [-Werror=misleading-indentation]
 1835 |     if(swap)
      |     ^~
unsquashfs.c:1841:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
 1841 |         read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
      |         ^~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [<builtin>: unsquashfs.o] Error 1

解决方法如下

git clone --quiet --depth 1 --branch "master" https://github.com/devttys0/sasquatch
cd sasquatch
wget https://github.com/devttys0/sasquatch/pull/51.patch && patch -p1 <51.patch
sudo ./build.sh

再次 binwalk 一下,即可将固件中的文件系统提取出来,搜索需要分析的目标 httpd 服务器 boa

find ./ -name boa

劫持函数动态库

解包以后,在根目录下执行固件文件系统里的 /bin/boa 这个程序。根据程序输出的报错信息,去定位异常函数

apt-get install qemu binfmt-support qemu-user-static
cp $(which qemu-mips) ./
sudo chroot ./qemu-mips ./bin/boa

初次运行 boa 的错误提示信息如下

Initialize AP MIB failed!
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
[1]    89697 segmentation fault  sudo chroot . ./qemu-mips-static ./bin/boa

拖进 IDA 看下这个报错信息,shift + f12 打开字符串视窗,搜索 Initialize AP MIB failed! 字符串

点进去后 ctrl + x 查看对字符串的引用

websAspInit() 函数中被调用

通过分析程序逻辑,要使得 apmib_init() 函数返回值为 ture,才能使程序继续运行。到 GitHub 看了源码后发现此函数的功能绝大部分与漏洞研究无关,都是进行一系列初始化和相关配置检查,链接如下

https://github.com/luminais/ecos_http/blob/9cb66a1085d8519f536b493aedb4ea8b477972aa/rtk/ecos-work/AP/apmib/apmib.c#L1087

所以在硬件缺失的前提下,我们面对这种对我们”下绊字“的函数,可以直接替换,即重新编写一个新的 apmib_init() 函数去调用,劫持原本的函数

系统调用劫持 apmib.c 的代码如下

#include<stdio.h>
#include<stdlib.h>
int ampib_init(void)
{
     //Fake it.
     return 1;
}

需要安装交叉编译器 gcc-mips-linux-gnu,用于生成 MIPS 架构的 Linux 操作系统可执行文件

sudo apt install gcc-mips-linux-gnu

编译指令如下

mips-linux-gnu-gcc ./apmib.c -o apmib-ld.so -fPIC -shared

通过动态调试定位 Crash

将编译好的 apmib-ld.so 动态链接库复制到 DIR-605L 路由器根文件系统的根目录下

这里需要注意的是使用共享库编译的,所以需要把交叉编译环境下的 libgcc_s.so.1 动态库复制到 DIR-605L 路由器根文件系统的 lib 目录下。复制本机动态库文件到固件文件系统里的命令如下,复现时需要按需修改文件系统的目录

cp /usr/lib/i386-linux-gnu/libgcc_s.so.1 ~/work/IoT/DIR-605L/_dir605L_FW_113.bin.extracted/squashfs-root-0/lib/

然后使用 LD_PRELOAD 环境变量加载 apmib-ld.so ,劫持 apmib.so 中的 apmib_init() 函数。如下,上述报错已被修复,但是出现了新的报错信息 Create chklist file error!,但无需理会这一个报错,真正需要关注的是后面触发的 Crash 导致的程序退出,所以需要调试程序是运行到哪一步时出现问题

这里可以通过 IDA 进行远程调试,在目标固件仿真运行的机子上执行命令

sudo chroot ./ ./qemu-mips-static -E LD_PRELOAD="/apmib-ld.so" -g 1234  ./bin/boa

将 boa 拖入 IDA 进行反编译

选择 Debugger -> Select debugger…,选择 Remote GDB debugger

然后选择 Debugger -> Process options…,然后填写地址和端口号

apmib_init() 函数中断下以后,使用快捷键 F8 进行单步调试,调试到对 apmib_get() 函数时程序崩溃

真正触发程序崩溃的是 0x43B1A4 处的指令

因此,我们还需要劫持 apmib_get() 函数。查看 apmib.soapmib_get() 函数的汇编代码,通过对代码功能的分析,将 boa 中的 fork 函数一并劫持,形成最终的 boa 劫持代码,具体代码如下

#include<stdio.h>
#include<stdlib.h>
#define MIB_IP_ADDR  170
#define MIB_HW_VER   0x250
#define MIB_CAPTCHA  0x2C1

int apmib_init(){
    //Fake it.
    return 1;
}

int fork(void)
{
    return 0;
}

void apmib_get(int code, int *value)
{
    switch(code)
    {
       case MIB_HW_VER:
            *value = 0xF1;
            break;
       case MIB_IP_ADDR:
            *value = 0x7F000001;
             break;
       case MIB_CAPTCHA:
            *value = 1;
            break;
    }
    return;

}

编译最终的 apmib.c,生成 apmib-ld.so,命令如下

mips-linux-gnu-gcc ./apmib.c -o apmib-ld.so -fPIC -shared

将生成的 apmib-ld.so 复制到 DIR-605L 路由器的根文件系统下,然后使用下面的命令运行 boa

squashfs-root-0 sudo chroot ./ ./qemu-mips-static -E LD_PRELOAD="/apmib-ld.so"  ./bin/boa

直接访问目标地址发现访问拒绝连接

需要改动 web 目录下的 first.asp 文件

这里将代码 self.location.href="Basic/Wizard_Easy_LangSelect.asp"; 注释掉,然后将 self.location.href="Basic/Wizard_Easy_Welcome.asp"; 复制到 else 代码块

最终代码如下

<html>
<head>
</head>
<% getLangInfo("LangPathWizard");%>
<script>
function init()
{
    var ecflag = <% getIndexInfo("enableecflag") %>;
    if(ecflag == 0)
    {
        if((LangCode == "SC")||(LangCode == "TW"))
        {
            self.location.href="Basic/Wizard_Easy_Welcome.asp";
        }
        else
        {
            // self.location.href="Basic/Wizard_Easy_LangSelect.asp";
            self.location.href="Basic/Wizard_Easy_Welcome.asp";
        }
    }
    else
    {
        self.location.href="index.asp";
    }
}
</script>
<body onLoad="init();">
</html>

运行 boa 程序

最后再运行命令

sudo chroot ./ ./qemu-mips-static -E LD_PRELOAD="/apmib-ld.so"  ./bin/boa

成功将固件的 httpd 服务,即 boa 程序的仿真运行环境搭建起来,效果如下

4 条评论
某人
表情
可输入 255