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
|
from pwn import *
import json
BLOCK_SIZE = 32
# Nothing up my sleeve numbers (ref: Dual_EC_DRBG P-256 coordinates)
W = [0x6b17d1f2, 0xe12c4247, 0xf8bce6e5, 0x63a440f2, 0x77037d81, 0x2deb33a0, 0xf4a13945, 0xd898c296]
X = [0x4fe342e2, 0xfe1a7f9b, 0x8ee7eb4a, 0x7c0f9e16, 0x2bce3357, 0x6b315ece, 0xcbb64068, 0x37bf51f5]
Y = [0xc97445f4, 0x5cdef9f0, 0xd3e05e1e, 0x585fc297, 0x235b82b5, 0xbe8ff3ef, 0xca67c598, 0x52018192]
Z = [0xb28ef557, 0xba31dfcb, 0xdd21ac46, 0xe2a91e3c, 0x304f44cb, 0x87058ada, 0x2cb81515, 0x1e610046]
# Lets work with bytes instead!
W_bytes = b''.join([x.to_bytes(4,'big') for x in W])
X_bytes = b''.join([x.to_bytes(4,'big') for x in X])
Y_bytes = b''.join([x.to_bytes(4,'big') for x in Y])
Z_bytes = b''.join([x.to_bytes(4,'big') for x in Z])
def pad(data):
padding_len = (BLOCK_SIZE - len(data)) % BLOCK_SIZE
return data + bytes([padding_len]*padding_len)
def blocks(data):
return [data[i:(i+BLOCK_SIZE)] for i in range(0,len(data),BLOCK_SIZE)]
def xor(a,b):
return bytes([x^y for x,y in zip(a,b)])
def rotate_left(data, x):
x = x % BLOCK_SIZE
return data[x:] + data[:x]
def rotate_right(data, x):
x = x % BLOCK_SIZE
return data[-x:] + data[:-x]
def scramble_block(block):
for _ in range(40):
block = xor(W_bytes, block)
block = rotate_left(block, 6)
block = xor(X_bytes, block)
block = rotate_right(block, 17)
return block
def cryptohash(msg):
initial_state = xor(Y_bytes, Z_bytes)
msg_padded = pad(msg)
msg_blocks = blocks(msg_padded)
for i,b in enumerate(msg_blocks):
mix_in = scramble_block(b)
for _ in range(i):
mix_in = rotate_right(mix_in, i+11)
mix_in = xor(mix_in, X_bytes)
mix_in = rotate_left(mix_in, i+6)
print("Mix in: ", mix_in.hex())
initial_state = xor(initial_state,mix_in)
return initial_state.hex()
# Revert the scramble function
def unscramble(block):
for _ in range(40):
block = rotate_left(block, 17)
block = xor(X_bytes, block)
block = rotate_right(block, 6)
block = xor(W_bytes, block)
return block
# Target that we want is msg1
msg1 = X_bytes
# msg2 consists of two blocks
msg2 = Y_bytes
target = cryptohash(msg1)
state = cryptohash(msg2)
# Reverse the scrambling stage in the for loop in cryptohash
# scrambling only happens in the 2nd block
mix_in = xor(target, state)
mix_in = rotate_right(mix_in, 7)
mix_in = xor(mix_in, X_bytes)
mix_in = rotate_left(mix_in, 12)
# This is the original block
msg2_block = unscramble(mix_in)
msg2 = msg2 + msg2_block
io = remote('socket.cryptohack.org', 13405)
print(io.recvline())
to_send = dict()
to_send['m1'] = msg1.hex()
to_send['m2'] = msg2.hex()
io.sendline(json.dumps(to_send).encode())
io.interactive()
|