[2024/08/01] BUUOJ刷题 Re
[ACTF新生赛2020] Oruga
抄出来爆破
#include <iostream>
unsigned char byte_201020[256] = {
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x23, 0x23, 0x23,
0x00, 0x00, 0x00, 0x23, 0x23, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4C, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x45,
0x00, 0x00, 0x00, 0x30, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x45,
0x54, 0x54, 0x54, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x54, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x54, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x21, 0x00, 0x00, 0x00, 0x45, 0x45
};
int __fastcall sub_78A(const char* src)
{
int v2; // [rsp+Ch] [rbp-Ch]
int v3; // [rsp+10h] [rbp-8h]
int v4; // [rsp+14h] [rbp-4h]
v2 = 0;
v3 = 5;
v4 = 0;
while (byte_201020[v2] != 0x21)
{
v2 -= v4;
if (src[v3] != 'W' || v4 == -16)
{
if (src[v3] != 'E' || v4 == 1)
{
if (src[v3] != 'M' || v4 == 0x10)
{
if (src[v3] != 'J' || v4 == -1)
return v3 + 1;
v4 = -1;
}
else
{
v4 = 16;
}
}
else
{
v4 = 1;
}
}
else
{
v4 = -16;
}
++v3;
while (!byte_201020[v2])
{
if (v4 == -1 && (v2 & 0xF) == 0)
return v3;
if (v4 == 1 && v2 % 16 == 15)
return v3;
if (v4 == 16 && (unsigned int)(v2 - 240) <= 0xF)
return v3;
if (v4 == -16 && (unsigned int)(v2 + 15) <= 0x1E)
return v3;
v2 += v4;
}
}
return v3 + 1;
}
int main()
{
int i;
char* src = (char*)malloc(40);
if (!src) return -1;
memcpy_s(src, 40, "actf{", 5);
int last = 5;
for (i = 0; i < 40; i++)
{
src[6 + i] = 0;
src[5 + i] = 'W';
if (sub_78A(src) == i + 6)
{
src[5 + i] = 'J';
if (sub_78A(src) == i + 6)
{
src[5 + i] = 'M';
if (sub_78A(src) == i + 6)
{
src[5 + i] = 'E';
if (sub_78A(src) == i + 6)
{
src[5 + i] = '}';
if (sub_78A(src) == i + 6)
{
break;
}
}
}
}
}
}
printf("%s", src);
free(src);
}
actf{MEWEMEWJMEWJM}
[WUSTCTF2020] level4
题目给了中序和后序排列
Practice my Data Structure code.....
Typing....Struct.....char....*left....*right............emmmmm...OK!
Traversal!
Traversal type 1:2f0t02T{hcsiI_SwA__r7Ee}
Traversal type 2:20f0Th{2tsIS_icArE}e7__w
Traversal type 3: //type3(&x[22]); No way!
显然缺了个前序排列,应该就是结果
我们用Python解
def ToPreOrder(Postorder,Inorder):
length = len(Postorder)
if length == 0:
return 0
root = Postorder[length-1]
for i in range(length):
if root == Inorder[i]:
break
print(root,end="")
ToPreOrder(Postorder[0:i],Inorder[0:i])
ToPreOrder(Postorder[i:length-1],Inorder[i+1:length])
ToPreOrder("20f0Th{2tsIS_icArE}e7__w","2f0t02T{hcsiI_SwA__r7Ee}")
# wctf2020{This_IS_A_7reE}
[GUET-CTF2019] number_game
树中序和后序排列,动调一下可以拿到替换表。
然后再分析一下,可以得知,相邻行/列不能相同,且输入只能是0 1 2 3 4
这五个字符。
写出z3-solver脚本即可。
from z3 import *
x = [BitVec(f"x{i}", 8) for i in range(25)]
s = Solver()
raw = """
1 4 # 2 3
3 0 # 1 #
0 # 2 3 #
# 3 # # 0
4 2 # # 1
"""
raw = "".join(raw.replace(' ', '').splitlines())
for i, v in enumerate(raw):
if v != '#':
s.add(x[i] == ord(v))
else:
s.add(x[i] >= ord('0'), x[i] <= ord('4'))
for i in range(5):
for j in range(5):
for k in range(j + 1, 5):
s.add(x[5 * i + j] != x[5 * i + k])
s.add(x[5 * j + i] != x[5 * k + i])
print(s)
print(s.check())
m = s.model()
ans = ""
for i in x:
ans += chr(m[i].as_long())
for i in range(5):
for j in range(5):
print(ans[5*i+j], end=' ')
print("")
# Tree transform
d_before = "0123456789"
d_after = "7381940526"
d_table = [d_before.index(d_after[i]) for i in range(len(d_before))]
print("table", d_table)
answers = [2, 7, 9, 11, 14, 15, 17, 18, 22, 23]
flag_ans = [i for i in range(10)]
for i in range(len(answers)):
flag_ans[d_table[i]] = ans[answers[i]]
flag = "".join(flag_ans)
print(flag)
sat
1 4 0 2 3
3 0 4 1 2
0 1 2 3 4
2 3 1 4 0
4 2 3 0 1
table [7, 3, 8, 1, 9, 4, 0, 5, 2, 6]
1134240024
flag{1134240024}
[2019红帽杯]xx
xxtea, S-box, 每3位为一组,每一组迭代异或。
xxtea用regadgets解,key是输入的前四个字符,我们认为输入前四个字符就是flag。
S盒用输入输出造一个,迭代异或用z3解。
from regadgets import *
from copy import deepcopy
from z3 import *
k = byte2dword(b'flag' + b'\x00' * 12)
print('key', k)
# Use My input and the data after s-box trans to make S-BOX.
enc1_s = bytes.fromhex('B5 B4 16 CB 6B CA 9C DB B9 DE C7 8E 56 94 77 66 EE AB 00 D6 0C 42 3C 70')
enc1_r = bytes.fromhex('B4 CB B5 16 CA DB 6B 9C DE 8E B9 C7 94 66 56 77 AB D6 EE 00 42 70 0C 3C')
enc = [0x6B40BCCE, 0xC0953A7C, 0x20209BEF, 0x3502F791, 0xC8021823, 0xFA5656E7]
enc = dword2byte(enc)
inv_s_box = [enc1_s.index(i) for i in enc1_r]
# s_box = [enc1_r.index(i) for i in enc1_s]
# Use Z3-Solver to solve.
s = Solver()
x = [BitVec(f"x{i}", 8) for i in range(24)]
y = deepcopy(x)
for i in range(3, 24):
for j in range(i // 3):
x[i] ^= x[j]
for i in range(len(enc)):
s.add(enc[i] == x[i])
if s.check() != sat:
print("no solve")
exit(0)
m = s.model()
result = []
for i in y:
result.append(m[i].as_long())
result = [result[inv_s_box[i]] for i in range(len(result))]
result = xxtea_decrypt(byte2dword(result), k, debug=True)
print(dword2byte(result))
# b'flag{CXX_and_++tea}\x00\x13\x00\x00\x00'
[2019红帽杯]childRE
非常有意思的一道题,首先是对于输入的flag进行一个树的后序遍历,然后是UnDecorateSymbolName(SymbolName指的是C++的编译后函数名称修饰),然后就是一个查表就解决了。
exp
from regadgets import *
from hashlib import md5
str1 = [0x28, 0x5F, 0x40, 0x34, 0x36, 0x32, 0x30, 0x21, 0x30, 0x38, 0x21, 0x36, 0x5F, 0x30, 0x2A, 0x30, 0x34, 0x34, 0x32, 0x21, 0x40, 0x31, 0x38, 0x36, 0x25, 0x25, 0x30, 0x40, 0x33, 0x3D,
0x36, 0x36, 0x21, 0x21, 0x39, 0x37, 0x34, 0x2A, 0x33, 0x32, 0x33, 0x34, 0x3D, 0x26, 0x30, 0x5E, 0x33, 0x26, 0x31, 0x40, 0x3D, 0x26, 0x30, 0x39, 0x30, 0x38, 0x21, 0x36, 0x5F, 0x30, 0x2A, 0x26]
str2 = [0x35, 0x35, 0x35, 0x36, 0x35, 0x36, 0x35, 0x33, 0x32, 0x35, 0x35, 0x35, 0x35, 0x32, 0x32, 0x32, 0x35, 0x35, 0x36, 0x35, 0x35, 0x36, 0x35, 0x35, 0x35, 0x35, 0x32, 0x34, 0x33, 0x34,
0x36, 0x36, 0x33, 0x33, 0x34, 0x36, 0x35, 0x33, 0x36, 0x36, 0x33, 0x35, 0x34, 0x34, 0x34, 0x32, 0x36, 0x35, 0x36, 0x35, 0x35, 0x35, 0x35, 0x35, 0x32, 0x35, 0x35, 0x35, 0x35, 0x32, 0x32, 0x32]
xxx = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F,
0x50, 0x7B, 0x7D, 0x61, 0x73, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B, 0x27, 0x41, 0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x22, 0x5A, 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x7A, 0x78, 0x63, 0x76, 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F]
r = []
for i in range(62):
a = xxx.index(str1[i])
b = xxx.index(str2[i])
r.append(b * 23 + a)
# private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)
print(bytes(r))
# 手动转换一下 查表
r = b'?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z'
data_from = b'abcdefghijklmnopqrstuvwxyz12345'
data_to = b'pqhrsidtujvwkebxylz1mf23n45ogca'
_, ibox = generate_sbox(data_from, data_to)
r = sbox_transform(r, ibox)
print(bytes(r))
print(f"flag{{{md5(bytes(r)).hexdigest()}}}")
# flag{63b148e750fed3a33419168ac58083f5}
学习了一下gcc和vs的名称粉碎(装饰)
修饰规则
C++ 的修饰规则为 “? + 函数名 + 标识符”
标识符的第一部分
标识符的第一部分是调用规则说明:
类型 | 符号 |
---|---|
int | H |
char | D |
void | X |
unsigned int | I |
unsigned char | E |
float | M |
double | N |
bool | _N |
struct | U |
标识符的第二部分
标识符的第二部分依次是返回值和函数参数的类型:
其中,如果类型是指针,则在标识符前增加 PA
;如果是 const 类型的指针,则增加 PB
。对于结构体,则在 U
后面添加结构体的名称,并以 @@
结尾。
标识符的第三部分
标识符的第三部分是结束符:
- 如果函数有参数,则以 “@Z” 结束,否则以 “Z” 结束。
函数名的第一部分
函数名的第一部分是函数的本名。如果该函数不是类的成员,那么就只有第一部分。
函数名的第二部分
对于类的成员的不同属性有如下规则:
属性 | 无 const | 有 const |
---|---|---|
public | @@QAE | @@QBE |
protected | @@IAE | @@IBE |
private | @@AAE | @@ABE |
同时取消标识符的第一部分。此时如果参数为类实例引用,则改为 “AAV1”,带 const 改为 “ABV1”。
例子
对于以下函数:
int Function1(char*, unsigned char);
struct mytype {
int x, y;
};
class CTest {
private:
void Function1(int);
protected:
void Function2(const CTest &src);
public:
void Function3(mytype*, int);
};
其中:
Function1 的修饰应当为:?Function1@CTest@@AAEXH@Z
Function2 的修饰应当为:?Function2@CTest@@IAEXABV1@Z
Function3 的修饰应当为:?Function3@CTest@@QAEXPAUmytype@@H@Z
[NPUCTF2020]你好sao啊
from regadgets import *
table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234{}789+/="
enc = bytes(qword2byte([0xFD370FEB59C9B9E, 0xDEAB7F029C4FD1B2, 0xFACD9D40E7636559]))
print(enc)
enc_bin = bin(b2l(enc))[2:]
print(enc_bin)
for i in range(0, len(enc_bin), 6):
v = enc_bin[i:i+6]
print(table[int(v, 2)], end='')
# b'\x9e\x9b\x9c\xb5\xfep\xd3\x0f\xb2\xd1O\x9c\x02\x7f\xab\xdeYec\xe7@\x9d\xcd\xfa'
# 100111101001101110011100101101011111111001110000110100110000111110110010110100010100111110011100000000100111111110101011110111100101100101100101011000111110011101000000100111011100110111111010
# npuctf{w0w+y0U+cAn+r3lllY+dAnc3}
[RoarCTF2019]polyre
d810 反混淆,然后CRC64,用z3解。
from regadgets import *
from z3 import *
from copy import deepcopy
enc = b"\x96\x62\x53\x43\x6D\xF2\x8F\xBC\x16\xEE\x30\x05\x78\x00\x01\x52\xEC\x08\x5F\x93\xEA\xB5\xC0\x4D\x50\xF4\x53\xD8\xAF\x90\x2B\x34\x81\x36\x2C\xAA\xBC\x0E\x25\x8B\xE4\x8A\xC6\xA2\x81\x9F\x75\x55\xB3"
def decrypt(x):
s = Solver()
y = BitVec("x", 64)
z = deepcopy(y)
for i in range(64):
y = If(LShR(y, 63) == 1, (y*2) ^ 0xB0004B7679FA26B3, y * 2)
s.add(y == x)
print(s.check())
m = s.model()
return qword2byte(m[z].as_long())
r = b''
for i in range(0, len(enc), 8):
r += decrypt(byte2qword(enc[i:i+8])[0])
print(r)