经过之前几篇的漏洞挖掘练习,对于普通linux内核与VxWorks内核的固件漏洞进行了分析,这次来分析一下被加密过的固件漏洞。
以D-Link DIR878为例,此路由器的固件从1.04版之后开始对之后的版本固件进行加密,而解密程序就在最后一个不加密的版本固件里也就是1.04版,所以这次我们需要先下载两个版本的固件,固件下载地址:D-Link。
关于固件加解密可参考D-Link DIR-882 路由器加密固件的解密
在下载固件时可能会找不到1.04版本的,直接找1.10版本的即可这两个版本在一起。
解密
下载好后会有1.04与1.20两个版本的固件,1.04后缀中有Unencrypt的字样。
先用binwalk看看1.20版本的,可以发现没有解析出任何内容,所以几乎可以肯定固件被加密处理过了。
然后使用binwalk导出1.04版本的目录导出后会在目录下出现两个文件A0与A0.7z继续用binwalk导出A0的目录结构当然在以上导出目录的同时也要记得查看输出的信息。
R然后进入A0.extracted目录会看到661C8、8AB758、8AB758.7z然后使用file看看文件的类型。
cpio是linux下一个比较老的归档工具现已被tar取代,所以我们再用binwalk导出8AB758的目录,进入。
然后可以看到0.cpio文件与cpio-root目录进入cpio-root目录就会发现这是一个类Linux的文件系统目录。
r然后先将我们刚刚下载的1.20版本的固件复制进这个目录,然后不出意外的话,你会在1.04版本解压出的cpio-root目录下的/bin目录中找到一个名为imgdecrypt的文件,没错一会就要用他来解密1.20版本地固件。
现在我们切换到刚刚导出的cpio-root目录下执行sudo chroot ./ ./bin/sh
命令,然后我们的终端就会被切换到BusyBox下。
然后使用/bin/imgdecrypt DIR_878_FW120B05.BIN
来解密1.20版本固件,执行完后可以看到KEY。
并且此时我们的DIR_878_FW120B05.BIN即1.20版本的固件被揭密,可以使用binwalk解析并导出和1.04版本一模一样的目录内容,所以之后就按照刚刚用binwalk解析1.04版那样把1.20版也解析导出目录,一直到我们能看到cpio-root目录为止。
逆向
截至目前为止,我们已经将我们所需要的固件解密并且导出目录完成了,接下来就该逆向反汇编查找漏洞了,这次不再用用老的ida pro改用最近由NSA美国国家安全局研究部门开发的软件逆向工程套件——Ghidra来完成,因为此固件是基于MIPS架构,所以ida pro无法将其进行反编译成C语言代码(如果非要用IDA那就只能安装插件),所以为了方便逆向分析,我们改用ghidra,我也是第一次用这个工具还是有点不太熟练,但不得不说的是,这个工具反编译出的C语言代码可读性确实比ida好不少,而且我在使用过程中还发现了不少作者在开发时留下来的一些有意思的小彩蛋…
当然缺点也有那就是基于JAVA开发在反汇编效率上可能没有IDA那么快,此文不过多介绍这个工具的用法因为我也还没玩明白,官方git:ghidra。
我从官方git上git下来后发现直接从RuntimeScript目录下启动会报无法找到主类的错误,在git上提问才恍然大悟!
按照作者的意思,想要直接运行还需要使用eclipse配置gradle构建一下,而用gradle构建的话就会发现好多必须文件会从国外下载所以…(你懂的),所以我又往我的git里上传了一份我构建过的,可以直接使用,无需再构建。地址: Pluviophile-BT
的人你也可以自己按照原作者的指示去自己构建一下自己需要的版本
地址:GhidraDev
安装好后开始干活,启动ing…(这界面风格很JAVA…)
这里要注意需要新建项目,因为ghidra与IDA不同,它使用项目来进行管理的,并且支持多人团队协作共同逆向分析一个项目,当然除此外还有其他的黑科技(强大…愿我天朝也能早日开发出并对外开放这样一款甚至比这更强大的工具)
新建完项目后在file中选择importr file把我们刚刚已经解密过的1.20版本的固件中cpio-root/lib
目录下的librcm.so
动态链接库包含金我们的逆向项目。
双击一下项目下要分析的文件名,进入后会有提示框,确认后会有选择对话框,我的建议是全选然后OK(Anlize),确认后注意左下角的进度条,他如果还在加载说明还在解析,需等待。
完成后我们在右边Symbol tree框中找到function函数框随便找一个函数点击后会看到
中间是反汇编的汇编输出框,最右边是反编译后的C语言伪代码(不得不说这伪代码可读性还是不错的)。
y由于我们已经知道这里有一个指令执行漏洞,我们就不广撒网的去找了,直接找准切入点搜索execv搞起!
r然后在工具栏找到一个绿色箭头查看此函数的调用函数,看看是怎么调用它的。
会发现两个函数调用了他。
twsystem_nowait与twsystem看函数名即可得知,一个会进行等待一个不会,点进去再看这两个函数的伪代码与调用者。
注意看如果第一个参数为0就提示空命令,所以按照我的推断第一个参数就是负责接收调用者输入进来的指令的(int不一定就是一个整数,他还有可能会是个char型数组的首地址),如果·不为空就fork一个子进程并在子进程里调用execv,因为我在这里看的是twsystem函数所以在最后他还会调用waitpid来等待子进程执行结束(相对的twsystem_nowait就不会等待),然后继续查看twsystem的调用者(左边一栏)。
会发现很多函数调用了他…头大…,从函数名可以看出前几个函数会完成ping功能,点进第一个函数,欣喜的发现这一句
它会将函数参数与字符串常量拼接成一句指令而且未作过滤(至少这个函数里没有,前一个函数有没有那是前一个函数的事),他会对指定IP进行ping并将结果输出到一个文件中,然后将这条指令交给twsystem函数(雨过了,天晴了,我又觉得我行了),接着看这个函数的调用者,然后…并没有发现这个函数的调用者…。
然后经过一番肝,最后终于找到了一个长的要命的函数FUN_0002FEF0函数(找这玩意又害我掉了几根头发,不禁叫出了某种植物的称呼)。
他会先向变量acStack544给一个iptables的shell指令对URL进行过滤,后面还有很多其他步骤,代码太多就不一一解释,取出域名调用系统指令进行过滤,这里只对/?等特殊符号进行分割处理,所以他无法防止指令注入,所以漏洞产生的地方就在这里。我手头因为没有对应型号的路由器也懒得搭虚拟环境,所以对于后续的动态测试漏洞利用过程可以参考D-Link DIR878路由器命令执行漏洞分析
的动态测试部分