家用路由器0day挖掘笔记(1)MIPS32平台逆向入门指南

发布于 2021-09-08  72 次阅读


前言

本系列受众为对Linux端开发,尤其是socket程序开发(包括码代码和设计理念)有一定了解,对X86平台逆向有一定了解,但对MIPS平台逆向基础薄弱的读者。本系列记录笔者遇到的问题和整体操作思路

本系列目标为复现并完全理解CVE-2005-2799,并在一定程度上拥有敏锐发现二进制敏感操作,以及思考他们可能造成什么样问题的能力

exp预期使用python编写

本系列原载于笔者博客www.ksrodio.art,由笔者自行搬运至看雪,知乎

禁止转载 禁止转载 禁止转载 欢迎借鉴 欢迎借鉴 欢迎借鉴

正文

Linksys WRT54G是一款SOHO无线路由器,千禧年初,该型号在极客间颇为有名,主要原因有:支持刷第三方固件,双天线相控阵信号通信等,功能十分强大!而这也正是 CVE-2005-2799 受影响的设备。

该漏洞存在于路由器内HTTPD程序的apply.cgi文件下,其对POST请求的验证不够完善,经一番不算太难的操作后便可溢出缓冲区,直接提权至root,该漏洞系远程任意代码执行漏洞,属于高危漏洞

本文将带大家从x86-PC平台逆向,进入嵌入式逆向的世界

MIPS32指令集,汇编

本小节只是一个基础,并非为了让大家精通MIPS32,笔者这里只会讲我们需要的内容

MIPS是RISC,所以相比于操作内存而言,大部分时候我们操作的都是寄存器

MIPS32架构有32个通用寄存器,基本都会用到,但是总共只有12种,很好记忆

ID名称备注
0$0,zero始终为零,作为常量寄存器
1$at保留,向上兼容
2-3$v0~$v1函数返回值寄存器
4-7$a0~$a3函数前四个参数
8-15$t0~$t7临时变量寄存器
16-23$s0~$s7帧变量寄存器,函数返回时必恢复
24-25$t8~$t9临时变量寄存器
26-27$k0 $k1中断寄存器
28$gp全局指针寄存器,静态变量指针寄存器
29$sp栈顶指针寄存器
30$fp栈帧寄存器
31$ra返回地址寄存器

几个点强调一下

首先是 RISC 会尽可能操作寄存器,其次是立即数,内存是最万不得已的选择

因此对于0这个常见的常量,MIPS特意分了一个寄存器,此外一些指令会利用这个寄存器进行一些优化

比如MOVE $t0,$t1,这一指令在底层会被优化为ADD $t0,$0,$t1——与0相加;由于某些底层设计的原因,后者速度更快,然而前者更符合大多数程序员的直觉,因此有了这种自动优化

“ 尽可能操作寄存器 ”也能很好解释为什么这么多临时变量寄存器,如果在PC上面的话,x86更多是栈储存临时变量

让人颇为在意的是两个返回值寄存器

大部分情况下我们用不到v1返回值寄存器,只会使用v0,但对于某些高级语言的元组语法糖,或在tuple结构中,或是手写汇编函数结构的情况下,都有可能会用到第二个返回值寄存器

在一般情况下,第二个返回值寄存器用于储存32位架构下的乘除结果(这一结果有可能是64位,至于为什么请查阅《加密与解密》)

MIPS64保留了双返回值寄存器这一设计以向下,向上兼容,预期目的是存储128位结果,不过笔者有生之年应该看不到233

t系列寄存器按照约定,不需要保存,也不需要清理,随时都可以使用,省去了PUSHAD的开销

s系列寄存器则需要保存,需要恢复现场

至于fp寄存器,由于MIPS平台体力弱小,因此栈帧寄存器常常会被寄存器“优化掉”,当作普通的临时变量寄存器

gp寄存器:由于最上面提到的原因,即“尽可能直接操作寄存器”,所以MIPS专门为了静态成员变量,设计了一个寄存器,也就是gp寄存器

ra寄存器,在X86下面,call之后的返回地址直接入栈,但是MIPS平台要尽可能少操作内存,因此JAL(相当于CALL)之后,返回地址会被存入寄存器当中(也就是ra寄存器)

另外是三个特殊寄存器:计数器PC,高位寄存器HI,低位寄存器LO,用于乘法时保存高低位,用于除法时LO存商,HI存余数

此外MIPS还有一些不得不注意的特点

MIPS没有flag寄存器任何临时寄存器都可以拿去当作flag寄存器

MIPS指令集的指令固定4字节长度,而且必须以4字节对齐,因为MIPS-CPU为了高效,没有设计在非对齐下的行为

跳转指令上下寻址空间256MB

条件分支指令上下寻址空间256KB

MIPS为了效率,采用高度流水线,有较大的分支延迟,当跳转指令的目标地址刚发送给CPU后端,而跳转指令本身还没执行时,跳转分支语句的下一条指令(地址相邻的下一条,而非跳转的目的地)就已经在装载并即将执行,这点非常重要,这会影响整个跳转流程分析

汇编部分我们只列出部分打头的字母代表的意思,详细内容查白皮书就行,这里就不复制粘贴了

L/S LOAD/STORE:存到寄存器/存到内存

MOVE:寄存器之间移动值

S SET(比较):比如SLT SET LESS THAN 小于比较

B BRANCH:分支

J JUMP:跳转

大小端

MIPS平台一般是大端字节序,这与普通的X86-Linux平台正好相反,稍微注意下即可

结束语和预告

现在已经基本掌握MIPS平台汇编的几个重要知识点,我们后续会在实战中巩固,敬请期待