m
U-Boot(Universal Boot Loader),即通用Bootloader,是德国DENX小组开发的用于多种嵌入式CPU的bootloader程序
Legacy-uImage
在kernel镜像的基础上,加上64Byte的信息提供给uboot使用
binwalk分析一下,是Squashfs文件系统
Binwalk如何进行提取:
通过maigc特征集与文件进行比对,但识别效率比file命令高多了
binwalk -Me 解压得到
文件系统是操作系统的重要组成部分,是操作运行的基础。不同的路由器使用的文件系统格式不尽相同。根文件系统会被打包成当前路由器所使用的文件系统格式,然后组装到固件中。路由器希望文件系统越小越好,所以这些文件系统中各种压缩格式随处可见。
Squashfs是一个只读格式的文件系统,具有超高压缩率,其压缩率最高可达34%。当系统启动后,会将文件系统保存在一个压缩过的文件系统文件中,这个文件可以使用换回的形式挂载并对其中的文件进行访问,当进程需要某些文件时,仅将对应部分的压缩文件解压缩。
Squashfs文件系统常用的压缩格式有GZIP、LZMA、LZO、XZ(LZMA2)。路由器的根文件系统通常会按照Squashfs文件系统常用压缩格式中的一种进行打包,形成一个完整的Squashfs文件系统,然后与路由器操作系统的内核一起形成更新固件。
由于squashFS可以在不需要解压的情况下直接挂载,因此有许多应用场景,例如: 1、安装Linux时用的live cd 2、小型嵌入式设备中的rootfs。rootfs一般以压缩好的形式存放在ROM中,如果开机时把整个rootfs都解压到内存里再读取,对于ROM和RAM容量一般都很小的小型嵌入式设备来说性价比太低。
0x2 静态分析
从Dlink固件里面提取样本,打开发现被加密了。
如生成字典用的crunch、rsmangler,爆破用的frackzip等
直接使用教程的密码beUT9Z,解压如下
- .mbn:高通的一套用于加载网络环境的文件(modem software configuration)
- .yaffs2:针对NAND芯片设计的嵌入式文件系统,可用unyaffs提取
核心应该是2K-mdm-image-mdm9625.yaffs2,用unyaffs提取
1 | unyaffs 2K-mdm-image-mdm9625.yaffs2 yaffs2-root/ |
接下来我们查找该路径下的所有.conf文件,.conf文件多是配置文件,有可能从中可以发现敏感的信息。
1 | find . -name '*.conf' |
其中的inadyn-mt.conf文件引起了我们注意,这是no-ip应用的配置文件,no-ip就是一个相当于花生壳的东西,可以申请动态域名。我们从中可以发现泄露的no-ip的登陆账号及密码。
我们还从shadow文件中找到了root账号的密码,通过爆破可以得到root的密码为1234。
接下来使用firmwalker来自动化遍历固件系统中的所有可疑文件。
1 | git clone https://github.com/craigz28/firmwalker.git |
Firmwalker是一个bash脚本,用于扫描从IoT固件提取的文件以查看它们是否容易受到攻击。唯一的要求是该工具和提取的固件文件应位于同一文件夹中。
将它们放置在相同的位置后,由Firmwalker生成的输出文件-Firmwalker.text-将突出显示潜在问题的列表,可以是以下任意一个:
etc / ssl目录
etc / passwd和etc / shadow
配置,脚本和其他.bin文件
关键字,例如远程,管理员,密码等。
常见的二进制文件,例如dropbear,tftp和ssh
物联网设备上存在的常见Web服务器
随机IP地址,电子邮件ID和URL
使用Shodan CLI调用Shodan API的实验功能
面临任何这些问题的所有物联网设备都容易受到攻击。
1 | ./firmwalker.sh yaffs2-root/ |
除了配置文件外,分析存在风险的二进制程序也很重要。查看自启动的程序,在etc/init.d目录下存放启动时运行的程序和脚本,一个start_appmgr脚本引起了我们注意,mgr一般就是主控程序的意思。
查看脚本,该脚本会在开机的时候以服务的形式运行/bin/appmgr程序。
用IDA打开该文件
发现一个后门,这个漏洞被收录到CVE-2016-10178
只要连接该固件的39889端口并发送HELODBG的字符串,就可以进行远程执行命令。
动态调试
采用Attify
1 | ./fat.py '/home/iot/Documents/DWP2360b-firmware-v206-rc018.bin' |
通过192.168.0.50即可访问固件
调试固件
用到了Damn Vulnerable Router Firmware这个项目
先用binwalk解压
提取出来的目录里有个文件夹pwnable,里面存放着漏洞程序示例,选取stack_bof_01程序进行实验,程序的源代码可以在DVRF/Pwnable Source/Intro/里查看
先用readelf查看文件信息,mips架构 小端序。。。
文件的主要逻辑:strcpy造成了栈溢出,存在后门函数。
动调
拷贝wmu-mipsel-static到固件根目录
1 | cp (which qemu-mipsel-static) . |
用qemu虚拟运行stack_bof_01:
以调试的方式启动程序,并在1234端口进行监听:
1 | sudo chroot . ./qemu-mipsel-static -g 1234 ./pwnable/Intro/stack_bof_01 1111 |
打开一个新的shell,运行以下命令:
1 | gdb-multiarch pwnable/Intro/stack_bof_01 |
计算偏移
v
1 | iot@attifyos ~/D/D/F/_/squashfs-root> |
如果直接把跳转地址设置为后门函数dat_shell的起始地址0x400950会触发异常
程序成功跳转至dat_shell,但依旧崩溃,因为我们溢出的时候把 $gp 寄存器也覆盖了,$gp 寄存器是用来全局指针寻址用的,覆盖了他就会导致程序无法正常寻址,自然程序就会 crash。
查询MIPS指令集,MIPS跳转方式:
1.设置t9寄存器数值,跳转到t9寄存器;
2.在执行某个函数之前,将要跳转的地址保存在ra寄存器中,执行函数后可跳转。
qemu不能vmmap。
ida打开libc.so.0
在MIPS中,函数内部会通过t9寄存器和gp寄存器来找数据,地址等。同时在mips的手册内默认$t9的值为当前函数的开始地址,
如果在执行00400958 addu $gp, $t9是手动把$t9改成0x00400950,后面就正常了。
所以现在需要找一个gadget,通过t9跳转过去,这也是mips常规的用法,比如main开头调用memet。
sp:MIPS架构中,栈是向下增长的,也就是栈底在高地址,栈顶在低地址。在图3-2中,GPR[sp]代表通用寄存器sp($29)指向栈顶,又称sp为栈指针(stack pointer)
其偏移0x6b20处确实有一个gadget
1 | .text:00006B20 00 00 B9 8F lw $t9, arg_0($sp) |
p &memset #查看memset地址,为0x408b6e10。(友情提示,需要在memset处下断点,运行至memset,不然由于之前没有运行memset,memset地址为其got地址)
ida打开libc.so.0,查看memset偏移为0x0001BE10
则libc基地址为:0x408b6e10-0x0001BE10=0x4089b000
gadget地址为 :0x4089b000+0x6b20=0x408a1b2
payload
1 | python2 -c "print 'a'*204+'\x20\x1b\x8a\x40'+'\x50\x09\x40\x00'" > payload |
getshell
修复固件运行环境
有一些固件因为硬件依赖等原因导致qemu和firmadyne之类的软件无法正确模拟
模拟固件运行的实质其实就是把固件的Web程序跑起来,而模拟失败则说明Web程序运行出错了,我们接下来就要看看Web程序报错的原因以及如何修复运行环境。
拿到dir605L_FW_113.bin固件
binwalk解析,进入文件系统目录squashfs-root-0,找到web服务程序Boa (在bin目录下
Boa程序是一个轻量级的web服务器程序,常见于嵌入式系统中。dlink就是在boa开源代码的基础上新增了很多功能接口以实现路由器上的不同功能。boa程序的路径为/bin/boa,同时我们发现在/etc/boa路径下还有个boa的密码配置文件,我们可以直接获取到boa加密后的密码。
1 | cp (which qemu-mips-static) . |
注:APMIB 是个Realtek(网卡?)的玩意
由于没有flash,导致读mib失败
拖到反编译工具中分析。先定位到字符串“Initialize AP MIB failed!”的位置。注意到在输出这个字符串前有个调用APMIB初始化的跳转,在此下断点,
IDA gdbserver远程调试
QEMU的远程调试不需要gdbserver,-g 指定端口,ida 远程调试选项指定相应端口就行
1 | sudo chroot . ./qemu-mips-static -g 23946 bin/boa |
BNEZ是branch not equal to zero
条件转移指令,当寄存器中内容不为0时转移发生
apmib_init
函数返回 0
导致了这个错误
编写劫持函数动态库:
在apmib.so函数里面。
直接写一个动态库 apmib_init
函数返回 1
劫持
1 |
|
编译
1 | mips-linux-gnu-gcc -Wall -fPIC -shared apmib.c -o apmib-ld.so |
然后运行 -E优先选择我们的so文件
1 | sudo chroot ./ ./qemu-mips-static -E LD_PRELOAD="./apmib-ld.so" ./bin/boa |
但是依旧报错
再次动调发现我们的 apmib_get
函数时出错了
可以将 apmib.so
直接拖出来 IDA32
分析一下 apmib_get
函数
https://jyhshin.pixnet.net/blog/post/47162002-realtek-apmib-libraryapmib_get()
, 讀取 RAM
的 mib
值qemu
模拟不了与硬件交互的情况,所以读取不到
重新写
1 |
|
再次编译
查看 Wizard_Easy_LangSelect.asp
代码,猜测 hw
是 hardware
缩写,所以应该是跟硬件交互
1 | var hw_version="<%getInfo("hwVersion")%>"; |
魔改入口网页 first.asp
1 | <html> |
如此便恢复完毕,网页可以访问。
接下来就可以挖洞了哇