BUU2023-07

笑死,除了比赛,buu真没动多少:smile:

[SUCTF2019]hardcpp

这题不难,耐心分析一下就行,就只用一个坑点:

首先是用了llvm混淆,这个没啥,用d810插件一下就去掉了:

image-20230801121543617

就很清晰的分析了。

加密就是

1
enc[i] == ((flag[i+1] + flag[i] % 7) ^ ((flag[i] ^ 18) * 3 + 2))

就是拿前面的数据加密后面的数据

坑点:

注意s和input在栈上的位置,所有这里的调用一个是input[i-1],一个是input[i-2]。

脚本爆破,居然有数值爆了,注意and 0xff:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enc = [0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9, 0x8C,
0x40, 0x76, 0xF4, 0x0E, 0x00, 0x05, 0xA3, 0x90, 0x0E, 0xA5]

# enc[i] = (flag[i] + flag[i - 1] % 7) ^ ((flag[i - 1] ^ 18) * 3 + 2)
for i in range(32, 127): #爆破第一位
if enc[0] == (ord('f') + i % 7) ^ ((i ^ 18) * 3 + 2):
print("flag = '{}'".format(chr(i)))
print()
flag = [ord('#')]

for i in range(len(enc)):
for ch in range(32, 127):

if enc[i] == ((ch + flag[i] % 7) ^ ((flag[i] ^ 18) * 3 + 2)) & 0xff:
flag.append(ch)
break
print(bytes(flag))

Dig the way

这道题目考的是栈溢出,先分析程序:

image-20230802121337044
image-20230802121324412

在开头给函数地址赋值,到后面进行使用,不难发现fun2的返回值是恒大于等于2的,此时v5的值是3,根据堆栈来看,v7[3] -> v8,所以正常运行这个程序是不可能到达getkey处。

但是发现了个可以无限读取的地方:

1
2
3
4
for ( i = 0; i < (int)v13; ++i ){
v4 = i;
Str[v4] = fgetc(v14);
}

一看Str的位置,在栈上,这意味着可以实现栈溢出。

image-20230802143648170

分析三个fun,发现是将数值交换和两个计算:

image-20230802143737098

虽然fun2不能返回0的值,但是fun1可以做到:

|-1 + 2| - |2| - |-1| + 2 = 0

由于存在栈溢出,而且v9,v10这两个参数在读取前面就实现了赋值,于是可以栈溢出输入参数,利用fun0将v7后面任意两个数据转换位置,所以可以让fun1最后执行,这样结果能够返回0然后写入到v8(v7[3])。

然后就是造v7的数据使得最后的计算结果为0:

|0 + 0| - |0| - |0| + 2 = 2

|-1 + 2| - |2| - |-1| + 2 = 0

所以v7[4]的数据为:

[任意dw大小数据, 0, 0, -1]

为了使得先执行fun2在执行fun1,fun0的参数很简单,一个7(fun1),一个8(fun2),在制造数据的时候注意一下大小端序就行。

v11就不可以动了,这里保存了关键的fun函数位置。

剩下的随意填充:

image-20230802144949663

如果使用栈溢出强行从main返回到getkey,那就记得多把两个参数压一下,v13是0,v12是8

不过都知道是这两个数了,前面也会了,这两参数是解密用的。

image-20230802145655531

[MRCTF2020]Shit

这题居然给了源码,一定程度上教了我花指令怎么写的,涉及的花指令见这篇文章

去完花分析即可:

image-20230803183036711

上图我patch过反动调的检查。

24位输入,然后进行简单的移位异或

image-20230803183205157

key由前面产生。

image-20230803183302848

有个这个神奇的函数:

image-20230803183240934

不知道有什么用。。

对dword_FC5030进行了--,这个函数是必执行的?

最后key是动调过的,在start前面有个初始化的函数

image-20230804104330295

如果在这里之前就动调了,就会在initterm这个函数里面无限循环,只能通过attach的方法来进行动调

查明了,里面写了个无限递归的,检测到动调就进行无限递归,用全局变量复制调用的

然后记得绕一下反动调就能得到key,写个解密就行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
key = [3, 0x10, 0xD, 4, 0x13, 0xB]
enc = [0x8C2C133A, 0xF74CB3F6, 0xFEDFA6F2, 0xAB293E3B, 0x26CF8A2A, 0x88A1F279]

for i in range(5, 0, -1):
enc[i] ^= enc[i - 1]
enc[i] &= 0xffffffff

flag = ''
for i in range(len(enc)):
enc[i] ^= (1 << key[i])
low = ((enc[i] & 0xffff0000) >> 16) & 0xffff
high = (~(enc[i] & 0x0000ffff) & 0xffff) << 16
enc[i] = (high | low) & 0xffffffff
enc[i] = ((enc[i] << key[i]) & 0xffffffff) | (enc[i] >> (32 - key[i]))
res = ''
for ii in range(4):
res = chr(enc[i] & 0xff) + res
enc[i] >>= 8
flag += res
print(flag)