defxor_encrypt(data: bytes, prng: LunarLCG) -> bytes: out = bytearray()
for b in data: k = prng.next_byte() out.append(b ^ k)
returnbytes(out)
for i inrange(6): prng = LunarLCG(m, a, c, leak_states[i]) flag = xor_encrypt(ct, prng) ifb"flag{"in flag: print(flag) #b'flag{ZeroG_lcg_stream_recovery}'
#!/usr/bin/env python3 """ LitCTF2026 — One-time pad reused for two messages (40 bytes each). Players receive output.txt and README; they do not receive secret.py. """ from __future__ import annotations
import argparse import os from pathlib import Path
try: from secret import M1_FLAG except ImportError: raise SystemExit( "secret.py (organizer) is required to generate ciphertext; " "players work from output.txt only." )
# Public second message — duplicated in README for contestants. M2_KNOWN = b"litctf2026_xor_keystream_reuse_40bytes!!"
assertlen(M1_FLAG) == len(M2_KNOWN) == 40
defxor_bytes(a: bytes, b: bytes) -> bytes: returnbytes(x ^ y for x, y inzip(a, b))
#!/usr/bin/env python3 """ LitCTF2026 — ElGamal handshake (story) Someone left debug logging on; the private exponent x was printed alongside ciphertext. """ from __future__ import annotations
import argparse from pathlib import Path from random import randrange
from Crypto.Util.number import bytes_to_long, getPrime, getRandomRange
try: from secret import FLAG except ImportError as e: raise SystemExit("secret.py (FLAG) is required to encrypt.") from e
defgenerate_elgamal_keypair(bits: int = 512) -> tuple[int, int, int, int]: p = getPrime(bits) for _ inrange(1000): g = getRandomRange(2, min(6, p - 1)) ifpow(g, (p - 1) // 2, p) != 1: break else: raise RuntimeError("could not find suitable g") x = randrange(2, p - 1) y = pow(g, x, p) return p, g, y, x
p, g, y, x = generate_elgamal_keypair(bits=512) k = randrange(1, p - 2) m = bytes_to_long(FLAG) if m >= p: raise ValueError("flag too large for chosen p — shorten FLAG")
# === Public key (p, g, y) === # p = 9000784855376359808051354825193962042770028561343848432778443672755982397391267124312572697249531643069409873722736348916207732622884411596948807031140651 # g = 3 # y = 269130883529708333054320571854006406481346665463416017026083074488011546059928157925990665431751017523964760326934454181952822744463714981243407307134357
#!/usr/bin/env python3 """ LitCTF2026 — RSA where q is 'far' along the prime line but still close enough to p for Fermat. """ from __future__ import annotations
import argparse from pathlib import Path
import gmpy2 from Crypto.Util.number import bytes_to_long, getPrime
try: from secret import FLAG, NEXT_PRIME_STEPS except ImportError as e: raise SystemExit( "secret.py is required to generate output (FLAG, NEXT_PRIME_STEPS)." ) from e
E = 65537
defmain() -> None: parser = argparse.ArgumentParser() parser.add_argument( "--write", type=Path, help="Write n, c to this file.", ) args = parser.parse_args()
p = getPrime(512) q = p for _ inrange(NEXT_PRIME_STEPS): q = int(gmpy2.next_prime(q))
n = p * q m = bytes_to_long(FLAG) if m >= n: raise ValueError("flag too large for n")
# n = 139637440016232025690294457609899605991056011052010466558411851317943636600860419882966079629826706361935550982744312593243181819999590825159611186779613601241742349986440676188542381451066058816661317621009248513651083772907520139375108426466691332559612971244160246310746215067136490772061317571744230078911 # c = 81172369642931859390486697024961350889751244109623802937988620847486863147682579984823958801948701482096140632580173113959531836503723522945335985723867818778699337807630592078265626995722998378992215523352858561923474395550395284015986525513984910021995657780411466237306614109262460764382539311725297619429 # e = 65537
from Crypto.Util.number import * import gmpy2 import math
n = 139637440016232025690294457609899605991056011052010466558411851317943636600860419882966079629826706361935550982744312593243181819999590825159611186779613601241742349986440676188542381451066058816661317621009248513651083772907520139375108426466691332559612971244160246310746215067136490772061317571744230078911 c = 81172369642931859390486697024961350889751244109623802937988620847486863147682579984823958801948701482096140632580173113959531836503723522945335985723867818778699337807630592078265626995722998378992215523352858561923474395550395284015986525513984910021995657780411466237306614109262460764382539311725297619429 e = 65537
#!/usr/bin/env python3 """ LitCTF2026 — AES-128-ECB with a mostly fixed key (weak operational policy). """ from __future__ import annotations
import argparse from pathlib import Path
from Crypto.Cipher import AES from Crypto.Util.Padding import pad
try: from secret import FLAG, UNKNOWN_KEY_SUFFIX except ImportError as e: raise SystemExit( "secret.py is required to generate ciphertext (contains FLAG and key suffix)." ) from e
defmain() -> None: parser = argparse.ArgumentParser() parser.add_argument( "--write", type=Path, help="Write ciphertext hex to this file.", ) args = parser.parse_args()
key = KEY_PREFIX + UNKNOWN_KEY_SUFFIX c = encrypt_aes_ecb_pkcs7(FLAG, key) line = f"c = {c!r}\n" print(line, end="") if args.write: args.write.write_text(line, encoding="utf-8")
if __name__ == "__main__": main()
# c = b"\x0c\xdb'`\xc91\xf7\x05\x91+\x0fM\xed\xbc\x9b\xf1\xd8D\xcd\xfd\x0c\xb9\xb6\xb2J<\x86\x19\x06K\xb3\xa2\xa4\x18\x87<v\xac\x1bbu#\xaa\xb5I\x7f\xd8\xd3"
思路
题目用AES-128的ECB模式进行加密,给了密钥的前13个字节,对后3个字节进行爆破即可
解答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
from Crypto.Util.number import * from Crypto.Cipher import AES from tqdm import trange
KEY_PREFIX = b"LitCTF2026!!!" c = b"\x0c\xdb'`\xc91\xf7\x05\x91+\x0fM\xed\xbc\x9b\xf1\xd8D\xcd\xfd\x0c\xb9\xb6\xb2J<\x86\x19\x06K\xb3\xa2\xa4\x18\x87<v\xac\x1bbu#\xaa\xb5I\x7f\xd8\xd3"
for i in trange (256**3): low=i.to_bytes(3) key=KEY_PREFIX+low