0xGame2024部分Reverse与Crypto

Re

week2

Xor_Random

动调获取随机数直接异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
int main(){
srand(0x77);
rand();
char v21=0x7b;
char v8;
char a[]={0x0C, 0x4F, 0x10, 0x1F, 0x4E, 0x16, 0x21, 0x12, 0x4B, 0x24,
0x10, 0x4B, 0x0A, 0x24, 0x1F, 0x17, 0x09, 0x4F, 0x07, 0x08,
0x21, 0x5C, 0x2C, 0x1A, 0x10, 0x1F, 0x11, 0x16, 0x59, 0x5A};
for(int i=0;i<30;i++){
if (i&1){
v8=v21;
}
else{
v8=v21+3;
}
printf("%c",a[i]^v8);
}
return 0;
}

Zzz

断点上面扩展了位数,且调试的时候发现输入的v5,v6,v7会被颠倒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Util.number import long_to_bytes
from libnum import n2s
from z3 import *
v10 = BitVec('v10', 32)
v11 = BitVec('v11', 32)
v12 = BitVec('v12', 32)

res=[]
solver = Solver()
solver.add(11 * v11 + 14 * v10 - v12 == 0x48FB41DDD)
solver.add(9 * v10 - 3 * v11 + 4 * v12 == 0x2BA692AD7)
solver.add((((v12 - v11)) >> 1) + (v10 ^ 0x87654321) == 3451779756)
if solver.check()==sat:
model=solver.model()
res.append(n2s(model[v10].as_long()))
res.append(n2s(model[v11].as_long()))
res.append(n2s(model[v12].as_long()))
print(res)

#0xGame{e544267d-7812-44b3-a35d-d085a85201a4}

week3

BabyAsm

直接正向输出flag

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
a=[20,
92,
43,
69,
81,
73,
95,
23,
72,
22,
24,
69,
25,
27,
22,
17,
23,
29,
24,
73,
17,
24,
85,
27,
112,
76,
15,
92,
24,
1,
73,
84,
13,
81,
12,
0,
84,
73,
82,
8,
82,
81,
76,
125]
print(len(a))
for i in range(22):
a[i]+=28
for i in range(22,43):
a[i]=a[i]^a[i-22]
s=''
for i in range(len(a)):
s+=chr(a[i])
print(s)

Puzzle

9*9的数组,大概率是数独题

手算比较麻烦,建议直接套模板

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

# 定义数独的9x9网格
board = [[5, 7, 0, 9, 4, 0, 8, 0, 0],
[0, 0, 8, 0, 3, 0, 0, 0, 5],
[0, 1, 0, 2, 0, 0, 0, 3, 7],
[0, 0, 9, 7, 2, 0, 0, 0, 0],
[7, 3, 4, 0, 0, 8, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 7, 5, 1],
[3, 0, 0, 0, 1, 4, 2, 0, 0],
[0, 6, 0, 0, 0, 2, 0, 4, 0],
[0, 2, 7, 0, 0, 9, 5, 0, 0]]

# 创建一个9x9的矩阵,存放Z3变量(每个格子一个变量)
X = [[Int(f'x_{i}_{j}') for j in range(9)] for i in range(9)]

# 约束1:所有变量取值范围在1到9之间
cells_c = [And(X[i][j] >= 1, X[i][j] <= 9) for i in range(9) for j in range(9)]

# 约束2:每一行的数字不能重复
rows_c = [Distinct(X[i]) for i in range(9)]

# 约束3:每一列的数字不能重复
cols_c = [Distinct([X[i][j] for i in range(9)]) for j in range(9)]

# 约束4:每个3x3的子方格中的数字不能重复
squares_c = [Distinct([X[3 * i + di][3 * j + dj] for di in range(3) for dj in range(3)])
for i in range(3) for j in range(3)]

# 约束5:已知的棋盘数字需要保持不变
instance_c = [If(board[i][j] == 0, True, X[i][j] == board[i][j]) for i in range(9) for j in range(9)]

# 创建求解器
solver = Solver()
solver.add(cells_c + rows_c + cols_c + squares_c + instance_c)

