陇原战”疫”2021网络安全大赛_RE_WP

EasyRe

方法一

IDA打开分析

image-20211108215957143

发现sub_4111406这个函数是对输入的flag进行加密,然后将加密后的数据存放到0X41A14C

来到sub_4111406函数,并不能F5, 直接动态调试一直跟

image-20211108221620057

发现程序在不断的生成一些数据,长度是32

image-20211108221836369

image-20211108222031497

多次调试,不同输入,这里获取的数据是一样的

image-20211108222147050

image-20211108222205631

分析,还原算法

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
#include <stdio.h>
#include <windows.h>

DWORD * enc(char* flag, char* key)
{
DWORD* pdw_flag = (DWORD*)flag;
DWORD* pdw_key = (DWORD*)key;

for (int i = 0; i < 8; i++)
{
pdw_flag[i] ^= pdw_key[(7 * i + 2) % 8];
}

for (int i = 0; i < 8; i++)
{
pdw_flag[i] ^= pdw_flag[i] << 7;
pdw_flag[i] ^= pdw_key[(7 * i + 3) % 8];
pdw_flag[i] ^= pdw_flag[(5 * i + 3) % 8];
pdw_flag[i] ^= pdw_flag[i] << 13;
pdw_flag[i] ^= pdw_key[(7 * i + 5) % 8];
pdw_flag[i] ^= pdw_flag[i] << 17;
}
return pdw_flag;
}


int main()
{
char flag[33] = "12345678901234567890123456789012";

char key[32] = { 12, 21, 30, 39, 32, 41, 50, 59, 68, 77, 86, 95, 88, 97, 106, 115, 124, 133, 142, 151, 144, 153, 162, 171, 180, 189, 198, 207, 200, 209, 218, 227};
enc(flag, key);
return 0; //在这里下断点观察加密后的数据是否与IDA调试时生成的一样
}

在末尾下断点调试

image-20211108222634154

IDA调试运行下断点观察加密后的数据

image-20211108222802969

发现是一样的,还原加密算法成功,现在开始写解密脚本

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <stdio.h>
#include <windows.h>

VOID dec_shift_xor(DWORD* mingwen, int shiftlen) {
//pdw_flag[i] ^= pdw_flag[i] << 13 类似这种加密方式,知道加密后的,解密得到原来的数据
//mingwen指向明文
//shiftlen指向移位的的位数

DWORD data = *mingwen;
DWORD mask = 1;
for (int i = 0; i < shiftlen - 1; i++) { // 构造mask
mask = (mask << 1) + 1;
}

DWORD zuidi2wei = data & mask;

int count = 32 / shiftlen;
count = 32 % shiftlen == 0 ? count : count + 1;
for (int i = 0; i < count; i++)
{
zuidi2wei <<= shiftlen;
mask <<= shiftlen;
data ^= zuidi2wei;
zuidi2wei = data & mask;
}

*mingwen = data;
}


DWORD* dec(char* enc_flag, char* key)
{
DWORD* pdw_flag = (DWORD*)enc_flag;
DWORD* pdw_key = (DWORD*)key;

for (int i = 7; i >=0; i--)
{
dec_shift_xor(&pdw_flag[i], 17);
pdw_flag[i] ^= pdw_key[(7 * i + 5) % 8];
dec_shift_xor(&pdw_flag[i], 13);
pdw_flag[i] ^= pdw_flag[(5 * i + 3) % 8];
pdw_flag[i] ^= pdw_key[(7 * i + 3) % 8];
dec_shift_xor(&pdw_flag[i], 7);
}

for (int i = 0; i < 8; i++)
{
pdw_flag[i] ^= pdw_key[(7 * i + 2) % 8];
}

return pdw_flag;
}


int main()
{
char key[32] = { 12, 21, 30, 39, 32, 41, 50, 59, 68, 77, 86, 95, 88, 97, 106, 115, 124, 133, 142, 151, 144, 153, 162, 171, 180, 189, 198, 207, 200, 209, 218, 227};
char enc_flag[33] = { 0x15, 0x86, 0x0F, 0xF9, 0x3D, 0x7C, 0x82, 0xC8, 0x63, 0x32, 0xD7, 0x1B, 0x54, 0x74, 0x0C, 0xA9, 0x05, 0x4E, 0x3F, 0x7D, 0x19, 0xBC, 0xE4, 0x53, 0x7F, 0x39, 0x5B, 0xA8, 0x5E, 0xA4, 0xB2, 0xD4,0}; //提取的0X41A058处的数据
dec(enc_flag, key);
printf("%s", enc_flag);
return 0;
}

