恢复D-Link DIR-605L(FW_113)固件运行环境的详细踩坑过程

前言

感觉iot这块最麻烦的还是仿真动态调试,因为硬件的缺失,固件的执行过程中总是会缺失部分内容,从而使得仿真、调试失败

这段时间研究的几个内存漏洞,普遍都有以下问题

  • qemu的仿真很难跑起来,经常因为网上搜索不到、自己不会找的原因而无法运行成功,过往的文章有些不需要内存层面的调试的,直接启动fat仿真起来就好,因为本身不需要怎么分析都能从代码逻辑上看明白为什么。但分析内存破坏漏洞就很难受了
  • 针对单个文件的漏洞进行的调试,尝试过qemu、qiling、fat、fat-plus之类的方法,但是gdb remote过去经常跑着跑着就崩溃了

感觉qiling是最人性化的,但可惜的是仍然因为某些原因,gdb远程调试很容易崩溃,然后fat-plus虽然仿真成功率还是ok的,但是每次都得传入gdbserver,而且也不一定ok

于是我花了实在很久很久,整整一周多,调试环境捣鼓来捣鼓去各种各样的,最后发现许多师傅其实直接用qemu就行,但是qemu又经常遭遇环境问题,发现自己除了能根据报错,在IDA上分析出来缺什么文件以外,有些问题,比如很常见的段错误一冒出来,就不太懂怎么解决

故希望通过《揭秘家用路由器0day利用技术》这本书,以及一些博客,来充实这部分的知识,遇到问题会优先自己来解决,实在不行再看书,但是发现这本书还是省略了超多细节啊,而细节对于二进制层面来说往往就是最重要的部分。

记录了一部分踩坑的过程,显得很啰嗦的话,希望师傅见谅

准备工作

下载固件:ftp://ftp2.dlink.com/PRODUCTS/DIR-605L/REVA/DIR-605L_FIRMWARE_1.13.ZIP

360的浏览器居然自带ftp访问的功能,不需要登陆上去还要看着目录翻文件,挺方便的

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

然后还有各类固件分析工具,此处不再赘述

直接仿真——失败

为了避免文件系统里面链接的丢失,建议在虚拟机里面进行解包,然后传出自己想分析的东西,