# 检查是否有解
if solver.check() == sat:
model = solver.model()
result_board = [[model.evaluate(X[i][j]) for j in range(9)] for i in range(9)]
# 打印填充好的数独
for row in result_board:
print(row)

# 将解转换为字符串形式,用于生成输入
nextLine = ""
for i in range(9):
for j in range(9):
if board[i][j] == 0:
nextLine += str(model.evaluate(X[i][j]))

print(nextLine)
else:
print("无解")

求出nextLine之后6个数字一组,10转16之后作为字符加到sb中输出

tea

一开始把密文前后交换,直接解密发现中间错误

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

int main() {
uint32_t v[2] = {1, 2};
uint32_t v0 = v[0], v1 = v[1], sum, i; /* set up */
uint32_t delta = 0x61C88647;
uint32_t v5[10] = {0x85336dd3,0x2a7a7c3b,0x64306238,0x36396434,0x62336364,0x38376533,0x37323664,0x33363463,0xf8ee8ea2,0xc9b65cce};
unsigned int k[4] = {2,0,2,4}, l = 0, r = 0;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (int m = 0; m < 10; m += 2) {
sum = delta*(-32);
for (i = 0; i < 32; i++) {
v5[m + 1] -= ((v5[m] << 4) + k2) ^ (v5[m] + sum) ^ ((v5[m] >> 5) + k3);
v5[m] -= ((v5[m + 1] << 4) + k0) ^ (v5[m + 1] + sum) ^ ((v5[m + 1] >> 5) + k1);
sum += delta;
}
}

for (int i = 0; i < 10; i++) {
for (int m = 0; m <= 3; m++) {
printf("%c", (v5[i] >> (8 * m)) & 0xff);
}
}
return 0;
}

调试发现之后前8位和最后8位进行了加密,也就是说中间24位不变

1
0xGame{e8b0d4d96dc3b3e78d627c463c9953a1}

ezAndroid

直接搜索secret找到密文

week4

PyPro

python3.12无法完全反编译,要用pydas

知道先aes_ecb再base64

cy好像解不了用脚本解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

key = 0x554B134A029DE539438BD18604BF114

key_bytes = key.to_bytes(16, byteorder='big')
print(key_bytes)

encrypted_data = "2e8Ugcv8lKVhL3gkv3grJGNE3UqkjlvKqCgJSGRNHHEk98Kd0wv6s60GpAUsU+8Q"

encrypted_bytes = base64.b64decode(encrypted_data)


cipher = AES.new(key_bytes, AES.MODE_ECB)

try:
decrypted_data = unpad(cipher.decrypt(encrypted_bytes), AES.block_size)

print("解密结果:", decrypted_data.decode('utf-8'))
except (ValueError, KeyError):
print("解密失败或填充错误!")

发现密钥是奇数位,15.5个字节,前面补一个0

tea2.0

main一个tea

交叉引用密文发现有tls

发现也是一次tea,但是不用管直接动调获取最后的密文

有个奇怪的点是明明密文有48位,为什么比较的时候只有44位

经过调试发现最后一轮的v1初始值是0

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void decrypt(uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x61C88647, sum = delta * (-64);
for (i=0; i < 64; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum += delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);

}
v[0] = v0; v[1] = v1;
}

int main() {
uint32_t const k[4] = {0x4512,0x9832,0x5647,0x6314};
uint32_t enc[] = {0xd04bb2c4,0xa625cf11,0x57686f2b,0x3b181680,0x6fc33f75,0x1779b334,0xd95ca4f6,0xc1ca9fa2,0x651a6aff,0xc9ddba37,0x3087d163,0x187d7e10};
for(int i=0; i<12; i+=2){
decrypt(&enc[i], k);
}
for (int i = 0; i < 12; i++) {
for (int m = 0; m <= 3; m++) {
printf("%c", (enc[i] >> (8 * m)) & 0xff);
}
}
return 0;
}

MineSweeper

先是交换后面异或,另外从资源段加载密文

imgimg

haha就是KEY