得到 fc5e038d38a57032085441e7fe7010b0,加上 flag{} 得到 flag{fc5e038d38a57032085441e7fe7010b0}

方法二

去花指令

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
from ida_bytes import get_bytes, patch_bytes
import re

addr = 0x415B53
end = 0x0415B79

buf = get_bytes(addr, end - addr)
buf_str = "".join([chr(i) for i in list(buf)])

pattern = r"\xE8\x01\x00\x00\x00.\x33\xDB\x33\xC0\x33\xC9\x59\x83\xC0([\s\S])\xBB([\s\S])\x00\x00\x00\xF7\xE3\x83\xC1\x20\x83\xC0([\s\S])\x33\xC3\x51(\x88\x45[\s\S])\xC3."


def handler(s):
eax = ord(s.group(1)[0])
ebx = ord(s.group(2)[0])
tmp = ord(s.group(3)[0])
c = s.group(4)

eax = eax * ebx
eax += tmp
eax ^= ebx
patch_ = "\xB8" + chr(eax) + "\x00\x00\x00"

return patch_ + '\x90'*(0x25-5-5) + c + "\x90" * 2


buf = re.sub(pattern, handler, buf_str, flags=re.I)

buf_bytes = bytes([ord(i) for i in buf])

patch_bytes(addr, buf_bytes)
print("OK")

image-20211109200215569

Z3模块解决

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
from z3 import *


if __name__ == "__main__":
enc = [0xF90F8615, 0xC8827C3D, 0x1BD73263, 0x0A90C7454,
0x7D3F4E05, 0x53E4BC19, 0xA85B397F, 0xD4B2A45E]

v5 = [0] * 8
flag = [BitVec(f"flag_{i}", 32) for i in range(8)]
s = Solver()

v4 = [0x271E150C, 0x3B322920, 0x5F564D44, 0x736A6158,
0x978E857C, 0xABA29990, 0xCFC6BDB4, 0xE3DAD1C8]

for i in range(8):
v5[i] = flag[i] ^ v4[(7 * i + 2) % 8]

for j in range(8):
v5[j] ^= v5[j] << 7
v5[j] ^= v4[(7 * j + 3) % 8]
v5[j] ^= v5[(5 * j + 3) % 8]
v5[j] ^= v5[j] << 13
v5[j] ^= v4[(7 * j + 5) % 8]
v5[j] ^= v5[j] << 17

for i in range(8):
s.add(v5[i] == enc[i])

assert s.check() == sat
m = s.model()
flag = [int.to_bytes(m[i].as_long(), 4, byteorder="little").decode()
for i in flag]
print("".join(flag))

EasyRe_Revenge

此题与EasyRe_Revenge一样,只是把密文换了,替换上图中的enc_flag即可

1
char enc_flag[33] = { 66, 176, 232, 238, 108, 238, 208,  87,  50,  75, 245, 243, 214, 183, 240, 211, 137, 195,  97,  10,  64, 186, 199,  56,  44, 158,  61,  12, 132, 146,  74, 214,0 };

后来发现,原来EasyRe那道题目,flag直接存在字符串中了,所以把密文换了,才有了这个EasyRe_Revenge

findme

IDA打开分析

image-20211108224257719

来到 403844 这个位置

image-20211108224444634

很显然这个位置不可能是strcmp,观察发现404840那个地址处还存了个函数的地址 sub_401866,估计程序有地方把403844这个地方的地址给替换掉了

来到401866位置

image-20211108224839058

分析401767函数,发现是明显的RC4加密

随便输入一个假的flag,12345678901234567890123456, 然后断下,看加密后的数据

image-20211108230241234

写脚本得到密钥流

1
2
3
4
5
6
7
8
fake_flag = "12345678901234567890123456"
enc_fake_flag = [ 0xD5, 0x25, 0xE2, 0xB6, 0xF1, 0x99, 0x4B, 0xD4, 0xB5, 0x1B,
0x81, 0xD0, 0x47, 0x8F, 0xEF, 0x35, 0x05, 0x46, 0x48, 0xEB,
0x8C, 0x21, 0x6C, 0xB8, 0x05, 0x8D]

key = [ord(fake_flag[i]) ^ enc_fake_flag[i] for i in range(26)]
print(key)
# [228, 23, 209, 130, 196, 175, 124, 236, 140, 43, 176, 226, 116, 187, 218, 3, 50, 126, 113, 219, 189, 19, 95, 140, 48, 187]

