Contents
  1. 1. 环境安装
  2. 2. 固件下载
  3. 3. binwalk提取
  4. 4. ida调试
    1. 4.1. ubuntu安装ida pro
    2. 4.2. 调试mips文件
      1. 4.2.1. XXXXX咋分析???

分析D-Link DIR-605L路由器中的web应用程序boa为例
(根据《揭秘家用路由器0day漏洞挖掘技术》,以下简称《揭秘》)

环境安装

上篇有讲过

固件下载

http://support.dlink.com.cn/ProductInfo.aspx?m=DIR-605L

binwalk提取

1
$ binwalk -e DIR605L\(W\)A1_FW114CNB05.bin

binwalk 会在当前目录下新建 _xxxxx.bin 目录,里面存放提取出来的固件里的所有内容,squashfs-root目录是我们需要的固件文件系统,第一次不知道也没有关系,可以直接寻找

1
2
3
4
5
6
kk@ubuntu:~/Desktop/iot/dlink605/_DIR605L(W)A1_FW114CNB05.bin.extracted$ sudo find / -name boa
[sudo] password for kk:
find: ‘/run/user/1000/gvfs’: Permission denied
/home/kk/Desktop/iot/dlink605/_DIR605L(W)A1_FW114CNB05.bin.extracted/squashfs-root-0/etc/boa
/home/kk/Desktop/iot/dlink605/_DIR605L(W)A1_FW114CNB05.bin.extracted/squashfs-root-0/bin/boa
/home/kk/tools/buildroot/package/boa
1
2
3
kk@ubuntu:~/Desktop/iot/dlink605/_DIR605L(W)A1_FW114CNB05.bin.extracted/squashfs-root-0$ cp $(which qemu-mips) ./
kk@ubuntu:~/Desktop/iot/dlink605/_DIR605L(W)A1_FW114CNB05.bin.extracted/squashfs-root-0$ sudo chroot ./qemu-mips ./bin/boa
chroot: cannot change root directory to './qemu-mips': Not a directory

出现报错
参考 https://xz.aliyun.com/t/6071#toc-3 的解决方法,使用相关指令来替代

1
2
qemu-mips   --> qemu-mips-static
qemu-mipsel --> qemu-mipsel-static
1
$ sudo apt-get install qemu binfmt-support qemu-user-static

然后替换

1
2
3
4
5
$ cp $(which qemu-mips-static) ./
$ sudo chroot ./ ./qemu-mips-static ./bin/boa
Initialize AP MIB failed!
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault (core dumped)

发现错误信息。
IDA调试boa,在windows上调试比较麻烦

ida调试

ubuntu安装ida pro

ida pro for linux的安装包:链接: https://pan.baidu.com/s/1qFtlhfc3aXsuFNHRlSHAMg 提取码: tnut
解压

1
$ unzip -o -d ./ ./IDA_Pro_v6.4_\(Linux\)_and_Hex-Rays_Decompiler_\(ARM\).zip

安装32bit的依赖包

1
$ sudo apt-get install libc6-i686:i386 libexpat1:i386 libffi6:i386 libfontconfig1:i386 libfreetype6:i386 libgcc1:i386 libglib2.0-0:i386 libice6:i386 libpcre3:i386 libpng12-0:i386 libsm6:i386 libstdc++6:i386 libuuid1:i386 libx11-6:i386 libxau6:i386 libxcb1:i386 libxdmcp6:i386 libxext6:i386 libxrender1:i386 zlib1g:i386 libx11-xcb1:i386 libdbus-1-3:i386 libxi6:i386 libsm6:i386 libcurl3:i386
  • 如果遇到报错,例如这样的:
    1
    libglu1-mesa:i386 : Depends: libgl1-mesa-glx:i386 but it is not going to be installed or libgl1:i386

可以尝试换源解决

1
$ ./idaq64

即可

调试mips文件

1
$ sudo chroot ./ ./qemu-mips-static -g 1234 ./bin/boa

打开ida,查找到报错字符串Initialize AP MIB failed!位置,在jalr $t9; _apmib_init下断点。
将ida设置为gdb调试器,配置页面将ip设置为虚拟机ip,端口设置为1234。开启动态调试.

列几个用到的汇编指令【mips汇编我是用到就查…不确定我的理解对不对哈】

  1. jalr oprd1 oprd2;
    无条件跳转到由寄存器 oprd1 存储的地址,并将下一条指令的地址保存到寄存器 oprd2(默认为31)中
  2. bnez r1,name;
    r1不等于0,程序跳转,以name为偏移地址
  3. 寄存器$v0 - $v1(Value简写)存储表达式或者是函数的返回值

所以上面那段代码,在0x004187B0处执行_apmib_init,v0就是返回值,如果返回值不为0,就跳转到下面的0x004187E4处,否则,继续向下。

函数_apmib_init的返回值为0,所以会进入”Initialize AP MIB failed!”
更改执行流,一个思路就是使该函数的返回值 != 0 ,这样就可以进入0x004187E4,绕开错误。

_apmib_init对应的动态链接库为apmib.so,我们尝试分析这个so文件。(可以写脚本查找函数名输出对应so文件)

XXXXX咋分析???

改写apmib.so,编写apmib.c

1
2
3
4
5
6
7
#include<stdio.h>
#include<stdlib.h>

int apmib_init(void)
{
return 1;
}

虽然ida中显示的函数是_apmib_init(),但是实际上经过测试,函数名还是apmib_init()【可在so文件查看】,改写_apmib_init并不会成功。

需要使用mips-linux-gcc进行编译,但是我们前面环境配置时,buildroot都是mipsel小端序,我们的编译选项是没有mips的,那么如何编译大端序呢?—>需要加上 -EB 选项,而且需要编译和链接分两步走,如:

1
2
mipsel-linux-gcc demo.c -EB -c -static -o demo1    编译
mipsel-linux-ld demo1 -EB -o demo 链接

所以我们执行:

1
2
$ mipsel-linux-gcc apmib.c -EB -c -static -o apmib
$ mipsel-linux-ld -fPIC -shared -EB apmib -o apmib-ld.so

接着将新生成的so文件复制到squashfs-root-0目录下。《揭秘》中写道,因为这里是使用共享库编译,所以需要把交叉编译环境下的libgcc_s.so.1动态库复制到根文件系统lib目录下。但是实际上我并没有复制这一文件,同样成功。
使用LD_PRELOAD环境变量加载apmib-ld.so,劫持apmib.so中的apmib_init()函数:

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


成功劫持,错误信息已经不再是Ini......!,但是依然有错,为此,我们还需要进一步调试,看看又是哪里出了问题。

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

进入ida调试

apmib.c修改为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<stdio.h>
#include<stdlib.h>
#define MIB_IP_ADDR 170
#define MIB_HW_VER 0x250
#define MIB_CAPTCHA 0x2c1

int apmib_init(void)
{
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;
}

执行和前面一样的操作生成新的so文件

同时

1
netstat -an|grep 80

发现新开启了80端口

参考:
https://xz.aliyun.com/t/6071#toc-3
https://xz.aliyun.com/t/3826#toc-5
分析固件so中的问题函数