enc从resources.assets中加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
key='0xoX0XOxOXoxGAME'
arr=[0x45,0x21,0x3E,0x08,0x57,0x31,0x09,0x4D,0x42,0x45,0x42,0x44,0x5D,0x5A,0x4B,0x4B,
0x52,0x56,0x16,0x44,0x66,0x45,0x6C,0x40,0x57,0x44,0x33,0x35,0x51,0x75,0x0D,0x58,
0x15,0x71,0x11,0x1B,0x0B,0x08,0x76,0x04,0x4F,0x5C,0x68,0x3C]
num=0
s='This is: True_KEY!for #0xgAmE_Unity~Cryption'
print(len(s))
KEY=[]
for i in range(len(s)):
KEY.append(ord(s[i]))
for i in range(44):
num=(num+ord(key[i%len(key)]))%44
KEY[i],KEY[num]=KEY[num],KEY[i]
for i in range(44):
arr[i]^=KEY[i]
print(chr(arr[i]),end="")

#0xGame{36ecd059-b3e7-73c8-fa80-0a2abef3c757}

crack

经过调试发现异或的数一直为6

问gpt发现是sha256

调试发现buf1就是输入的地址,也就是输入特定hash值即可

1
0xGame{1b4e549d12ccb4bb4936f95fedecebf55494dec8}

JustSoso

getKey在native层

直接在资源段搜索密文

得到key后rc4,有一处魔改

之后再base64

getKey的部分静态有点复杂

直接尝试用objection注入得到rc4的key,android hooking watch class_method com.ctf.justsoso.MainActivity.getKey –dump-return

用frida也行,frida -U -l 1.js -f com.ctf.justsoso

最后解密即可

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
import base64
def rc4(data, key):
S = [0]*256
for i in range(256):
S[i]=256-i
j = 0
out = []

for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]

i = j = 0
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
out.append(char ^ S[(S[i] + S[j]) % 256])

return bytes(out)

s='nB9RCjwReif5P1H1MYO6m/hucCGjI6EE9wWEx/E4N+bO5k5ior6MnqAGQfc='
out=base64.b64decode(s)


data = bytes([0x9c, 0x1f, 0x51, 0x0a, 0x3c, 0x11, 0x7a, 0x27, 0xf9, 0x3f, 0x51, 0xf5, 0x31, 0x83, 0xba, 0x9b, 0xf8, 0x6e, 0x70, 0x21, 0xa3, 0x23, 0xa1, 0x04, 0xf7, 0x05, 0x84, 0xc7, 0xf1, 0x38, 0x37, 0xe6, 0xce, 0xe6, 0x4e, 0x62, 0xa2, 0xbe, 0x8c, 0x9e, 0xa0, 0x06, 0x41, 0xf7])
key = bytes([171,149,153,151,193,31,143,241,189,165,181,193,153,161])

decrypted = rc4(out, key)
print(decrypted)
#0xGame{fd51ce4b-4556-4cf9-9430-67480614e43b}

Crypto

week1

crt-1

e和phi不互素,先求出e//2对应的m,再开根号,答案就是其中一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
n,e = (1022053332886345327, 294200073186305890)
c = 107033510346108389

