FormSec

逢魔网络安全实验室

DDCTF 2018 逆向 baby_mips Writeup

Auther : WeaponX

0x00 背景

最近一直在研究IoT设备的安全,而在IoT设备上程序很多都是MIPS架构的。所以对MIPS指令有一定研究,而在DDCTF 2018中刚好有一道逆向题目是MIPS程序,于是尝试做了一下。

0x01 环境搭建

由于我们通常的操作系统指令集都是x86的,所以无法跑MIPS程序。这时候就需要装QEMU来模拟,QEMU通过源码编译较为复杂,我们又没有特殊的需求,所以直接使用ubuntu的APT进行安装即可。

1
sudo apt install qemu

由于MIPS架构有两种——大端MIPS和小端MIPS。所以,我们需要确定这个程序是大端MIPS还是小端MIPS。

1
2
user@ubuntu ~ file baby_mips 
baby_mips: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, stripped

ELF 32-bit LSB很明显,这个程序是32位小端的MIPS。所以,我们使用qemu-mipsel baby_mips来运行这个程序。因为我们需要远程调试MIPS程序,所以要加上-g 端口参数,qemu-mipsel -g 1234 baby_mips,此时用IDA pro就可以通过Remote GDB Server来调试这个MIPS程序。

0x02 题目分析

直接打开IDA来载入程序,搜索字符串,可以看到

查找这个字符串的交叉引用,直接到sub_403238

可以看到一个简单的流程,程序根据loc_400420函数的返回结果来判断是否为正确的key。那么,到这里我们需要理解loc_400420具体干了什么。进入函数之后,代码比较乱而且还有很多无法识别的代码块。

这时候为了方便我们理解,就得来远程调试这个MIPS程序。随后,在虚拟机中使用QEMU启动该程序,使用IDA连接虚拟机的gdb服务,然后让程序跑起来。在输入完key后,程序会在这里崩溃掉。

当我们把这条指令以数据的形式展示后,发现指令为0xEB023DC5。而且我们发现,识别不出来的代码段。都有个特点,就是指令的头两个字节为\xEB\x02,且在x86指令集中\xEB为跳转指令。

我们把操作码反汇编成汇编代码后发现第一条指令是jmp 0x4,刚好MIPS指令集每条指令大小为4字节。

1
2
>>> print disasm("\xeb\x02")
0: eb 02 jmp 0x4

于是做出猜测,是不是程序让我们遇到这个指令就跳转四字节呢?然后我们把以\xEB\x02开头的指令全部替换为nop

1
2
3
4
5
6
7
8
9
10
11
12
13
import os
f = open("baby_mips", "rb")
content = f.read()
content = list(content)
for x in range(0, len(content)):
if content[x] == "\xeb" and content[x+1] == "\x02" and (x%4==0):
content[x] = "\x00"
content[x+1] = "\x00"
content[x+2] = "\x00"
content[x+3] = "\x00"
content = "".join(content)
p = open("patch", "wb")
p.write(content)

替换好之后,我们再使用IDA载入程序,发现已经没有不能识别的代码段了。然后,为了方便我们了解key比对函数的功能,我们可以需要对MIPS进行反编译,目前可以反编译MIPS程序的工具有两个。

  • Retdec
  • JEB-mips

我们首先使用Retdec来反编译该程序

接着我们尝试使用JEB-mips来反编译改程序

可以很轻易的看出,这块其实就是一个16元1次方程组,我们写一个python脚本来解这个方程组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import numpy as np

A = "-15858,-48466,32599,38605,-44159,23939,45662,9287,47754,47937,41896,51986,-26968,22561,30701,63487;"
A += "60228,-3993,-16615,57134,-19246,-38581,40294,-44968,-28198,-58965,-39534,22458,-8828,48593,46135,23871;"
A += "59121,42162,-65140,-3847,-23842,-47173,-39252,37804,-20964,-19217,56467,5112,9324,61729,61599,3578;"
A += "-36731,-26147,1670,19245,26847,39911,8628,57946,-51207,63125,-21537,-9321,40745,-58129,30962,-27610;"
A += "-63560,-53320,-34289,61060,-14289,46922,53218,36638,-61969,-33727,-4681,32423,-17044,-46689,-35443,-24156;"
A += "-10571,-11103,51585,-24771,63730,57047,-63227,4227,-56470,-22654,-46325,62842,22480,59412,24937,62085;"
A += "52617,-54333,61495,33704,-41733,-44527,51882,-61765,-24691,-10103,31055,61454,-59349,9812,-48848,-47279;"
A += "-40696,-26470,54670,-23715,10008,7723,-62622,53112,31753,-5047,-48878,-58448,19875,-34944,-22161,35800;"
A += "-23196,-43354,-58947,3384,-2426,-60194,51907,-20177,-31882,61703,42398,-4627,45749,-29203,-11139,-41301;"
A += "-37819,-10066,-48579,-62613,-28961,40001,-37989,-27875,-20264,-33616,-5998,30740,-29594,21652,5165,51797;"
A += "52993,62328,4196,-55719,-1917,28075,-44831,-15799,13652,-52110,-38933,62219,40030,-23815,-19505,60128;"
A += "35796,-28033,-59250,46833,39767,-22909,5585,-42334,64787,6068,60536,-54554,22189,-49945,40846,64023;"
A += "-18536,-35823,4253,-63956,20175,43158,30523,28298,-29564,18809,50821,-38574,3005,33408,58281,-29452;"
A += "2848,39836,46250,24950,38512,31901,-21506,-36050,44162,41717,-36605,-26097,-38073,36024,7349,19105;"
A += "22525,15747,63301,42436,-26106,-22761,48830,6176,-55225,-45599,-30368,50701,5775,10902,12758,-19336;"
A += "-58450,-51156,-5460,32490,-26701,27355,34100,-14902,10736,54258,-9189,-25920,48339,-61339,61403,-30542"

b = "23261386,-1298872,13877344,9172342,-11622989,10343966,-9721165,-8286458,-7515929,-12609498,2179053,11137244,12446496,10255605,854242,1542147"

A = np.mat(A)
b = np.mat(b).T
r = np.linalg.solve(A,b)
print r

结果如下

四舍五入后输入程序中,得到最终的flag如下

0x03 Refer

https://wenku.baidu.com/view/1908905f178884868762caaedd3383c4bb4cb469.html

https://blog.csdn.net/KoalaZB/article/details/52733910?locationNum=3

https://zhuanlan.zhihu.com/p/24893371