cscg ist super
This commit is contained in:
1
2026/cscg/crypto/intro3/.python-version
Normal file
1
2026/cscg/crypto/intro3/.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.13
|
||||
27
2026/cscg/crypto/intro3/main.py
Normal file
27
2026/cscg/crypto/intro3/main.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
|
||||
BITS = 56
|
||||
|
||||
FLAG = os.getenv("FLAG", "CSCG{TESTFLAG}")
|
||||
|
||||
A = int.from_bytes(os.urandom(BITS//8), "little")
|
||||
B = int.from_bytes(os.urandom(BITS//8), "little")
|
||||
SEED = int.from_bytes(os.urandom(BITS//8), "little")
|
||||
|
||||
def rng(x, size):
|
||||
return (x*A+B) & ((2**size)-1)
|
||||
|
||||
def gen_random(seed, bits, mask):
|
||||
state = seed
|
||||
while True:
|
||||
state = rng(state, bits)
|
||||
yield state & mask
|
||||
|
||||
def main():
|
||||
print("Here are some random numbers, now guess the flag")
|
||||
rng = gen_random(SEED, BITS, 0xFF)
|
||||
for i in range(len(FLAG)):
|
||||
print(next(rng) ^ ord(FLAG[i]))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
139
2026/cscg/crypto/intro3/msg.txt
Normal file
139
2026/cscg/crypto/intro3/msg.txt
Normal file
@@ -0,0 +1,139 @@
|
||||
Here are some random numbers, now guess the flag
|
||||
212
|
||||
222
|
||||
52
|
||||
234
|
||||
44
|
||||
156
|
||||
96
|
||||
149
|
||||
122
|
||||
84
|
||||
164
|
||||
111
|
||||
148
|
||||
46
|
||||
218
|
||||
43
|
||||
165
|
||||
239
|
||||
14
|
||||
239
|
||||
31
|
||||
175
|
||||
5
|
||||
149
|
||||
122
|
||||
68
|
||||
177
|
||||
123
|
||||
162
|
||||
44
|
||||
224
|
||||
55
|
||||
225
|
||||
238
|
||||
26
|
||||
157
|
||||
48
|
||||
155
|
||||
90
|
||||
129
|
||||
125
|
||||
105
|
||||
176
|
||||
20
|
||||
174
|
||||
4
|
||||
242
|
||||
43
|
||||
228
|
||||
215
|
||||
26
|
||||
232
|
||||
48
|
||||
155
|
||||
112
|
||||
171
|
||||
98
|
||||
87
|
||||
197
|
||||
21
|
||||
176
|
||||
31
|
||||
133
|
||||
84
|
||||
228
|
||||
215
|
||||
30
|
||||
239
|
||||
20
|
||||
174
|
||||
90
|
||||
171
|
||||
37
|
||||
111
|
||||
142
|
||||
111
|
||||
144
|
||||
47
|
||||
132
|
||||
5
|
||||
167
|
||||
238
|
||||
26
|
||||
148
|
||||
103
|
||||
132
|
||||
113
|
||||
167
|
||||
97
|
||||
111
|
||||
160
|
||||
123
|
||||
161
|
||||
4
|
||||
241
|
||||
39
|
||||
225
|
||||
239
|
||||
32
|
||||
251
|
||||
33
|
||||
132
|
||||
113
|
||||
187
|
||||
98
|
||||
108
|
||||
160
|
||||
119
|
||||
161
|
||||
46
|
||||
218
|
||||
93
|
||||
240
|
||||
216
|
||||
26
|
||||
148
|
||||
35
|
||||
151
|
||||
96
|
||||
213
|
||||
112
|
||||
95
|
||||
160
|
||||
99
|
||||
184
|
||||
47
|
||||
206
|
||||
47
|
||||
196
|
||||
239
|
||||
69
|
||||
156
|
||||
59
|
||||
175
|
||||
78
|
||||
172
|
||||
42
|
||||
112
|
||||
9
2026/cscg/crypto/intro3/pyproject.toml
Normal file
9
2026/cscg/crypto/intro3/pyproject.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[project]
|
||||
name = "intro3"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"z3-solver>=4.16.0.0",
|
||||
]
|
||||
52
2026/cscg/crypto/intro3/solve.py
Normal file
52
2026/cscg/crypto/intro3/solve.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from z3 import BitVec, Solver, sat
|
||||
|
||||
# Replace this with the actual numbers printed by the program
|
||||
with open("./msg.txt") as f:
|
||||
OUTPUTS = [int(line) for line in f.readlines()[1:]]
|
||||
|
||||
BITS = 56
|
||||
MASK = 0xFF
|
||||
|
||||
# Symbolic variables for the LCG parameters
|
||||
A = BitVec('A', BITS)
|
||||
B = BitVec('B', BITS)
|
||||
SEED = BitVec('SEED', BITS)
|
||||
|
||||
s = Solver()
|
||||
|
||||
# Define the state sequence
|
||||
states = [SEED]
|
||||
for i in range(len(OUTPUTS)):
|
||||
# Next state transition: s_i+1 = (s_i * A + B) & (2**56 - 1)
|
||||
# Z3 BitVec arithmetic handles the modulo 2^n automatically
|
||||
next_state = (states[i] * A) + B
|
||||
states.append(next_state)
|
||||
|
||||
# Known prefix: "CSCG{"
|
||||
known_prefix = "CSCG{"
|
||||
for i, char in enumerate(known_prefix):
|
||||
# output = (state_i+1 & MASK) ^ ord(FLAG[i])
|
||||
# Therefore: (state_i+1 & MASK) == output ^ ord(FLAG[i])
|
||||
s.add((states[i+1] & MASK) == OUTPUTS[i] ^ ord(char))
|
||||
|
||||
# If the flag ends with '}', add that constraint as well
|
||||
s.add((states[len(OUTPUTS)] & MASK) == OUTPUTS[-1] ^ ord('}'))
|
||||
|
||||
if s.check() == sat:
|
||||
model = s.model()
|
||||
print("Found LCG Parameters:")
|
||||
print(f"A: {model[A]}")
|
||||
print(f"B: {model[B]}")
|
||||
print(f"SEED: {model[SEED]}")
|
||||
|
||||
# Recover the flag
|
||||
flag = ""
|
||||
for i in range(len(OUTPUTS)):
|
||||
# Extract the lower 8 bits of the calculated state
|
||||
state_val = model.evaluate(states[i+1]).as_long()
|
||||
flag_char = chr((state_val & MASK) ^ OUTPUTS[i])
|
||||
flag += flag_char
|
||||
|
||||
print(f"Flag: {flag}")
|
||||
else:
|
||||
print("Unsatisfiable: Check if the prefix or output data is correct.")
|
||||
29
2026/cscg/crypto/intro3/uv.lock
generated
Normal file
29
2026/cscg/crypto/intro3/uv.lock
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "intro3"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "z3-solver" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "z3-solver", specifier = ">=4.16.0.0" }]
|
||||
|
||||
[[package]]
|
||||
name = "z3-solver"
|
||||
version = "4.16.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/93/3b/2b714c40ef2ecf6d8aa080056b9c24a77fe4ca2c83abd83e9c93d34212ac/z3_solver-4.16.0.0.tar.gz", hash = "sha256:263d9ad668966e832c2b246ba0389298a599637793da2dc01cc5e4ef4b0b6c78", size = 5098891, upload-time = "2026-02-19T04:14:08.818Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/5d/9b277a80333db6b85fedd0f5082e311efcbaec47f2c44c57d38953c2d4d9/z3_solver-4.16.0.0-py3-none-macosx_15_0_arm64.whl", hash = "sha256:cc52843cfdd3d3f2cd24bedc62e71c18af8c8b7b23fb05e639ab60b01b5f8f2f", size = 36963251, upload-time = "2026-02-19T04:13:44.303Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/c4/fc99aa544930fb7bfcd88947c2788f318acaf1b9704a7a914445e204436a/z3_solver-4.16.0.0-py3-none-macosx_15_0_x86_64.whl", hash = "sha256:e292df40951523e4ecfbc8dee549d93dee00a3fe4ee4833270d19876b713e210", size = 47523873, upload-time = "2026-02-19T04:13:48.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/e6/98741b086b6e01630a55db1fbda596949f738204aac14ef35e64a9526ccb/z3_solver-4.16.0.0-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:afae2551f795670f0522cfce82132d129c408a2694adff71eb01ba0f2ece44f9", size = 31741807, upload-time = "2026-02-19T04:13:52.283Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/2e/295d467c7c796c01337bff790dbedc28cf279f9d365ed64aa9f8ca6b2ba1/z3_solver-4.16.0.0-py3-none-manylinux_2_38_aarch64.whl", hash = "sha256:358648c3b5ef82b9ec9a25711cf4fc498c7881f03a9f4a2ea6ffa9304ca65d94", size = 27326531, upload-time = "2026-02-19T04:13:55.787Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/df/29816ce4de24cca3acb007412f9c6fba603e55fcc27ce8c2aade0939057a/z3_solver-4.16.0.0-py3-none-win32.whl", hash = "sha256:cc64c4d41fbebe419fccddb044979c3d95b41214547db65eecdaa67fafef7fe0", size = 13341643, upload-time = "2026-02-19T04:13:58.88Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/20/cef4f4d70845df24572d005d19995f92b7f527eb2ffb63a3f5f938a0de2e/z3_solver-4.16.0.0-py3-none-win_amd64.whl", hash = "sha256:eb5df383cb6a3d6b7767dbdca348ac71f6f41e82f76c9ac42002a1f55e35f462", size = 16419861, upload-time = "2026-02-19T04:14:03.232Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/18/7dc1051093abfd6db56ce9addb63c624bfa31946ccb9cfc9be5e75237a26/z3_solver-4.16.0.0-py3-none-win_arm64.whl", hash = "sha256:28729eae2c89112e37697acce4d4517f5e44c6c54d36fed9cf914b06f380cbd6", size = 15084866, upload-time = "2026-02-19T04:14:06.355Z" },
|
||||
]
|
||||
Reference in New Issue
Block a user