而不是wsl上binwalk解包完,拿出自己想要的东西然后再丢进虚拟机,不知道会不会有人踩过这个坑(

解包以后,书上说我们要执行/文件系统根目录/bin/boa这个程序,在根目录下

报错显示:

Initialize AP MIB failed!
qemu: uncaught target signal 11 (Segmentation fault) – core dumped
Segmentation fault

尝试修复报错

Break Off the Fork

fork产生的过多子进程,会导致调试的情况很复杂。直接顺带劫持一下,让其返回0即可

分析第一个报错原因

该提示对应的文件位置:

跟进,可以看到这个if判断不满足,就会弹出错误

但这是一个外部函数

显然可以grep,显然在最后一个

跟进以后发现短时间内捋清楚是一个有点困难的事情,作者也是这样想的,甚至没有给出怎么分析,

只好又用那一招了,对,找一个特别的函数名字,搜索github代码,运气不错,可以看这个,在https://github.com/luminais/ecos_http/blob/9cb66a1085d8519f536b493aedb4ea8b477972aa/rtk/ecos-work/AP/apmib/apmib.c#L1087,其主要逻辑在_apmib_init

首先,对于MIPS特有流水线机制,为__apmib_init实现了一个同步机制

接着跟进__apmib_init,前几行的逻辑是判断pMib指针是否NULL,NULL意味着没有初始化

如果未被初始化,那就走入linkchain逻辑,且看看这里进行了什么处理?

主要是检测了六个值是否被设置(ifdef那些),如果没有,就报错,

(这算运气成分吧,怎么学啊,能hijack的东西都试试吗,看到后面就明白了)

当然不能稀里糊涂的就跟着书本hijack成return 1啊,所以看了看GitHub源代码,发现这个函数主要做了这些事情,绝大部分都是漏洞研究无关的,都是用户与用户之间的通讯进行协调之类的事情,

  • 检查有没有wlanMacChain,wifi串联
  • RTK_MESH(一种类似于蓝牙的网络)的配置
  • HOME_GATEWAY,家庭网关的那些东西,初始化了端口前置的表,看起来就是Vpn那些东西
  • QoS rules table,初始化了用于改善服务质量规则的表
  • static route table,初始化了静态路由表
  • TLS加密传输相关
  • VLAN相关配置
  • pMib几个参数的初始化

判断是否跳转的关键指令是这里(0x0418228):loc_418250是正常运行,而右路则会去到报错退出的路线

右路:正是错误字符出现位置

直接跟着书本动态调试看看。相较于之前来说,出奇的顺利,之后确定了是使用了chroot指定整个文件系统,而非qemu -L指定库的原因,之前真的花不少时间去发现这个小坑点(QwQ是的)

断点0x0418228执行

V0 寄存器值为0,所以bnez是不会跳到标签上的

LD_PRELOAD劫持apmib_init()函数

正常情况下的攻击当然很难有这种权限去hijack函数,但是毕竟是仿真运行固件来进行漏洞研究,这种方式利用来做环境修复是非常棒的,

更简便的方法是改判断,比如bnez改成bez,但那个学不到东西

关于LD_PRELOAD可以看看这个博客的之前的文章,里面有收集第一次接触这个概念需要学习的内容

hijack的代码非常简单,更改值便可

编译指令: mips-linux-gnu-gcc ./hijack-apmib.c -o hijack.so -fPIC -shared

把得到的.so文件放进文件系统内任意一个位置,当然感觉还是放/lib比较整洁

这里还有一个小细节还需要注意:

把本机的复制到固件文件系统里就好

cd /lib32/libgcc_s.so.1 /rootfs文件系统路径/lib/

想要在仿真时LD_PRELOAD带这个.so,只需要加-E参数即可

仿真指令:

sudo chroot . ./qemu-mips-static -E LD_PRELOAD=/文件系统里的路径(比如lib)/hijack.so ./bin/boa

运行,可以看到已经没有”Initialize AP MIB failed!”这个问题了,当然,取而代之的是chklist file error(苦笑)

搜索相关字符串,发现只要有三个缓存文件就好

创建三个文件并且填入114514即可,执行,结果返回了个,0,不知道为什么?

看了下书,原来不是这样修复的!这里我就发现自己这几次调试的一个问题,都是看报错文字然后去IDA找,没有真正去动态调试,所以这里,还有之前的,都不知道发生了什么,于是总是以为是qemu出了问题,就没有去细究。

首先还是要进行静态分析的

好,那么就来动态调试看一看。劫持后成功跳转到另外一个分支0x418250

直接continue的话,崩溃的点不够直观啊,即使是在ida上也是不够直观,本书直接就出来了感觉有点奇怪

IDA的动态调试还是第一次这样做,之前要不就是x64dbg,要不就是pwndbg,而且很烦的一点是对于恢复环境,如果直接continue,直接就崩溃了,mips也让pwndbg看不到调用栈信息啥的,确定不了是啥问题,没事,通过单步调试还是能解决这个困难的

其实这四个步进方式是类似的,步进步入,步进步过,步进直到返回处,步进直到光标处

经过一番探索,发现这步是真正的导致崩溃指令:

看来又是库函数的问题,而且仍然是apmib,这里的apmib_get可以再回去https://github.com/luminais/ecos_http/blob/9cb66a1085d8519f536b493aedb4ea8b477972aa/rtk/ecos-work/AP/apmib/apmib.c#L1087看到,不然逆向猜测一个个缺失符号的方法是怎么用的到头秃,也是可以的

经典mips流水线机制的互斥锁,跟进里面的部分

跟进去发现这就尴尬了,apmib_get的就是之前apmib_init的东西,难怪会崩溃,那该怎么恢复啊?想到两个办法

1.改写apmib_init,让apmib_init对正确的位置写入正确的内容,但是好像不太行得通,本来就是因为正确的位置由于硬件的缺失从而无法写入啊

2.保留对apmib_init的改写,现在把apmib_get的逻辑完全改写,直接返回看似正常的东西,保证后文的正常执行即可。乱改是不行的,看起来后文需要apmib_get的东西,

(这也能说得通为什么作者可以毫不犹豫地把apmib_init改成return 1,原来后面还是有说法的)

分析如何hijack apmib_get()

那么真正的难题来了,怎么改写apmib_get呢?这段代码看起来有些复杂

耐心地继续看,发现apmib_get()第一个参数是决定type的,第二个参数是个地址,

type进入了一个巨长的if-else if-else,刚开始还疑惑这是在干嘛

…省略号…

其实这段如此长的if else代码是编译器的优化switch(case)的行为,一时间忘记了,后来翻找看源代码的switch才记起来

这就必须要提一句了,我敢100%肯定本书作者也是看了源代码才分析出来以下内容,因为连这些IDA缺失的符号名称都知道了,所以直接看源代码对照分析是最快的,这也是本书作者没有说出来的一点

何况没有做过路由器开发的话,要想直接逆向搞懂type这几十个值各自到底代表什么具体的东西,在手上没有设备给你反复测试的情况下,还是很有难度的

以下为作者突然在书上给出的代码,

讲真,我看了两个小时都不太懂这些是怎么调出来的,惭愧,看了下网上99%的相关过程记录都是照搬代码,没有分析,还有1%是指我还没找到的部分

然后后面两天断断续续调来调去,都不知道作者所说的这三个值怎么来的,上课都在搞这个。然后让我发现了这一篇,即使不需要设置这几个值,直接return 1都能跑😶整不会了,那我看的大部分文章都照搬跑通完事,赶紧试试

https://cloud.tencent.com/developer/article/1808922
mips-linux-gnu-gcc hook-apmib.c -shared -fPIC -Wall -o hook.so

cp hook.so ./lib/

您猜怎么着,嘿,还真它喵的可以

当我尝试打开网站,

报错,以及,一片空白,真的不行吗,然后我发现即使使用了作者的hijack agmib_get都会存在这样的问题,于是确认这种做法其实还是有概率行得通的

web服务起来后,仅仅从后端bin文件报错中寻问题,会被一定程度上误导,因为能正常执行的时候,也会报错,不一定就是缺失了什么,那么这个时候,应从web上找答案

【错误示范】被后端可执行文件报错误导的分析过程

这部分是错误的分析,想看正常流程可以跳过,记录在这里纪念我掉落的头发和因为搞不定而摆烂的两天

43B484是第一个报错出现的时刻

(按快了,凑合看看)

然后发现在这里卡死了

卡死以后ida可以ignore掉,继续执行,到jalr $t9;select这一行真的卡住了,访问网页就好了:

racted/squashfs-root-0$ sudo chroot . ./qemu-mips-static -g 12345 -E LD_PRELOAD=/lib/hook.so ./bin/boa

[sudo] password for ba1100n:

0cat: /proc/wlan0/mib_all: No such file or directory

DevInfo.txt text mode!

hard ver is

boa: server version Boa/0.94.14rc21

boa: server built May 25 2012 at 13:03:21.

boa: starting server pid=8263, port 80

device ioctl:: Function not implemented

device ioctl:: Function not implemented

smart 404 ----------------------------------

killall: dnsmasq: no process killed

killall: proxyd: no process killed

dnsmasq: failed to seed the random number generator: No such file or directory

dnsmasq: failed to seed the random number generator: No such file or directory

iptables v1.2.6a: can't initialize iptables table nat': iptables who? (do you need to insmod?) Perhaps iptables or your kernel needs to be upgraded. iptables v1.2.6a: can't initialize iptables table nat': iptables who? (do you need to insmod?)

Perhaps iptables or your kernel needs to be upgraded.

smart404 start ok.

device ioctl:: Function not implemented

device ioctl:: Function not implemented

可以注意到iptable nat没有办法被初始化,搜索该报错出现的bin文件

奇怪的是,iptables上面

跟进发现没有什么造成崩溃的地方

而且可以注意到在程序完全崩溃之前,触发了跳转到这里的逻辑,说明真正崩溃是在这之后

。。。

以上就是被误导的过程,反正一旦web通了,还停留在逆向后端固件服务层次上的分析,真的很坑,绕来绕去转圈

真正导致web界面空白的原因

发现访问网站时,被跳转到这里出现了空白

至少证明了web服务起来而且有跳转代码被执行了,即使一片空白,这其实是个好消息

包含该路径的后端逻辑位于process_header_end(),看不到网站入口往这里跳转的逻辑

此时自然地想到,跳转逻辑应该在主页

显然得把这段掐掉换成别的正常的东西

成功启动固件,并不需要按作者的方式来

总结

有些额外的涉及无关漏洞利用功能的库可被直接劫持成别的函数也不会影响后面的执行,主要还是得看出来这是干嘛用的,强烈推荐找源码大法

chroot而不是qemu -L也许会提高qemu仿真成功率

-g参数不要放在最末尾,而应该放在二进制程序路径的前面。。。

最重要的还是根据报错找问题,缺什么补什么,或者直接hijack整个函数

但是感觉还是不够,这次劫持这个函数之所以能仿真成功,是因为没有影响后面的执行,这一块感觉这个篇章的实验有点运气成分在里面,后面有时间还是得多弄几个

评论

  1. 慕雪岑
    3 月前
    2024-7-25 14:29:27

    大佬 受教了 那个源码部分我也调了好久 书上真的突然就跳出来了

    • 博主
      慕雪岑
      3 月前
      2024-7-29 14:17:57

      我不是大佬哈哈,逆向能力不足时的一些小花招罢了,共勉~

  2. finelyTang
    1 月前
    2024-9-11 16:53:36

    ftp://ftp2.dlink.com/PRODUCTS/DIR-605L/REVA/DIR-605L_FIRMWARE_1.13.ZIP 大佬这个地址是不是访问不了了?

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
粤ICP备20015830号