IOT 设备漏洞挖掘-MIPS 指令集逆向技巧

阅读量843891

|评论1

发布时间 : 2020-03-31 15:00:02

xxxkkk@海特实验室

MIPS 反汇编工具

IDA 无法直接反汇编 mips 代码,但是有两个插件可以辅助我们进行伪代码的生成。

IDA插件之retdec

项目地址:https://github.com/avast/retdec

安装过程较为简单,可以参考网上的相关教程,不在此赘述了,以下是两张分析时候的截图,第一张是分析过程中的截图,第二张是分析的结果。

Ghidra

Ghidra是由美国国家安全局(NSA)研究部门开发的软件逆向工程(SRE)套件,是一个软件逆向工程(SRE)框架,包括一套功能齐全的高端软件分析工具,使用户能够在各种平台上分析编译后的代码,包括Windows、Mac OS和Linux。功能包括反汇编,汇编,反编译,绘图和脚本,以及数百个其他功能。Ghidra支持各种处理器指令集和可执行格式,可以在用户交互模式和自动模式下运行。用户还可以使用公开的API开发自己的Ghidra插件和脚本。

总之这个一个功能非常强大的反汇编工具,基于 java 开发,可以反汇编很多种的汇编代码类型。而我们使用这个工具的目的就是因为这个工具可以帮助我们生成 mips 的伪 C 代码。从而方便我们进行代码逆向。

有一款Ghrida的插件比较适用于习惯于用IDA的同学,会把Ghrida里面的快捷键映射成IDA里面的快捷键,这样用起来就好多了。

插件地址:https://github.com/enovella/ida2ghidra-kb

插件的安装方法较为简单,依照说明即可。实现了包括x、g等IDA中快捷键功能。

另外,需要主要,在使用Ghrida分析MIPS的时候,PLT和GOT的时候经常会出现问题,如图所示:

如果你需要定位GOT表,还是需要使用IDA查找更为直观方便。

 

敏感函数定位

我们在逆向分析一个 mips 指令集架构的二进制程序时,可以使用敏感函数定位的方法,快速定位敏感函数,如 system、sprintf、strcpy 等命令执行和容易发生栈溢出的函数。

 

常见敏感函数类别

内存类型的敏感函数

  • 栈溢出敏感函数

在 MIPS 指令集中,特别是智能设备,一般来说栈溢出漏洞较为常见,也是比较容易利用的一类漏洞,发生栈溢出可能的函数有 strcpy,sprintf,snprint, strchr 等。

1) strcpy 类函数如下所示,直接从 http 数据包参数中的数据内容,直接复制到栈上,没有经过任何的判断与处理,因此可以通过栈溢出越界的 buffer 覆盖当前函数的返回地址,可以进一步利用 ROP 技术来获取目标程序的 shell。

strcpy(stack, buf_from_http);

2)sprintf类,如果格式化中有“%s”格式化字符串,同时没有对输入的数据进行长度判断的话,则也有可能造成栈溢出漏洞。

sprintf(stack, "%s", buf_from_http);

3) snprintf类,snprintf 的返回值是输入的长度,而不是输出的长度,因此下面的代码则有可能存在漏洞,大致的利用原理因为,第一个snprinf返回值是输入的长度,一般输入的长度大于sizeof(stack),则第二个 snprintf 的 size 则变为负数,snprintf 的大小是无符号的,因此变成了一个超大的size,导致第二个可以用来覆盖返回地址。值得注意的是,这样类型的 overflow 还可以用来bypass canary。

int left = snprintf(stack, sizeof(stack),"%s", buf_from_http1);
snprintf(stack+left, sizeof(stack)-left, "%s", buf_from_http2);

4) strchr类,如下所示,乍一看好像使用了strncpy规定了复制的长度,但仔细看就会发现,复制的长度也是由输入的字符串来决定的,因此直接在?前面输入超长的字符即可实现overflow

char *query = strchr(url, '?');
strncpy(stack, url, quey - url -1);

如:index.phpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?a=1。只要 QURTY_STRING 够长就可以导致栈溢出。

注入类型的敏感函数(逻辑)

注入类型的漏洞相对来说就简单很多,只要看数据流的处理流程,确定输入能否控制敏感函数即可。常见的敏感函数如system、popen、exec、execve等,在注入类型漏洞中,对于过滤的关键词绕过是比较关键的,例如没有空格的时候可以使用 $IFS进行绕过。也可以通过一些编码比如xxd,base64等。

 

常IDA自动定位敏感函数插件

这里推荐一个比较方便定位二进制程序敏感函数的 python 插件:MipsAduit,项目地址:https://github.com/giantbranch/mipsAudit

该工具是一个 MIPS 静态汇编审计辅助脚本,通过敏感函数回溯的方法,可以较方便的审计出 C 语言中的危险函数。

插件的安装方法

在 IDA -> file -> Script File 中加载即可,加载完成后会在控制台中输出相应的信息。

点击相应的地址就可以跳转过去,对应的位置会被高亮显示:

 

使用IDA Python 自带函数来定位敏感函数

IDAPython 自带很多的 API,可以使用这这些 API 函数来辅助我们进行函数的定位。

如,定位出调用 sprintf 函数的地址列表的代码:

sprintf_list = set()
for loc,name in Names():
    if "sprintf" == name:
        for addr in XrefsTo(loc):                                           # 列出调用 sprintf 的函数地址
                sprintf_list.add(GetFunctionName(addr.frm))

print("\n\n")
print(sprintf_list)               # 打印输出

– 可以直接在 IDA 中,File -> Script command… 的输入框中输入这些代码,点击 run 就可以执行:

运行完成之后的结果使用 print 函数输出之后,会打印在 Output window 中:

这些输出的地址就是引用了 sprintf 方法的函数,同样双击函数名可以直接跳转到相应的地址。

  • 读者可以在自行在for addr in XrefsTo(loc): 语句下加入其他过滤语句,以达到更准确定制自己想要的功能。

如这里想要排除 sytem 敏感函数第一个参数为 .data 段中的字符,且不包含 %s 字符的话(说明格式化参数不可控),如我们需要排除这种情况:

system("rm -f /tmp/auth_engineer");

那么,条件可以写成这样:

system_list = set()
for loc,name in Names():
    if "system" == name:
        for addr in XrefsTo(loc):                                            # 列出调用 system 的函数地址
                system_list.add(addr.frm)
print("\n\n")

system_args_list = set()
for addr in system_list:
    arg2_addr = 0
    arg2_addr = RfirstB(addr)       # 获取对 a0 语句赋值的语句
    arg2_str = GetString(Dword(GetOperandValue(arg2_addr,1)))                                # 获取 a0 参数的值的字符串

    try:
        if "%s" not in arg2_str:
            system_args_list.add(addr)  # 排除这种情况
        else:
            pass
    except:
        pass

result_list = system_list-system_args_list  # 取差集,得到最终结果

for addr in result_list:
    print(hex(addr))

得到的结果也更精确一些:

本文由安恒信息安全研究院原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/202053

安全客 - 有思想的安全新媒体

分享到:微信
+18赞
收藏
安恒信息安全研究院
分享到:微信

发表评论

内容需知
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全客 All Rights Reserved 京ICP备08010314号-66