This repository has been archived by the owner on Mar 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolve.py
100 lines (88 loc) · 3.2 KB
/
solve.py
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
import re
import sys
from base64 import decodebytes
import pwn as p
from matryoshka.dolls.base import DollError, DollsBase
from matryoshka.dolls.multi_base import Base16Doll, Base32Doll, Base64Doll, Base85Doll
from matryoshka.dolls.qrcode_encode import QRCodeDoll
from matryoshka.dolls.reverse import BitReverseDoll, ByteReverseDoll
from matryoshka.dolls.rgb_bytes import RGBAImageBytesDoll
from matryoshka.dolls.significant_byte import (
LeastSignificantByteDoll,
MostSignificantByteDoll,
)
from matryoshka.dolls.weak_zip import WeakZipDoll
def decode(
data: bytes,
round: int = 1,
result_regex=rb"flag{.*?}",
accepted_dolls: tuple[type[DollsBase], ...] = (),
length_threshold: int = 10,
):
def prefixed_print(*args):
p.log.info(" ".join(["--" * round + ">", *map(str, args)]))
prefixed_print("entering round", round)
attempts: list[type[DollsBase]] = []
if data.startswith(b"PK"): # PK is the magic number for ZIP files
attempts.append(WeakZipDoll)
if data.startswith(b"\x89PNG"): # PNG magic number
attempts.append(RGBAImageBytesDoll)
attempts.append(LeastSignificantByteDoll)
attempts.append(MostSignificantByteDoll)
if data.isascii(): # ASCII
charset = {bytes([c]) for c in data}
if charset == {b"0", b"1"}:
attempts.append(QRCodeDoll)
else:
attempts.append(Base16Doll)
attempts.append(Base32Doll)
attempts.append(Base64Doll)
attempts.append(Base85Doll)
attempts.append(BitReverseDoll)
attempts.append(ByteReverseDoll)
attempts = [attempt for attempt in attempts if attempt not in accepted_dolls]
for attempt in attempts:
prefixed_print(f"trying {attempt.__name__}")
try:
result = attempt().decode(data)
except DollError as e:
prefixed_print(f"failed {attempt.__name__}: {e}")
continue
if len(result) < length_threshold:
prefixed_print(f"failed {attempt.__name__}: length not accepted")
continue
if re.search(result_regex, result, re.DOTALL):
prefixed_print(f"success {attempt.__name__}: {result}")
return result
prefixed_print("result not clear, recursive decode begin")
result = decode(result, round + 1, result_regex, (*accepted_dolls, attempt))
if result:
return result
prefixed_print("round failed")
return None
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <host> <port>")
sys.exit(1)
_, host, port = sys.argv
s = p.remote(host, port)
s.recvuntil(b"name")
s.sendline(b"mix")
while True:
data = s.recvuntil(b"-----END MATRYOSHKA MESSAGE-----")
round_data = re.search(rb"Round (\d+)/(\d+)", data)
assert round_data
round = int(round_data.group(1))
total_rounds = int(round_data.group(2))
p.log.info(f"Round {round}/{total_rounds}")
data_chunk = re.search(
b"-----BEGIN MATRYOSHKA MESSAGE-----\n(.*)\n-----END MATRYOSHKA MESSAGE-----",
data,
re.DOTALL,
)
assert data_chunk
data = decode(decodebytes(data_chunk.group(1)))
assert data
s.sendline(data)
if round == total_rounds:
break
s.interactive()