然后提取出dword_403040解密即可

1
2
3
4
5
enc = [0xFFFFFFB7, 0x52, 0x0FFFFFF85, 0x0FFFFFFC1, 0x0FFFFFF90, 0x0FFFFFFE9, 0x7, 0xFFFFFFB8, 0x0FFFFFFE4, 0x1A, 0x0FFFFFFC3, 0x0FFFFFFBD, 0x1D, 0x0FFFFFF8E, 0x0FFFFFF85, 0x46, 0x0, 0x21, 0x44, 0x0FFFFFFAF, 0x0FFFFFFEF, 0x70, 0x32, 0x0FFFFFFB5, 0x11, 0x0FFFFFFC6]
key = [228, 23, 209, 130, 196, 175, 124, 236, 140, 43, 176, 226, 116, 187, 218, 3, 50, 126, 113, 219, 189, 19, 95, 140, 48, 187]
flag = [chr((enc[i] & 0XFF) ^ key[i]) for i in range(26)]
print("".join(flag))
# SETCTF{Th1s_i5_E2_5tRcm9!}

power

拿到题目,附件是ARM汇编源文件

直接用arm-none-eabi-as.exe power编译下生成a.out

IDA打开

image-20211109101313110

发现是AES加密,这里写的是CBC模式,但其实是ECB模式,写脚本解密即可

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
47
from Crypto.Cipher import AES
import base64
import binascii


class Aescrypt():
def __init__(self, key, model, iv):
self.key = self.add_16(key)
self.model = model
self.iv = iv

def add_16(self, par):
if type(par) == str:
par = par.encode()
while len(par) % 16 != 0:
par += b'\x00'
return par

def aesencrypt(self, text):
text = self.add_16(text)
if self.model == AES.MODE_CBC:
self.aes = AES.new(self.key, self.model, self.iv)
elif self.model == AES.MODE_ECB:
self.aes = AES.new(self.key, self.model)
self.encrypt_text = self.aes.encrypt(text)
return self.encrypt_text

def aesdecrypt(self, text):
if self.model == AES.MODE_CBC:
self.aes = AES.new(self.key, self.model, self.iv)
elif self.model == AES.MODE_ECB:
self.aes = AES.new(self.key, self.model)
self.decrypt_text = self.aes.decrypt(text)
self.decrypt_text = self.decrypt_text.strip(b"\x00")
return self.decrypt_text


if __name__ == '__main__':
passwd = b"this_is_a_key!!!"
enc_flag_str = "1030a9254d44937bed312da03d2db9adbec5762c2eca7b5853e489d2a140427b"
enc_flag = binascii.unhexlify(enc_flag_str)

aescryptor = Aescrypt(passwd, AES.MODE_ECB, None) # ECB
text = aescryptor.aesdecrypt(enc_flag)
print("明文:", text)

# 明文: b'flag{y0u_found_the_aes_12113112}'

Eat_something

核心代码在Eat_something.wasm

image-20211109101808006

找到工具将wasm转为.o文件 https://www.52pojie.cn/thread-1438499-1-1.html

用IDA打开,找到w2c_checkright函数,这是验证flag的地方

image-20211109102132206

核心算法就是这一句 v13 != (i32_load(w2c_memory, v16 + 12LL) ^ (2 * v10))

翻译下就是enc[i] != i ^ (flag[i] * 2)

image-20211109102352748

image-20211109102414299

将enc提取出来,写脚本即可

1
2
3
4
5
6
7
8
9
10
11
12
enc =   [0x86, 0x8B, 0xAA, 0x85, 0xAC, 0x89, 0xF0, 0xAF, 0xD8, 0x69, 
0xD6, 0xDD, 0xB2, 0xBF, 0x6E, 0xE5, 0xAE, 0x99, 0xCC, 0xD5,
0xBC, 0x8B, 0xF2, 0x7D, 0x7A, 0xE3, 0x59, 0x6F, 0x75, 0x20,
0x61, 0x72, 0x65, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x21,
0x00, 0x59, 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x77,
0x72, 0x6F, 0x6E, 0x67, 0x21, 0x00]

flag = []
for i in range(26):
flag .append(chr((i ^ enc[i]) // 2))
print("".join(flag))
# CETCTF{Th0nk_Y0u_DocTOr51}

最后将CETCTF 改为 SETCTF即为flag