phi = 970868178 * 1052721012
#print(gcd(e,phi))
d = invese_mod(e//2, phi)
m2 = pow(c,d,n)

P.<x> = PolynomialRing(Zmod(n))
f = x^2 - m2
res = f.roots(multiplicities=False)

for i in res:
MD5(int(i))

'127016d0be858ef48a99723710ad4d49'
'f4107420d94cc7037114376d8566d4ef'
'3932f6728585abbf751a212f69276d3e'
'15820afdb9a129e89e40e57f40ff8de9'

week2

rc4

前半部分求得四个字符,后半部分注意先fromhex

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
from random import choice
from hashlib import sha256
from string import ascii_letters, digits
while(1):
s4 = ''.join([choice(ascii_letters+digits) for _ in range(4)])
#print(s4)
s20=s4+'5mcbb8TCD9muMJy0'
s=sha256(s20.encode()).hexdigest()
if s=='08d287b38cb45c90dd1a8ab20484d8122119e2e50e50b60300ee30b74a86f456':
print(s4)
break

a='edd186458e9679384d4623dcc37845c803f5e70cf8c60fbe5a339de88bbf93540b8ba4e407d97cadaf2fa4499d88dea4a87471'
a=bytes.fromhex(a)
b='01234567890abcdef'*6
b=bytes.fromhex(b)
print(b)
m=[]
for i in range(len(b)):
m.append(a[i]^b[i])
print(m)

m=[236, 242, 195, 34, 7, 156, 197, 230, 189, 84, 23, 138, 187, 232, 238, 5, 236, 244, 196, 73, 159, 79, 5, 2, 132, 195, 143, 220, 221, 199, 3, 255, 198, 100, 165, 199, 66, 190, 245, 167, 19, 241, 84, 91, 169, 222, 166, 52, 3, 185, 158]

enc='dc8a84436af9bede8c622fb888dbd928dac3f778b2763461b3eeebecebf72ecca302c6a324dbc4c572c43226'
enc=bytes.fromhex(enc)
flag=''
for i in range(len(enc)):
flag+=chr(enc[i]^m[i%len(m)])
print(flag)
#0xGame{81682337-6731-91c7-d060-3efcdfe1ba5f}

RSAIV

因为交互的总时间足够长,challenge2适合yafu手动解后输入

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
from math import isqrt
from random import choice
from hashlib import sha256
from string import ascii_letters, digits
from Crypto.Util.number import *
from gmpy2 import gmpy2, gcdext
from pwn import *

io= remote('118.195.138.159',10003)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()



def ch0(s):
n,e,c=eval(s)
# n=1748540272127031261953491227523826413186688228587730569034148979069843516521168331238821457
# e=3
# c=73664223980107312196785660420184405948303349111082519137365225806576685634069671168357
k = 0
t = gmpy2.iroot(c,e)
if t[1]:
#print(t[0])
sl(str(t[0]).encode())
else:
while 1:
m = gmpy2.iroot(k*n+c,e)
if m[1]:
#print(bytes_to_long(m[0]))
sl(str(bytes_to_long(m[0])).encode())
break
else:
k += 1

def ch1(s):
n,e,c,dp=eval(s)
# n=174434352212179643958855935833036063001
# e=0x10001
# c=39466599612748960141905412873983556787
# dp=6171497056913161467

for i in range(1,e):
t = (dp * e - 1) % i #这是p-1前面的系数
if t == 0:
p = (dp * e - 1) // i + 1
if n % p == 0:
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
#print(str(pow(c,d,n)).encode())
sl(str(pow(c,d,n)).encode())

def ch2(s):
n,e,c=eval(s)
# n=319642561199483600677262826186024249019
# e=170254189003332402684383900760365999599
# c=315096655202591609017165088376826841837
# p,q=fermat(n)
# phi=(p-1)*(q-1)
# d=inverse(e,phi)
# m=pow(c,d,n)
# print(m)
# sl(str(m).encode())

def ch3(s):
n,e1,c1,e2,c2=eval(s)
# n = 123859953327496855816310504481883257257
# c1 = 115331678509320635403714895034425874310
# c2 = 19516419686488748417408440624144239780
# e1 = 162726227029902673640708475886431248549
# e2 = 92095361035743610350805143550253960191
_ ,s1 ,s2 = gcdext(e1,e2)
m = pow(c1,s1,n) * pow(c2,s2,n) % n
print(str(m).encode())
sl(str(m).encode())

s=ru('sha256(XXXX+')
print(s)
s1=io.recvuntil(b') == ',drop=True)
print(s1)
s2=io.recvuntil(b'\n',drop=True)
print(s2)
while(1):
s4 = ''.join([choice(ascii_letters+digits) for _ in range(4)])
#print(s4)
s20=s4+s1.decode()
s=sha256(s20.encode()).hexdigest()
#print(type(s))
if s==s2.decode():
print(s4)
sl(s4.encode())
break

sla('>',b'0')
s=ru(')')
ch0(s)
sla('input choice:',b'1')
io.recvuntil('>',drop=True)
s=ru(')')
ch1(s)
# sla('input choice:',b'2')
# io.recvuntil('>',drop=True)
# s=ru(')')
# ch2(s)
sla('input choice:',b'3')
io.recvuntil('>',drop=True)
s=ru(')')
ch3(s)
inter()

0xGame2024部分Reverse与Crypto
https://j1ya-22.github.io/2024/10/23/0xGame2024部分Reverse与Crypto/
作者
j1ya
发布于
2024年10月23日
许可协议