2025第八届强网拟态国际精英挑战赛 -- Crypto -- WriteUp
2025第八届强网拟态国际精英挑战赛 -- Crypto -- WriteUp
前言
这次比赛也是完成了为数不多的密码方向的AK,本来想着赛后写一写WP,不过因为学业任务比较繁重,各种课程的实验都没来得及完成。拖着拖着,终于拖到了今天晚上,对比赛结束后提交的WP进行了完善补充。感觉本次赛题还是学到了不少的东西,也是纯手工搓了搓解密脚本,还是认为有记录一下的必要的。
Unsafe Parameters
task
from Crypto.Util.number import *
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
from hashlib import sha3_512
from secret import *
def genParams():
ns = []
es = []
ps = []
d = getPrime(425) # Common Private Exponent 问题
for _ in 'flag{': # 获取 5 组 密钥对,返回公钥
p, q, r = [getPrime(512) for _ in range(3)]
ps.append((p, q, r))
n = p * q * r
totient = (p - 1) * (q - 1) * (r - 1)
es.append(inverse(d, totient))
ns.append(n)
return (ns, es), (d, ps)
pub, priv = genParams()
# 需分解每个 ns[i] 对每个大素因子求和
key = sha3_512(str(sum(sum(psum) for psum in priv[1])).encode()).digest()[:16]
ct = AES.new(key, AES.MODE_ECB).encrypt(pad(flag, 16))
print(f'ns = {pub[0]}')
print(f'es = {pub[1]}')
print(f'ct = {ct}')
"""
ns = [729626364576206469704240917876675932841677846807662743683194531189219993605123671836962855605283722577718230552963049472251011326675202612492908848548419883361685662678347011887752523869081347313358470192291106167923273619672010347904232948623232956703976722596246251219832472749781700661621717970912452690860710243752051416797956410009096107757901714990018414837758557784033898837218196380413347278999394220278929595840196278059116531409774355756772349502091527, 1905432596115201099512716986634374621489368222604315919606798930577721863294916275385323430940054377575273762764157350871093106918016952598143825002497857813393515175754983371150373414986745909170502391681896252141058196242286758315439213464335711981585004206505072743627148478873299089587473670712150938286701206231734068594554186483978059254161949801153805752489828395472590106405761648181381945795038085612905557546907903561767813822101495476457137965288880829, 1364349980724204783960363890369037262456777329397270902364257972605993939460160766530889520645888701966401869980072151818996346007664249855901114579605632358191242379651843548926065735575249122023543206153088606751338328933651430885645444839242513718915066302971957689904414300766000572990594260836480347717506097403302570129593533017205416936506156113683938133811098995666977893386015199252455279325252257306124895958614122639652100229863446635612470942945471629, 801368910415539931617837996119032301790585643652894417707002521182569449104238101253556548156062846942011258499343192564944616333555000780965111384091131074358231330717413121484815002612991437436336271715078003900216545055505405363415778086330672269759661284535787363323398929120499505051378299467980018690275341014026390376705451595348674549031968858607633947674244014656615045639930798213161815130251215148286379903187335369475976106390101774566278602818405563, 966507016385573035667733231340091844033410158675175976938028218854439065352997895173668326599042719776214706325758565722305289931861889759808022284179479582700755314576250841330755684569639628012527976286442288571350327307582007959428925460653350857512795573323486273071975979456828134582982048746188934676698845075430701350305713747666370252912970653968385390246217234899448990236850880873105998296512557366752267827688836849041157572772272378435636367162425013]
es = [271264973728317298627822473902975461834475616151421882685140849409171660245987005602120200976835072966082573357282000859946014645129524701781302678299643424924092704444611429422064341444927220441684375194952864825982915148126084102832224731498348832396834993134927447743362540828447462072582023959357845229307404791804881057335208287771899121154533179273274029972648764343120454360366227609296867085751393693129946684282269737380796082741762647814800935844443493, 1003585299728442138241618739786172474341836074346983356412903232651178484164007865852681323340512406956827176253325249434459143223478630158795320316445722303141000749369087588146876087005139101967705654538148200848735795226715484701026716263131990473014248826031226350016169675911701420383849573743077161936130739955632072650333006768068396767746102320645544271946493533626477749495460960365939362830334782483616521427745117179433129272929291131199903349977861093, 528794486797786998573050589647661205854628331390578568482905276781799068613879068393786314280307765489986817827366340249545226369795434498075653554440390174127680889163962386407937584138342055553885382937486807537913781141805602397908008361192107987266566035872632130183102501118938531330140154852996630732644530954025739132771439783366022539476194754352734861357158197716623228211860189868592877935421689151152269864018399507621324672725433395533000425391708101, 63082374875671578481986217433413118060930080658278695174993640397998104913203950822096713822227514918774669078130439943184022889683633824002111416144422250644695809731240622289790840695469043596475009958463780096705571401137513331089894183226911665633164170027318352120002851940432163291498705806239158684141492080194438572549164494596965748695244152843943149994989589419519395650481254722496058552304954140980743159877918387972030837603120258130045817858729621, 120373323462979513980656435521004077312964483601298713849302793507801996545855844801219890178210569842943901523332883574699699439655256681068585396438543716728771762620808023696864023456625376138578749985774885652016790204471223404504866831356254849552890279653807176865165230965065842479979722094076544915080001416276324550993965426099480075249719779502220020343237480355441663501565965298776708377675024327374331823503627493136287447543537154779812201209689733]
ct = b'J\x08\x0c\xfe\x0eC\n\x96!\xb3\x05\xa9\x9b\xf9\n\xe3-\xf2m\xdb&.\xb5h\xe1\x0e\xd6\x89\x14\x87Z\x0b0p\xbb\xd9\x93\xd7\x1cT\xa2\xf36\x02\x8e:\\\x92'
"""
analysis
- 首先,解题思路很清晰,就是想办法分解ns数组中的每一个n,最终AES解密获取flag即可,而且这里d与es的生成方式,是一个典型的Common Private Exponent问题,参考博客Common Private Exponent Attack - sevensnight - 博客园
- 我们通过Common Private Exponent获得相应的欧拉函数后,已知φ(N),分解N。
exp
# sage 10.7
from Crypto.Cipher import AES
from hashlib import sha3_512
def factorize_multi_prime(N, phi):
"""
Recovers the prime factors from a modulus if Euler's totient is known.
This method works for a modulus consisting of any number of primes, but is considerably be slower than factorize.
More information: Hinek M. J., Low M. K., Teske E., "On Some Attacks on Multi-prime RSA" (Section 3)
:param N: the modulus
:param phi: Euler's totient, the order of the multiplicative group modulo N
:return: a tuple containing the prime factors
"""
prime_factors = set()
factors = [N]
while len(factors) > 0:
# Element to factorize.
N = factors[0]
w = randrange(2, N - 1)
i = 1
while phi % (2 ** i) == 0:
sqrt_1 = pow(w, phi // (2 ** i), N)
if sqrt_1 > 1 and sqrt_1 != N - 1:
# We can remove the element to factorize now, because we have a factorization.
factors = factors[1:]
p = gcd(N, sqrt_1 + 1)
q = N // p
if is_prime(p):
prime_factors.add(p)
elif p > 1:
factors.append(p)
if is_prime(q):
prime_factors.add(q)
elif q > 1:
factors.append(q)
# Continue in the outer loop
break
i += 1
return tuple(prime_factors)
ns = [729626364576206469704240917876675932841677846807662743683194531189219993605123671836962855605283722577718230552963049472251011326675202612492908848548419883361685662678347011887752523869081347313358470192291106167923273619672010347904232948623232956703976722596246251219832472749781700661621717970912452690860710243752051416797956410009096107757901714990018414837758557784033898837218196380413347278999394220278929595840196278059116531409774355756772349502091527, 1905432596115201099512716986634374621489368222604315919606798930577721863294916275385323430940054377575273762764157350871093106918016952598143825002497857813393515175754983371150373414986745909170502391681896252141058196242286758315439213464335711981585004206505072743627148478873299089587473670712150938286701206231734068594554186483978059254161949801153805752489828395472590106405761648181381945795038085612905557546907903561767813822101495476457137965288880829, 1364349980724204783960363890369037262456777329397270902364257972605993939460160766530889520645888701966401869980072151818996346007664249855901114579605632358191242379651843548926065735575249122023543206153088606751338328933651430885645444839242513718915066302971957689904414300766000572990594260836480347717506097403302570129593533017205416936506156113683938133811098995666977893386015199252455279325252257306124895958614122639652100229863446635612470942945471629, 801368910415539931617837996119032301790585643652894417707002521182569449104238101253556548156062846942011258499343192564944616333555000780965111384091131074358231330717413121484815002612991437436336271715078003900216545055505405363415778086330672269759661284535787363323398929120499505051378299467980018690275341014026390376705451595348674549031968858607633947674244014656615045639930798213161815130251215148286379903187335369475976106390101774566278602818405563, 966507016385573035667733231340091844033410158675175976938028218854439065352997895173668326599042719776214706325758565722305289931861889759808022284179479582700755314576250841330755684569639628012527976286442288571350327307582007959428925460653350857512795573323486273071975979456828134582982048746188934676698845075430701350305713747666370252912970653968385390246217234899448990236850880873105998296512557366752267827688836849041157572772272378435636367162425013]
es = [271264973728317298627822473902975461834475616151421882685140849409171660245987005602120200976835072966082573357282000859946014645129524701781302678299643424924092704444611429422064341444927220441684375194952864825982915148126084102832224731498348832396834993134927447743362540828447462072582023959357845229307404791804881057335208287771899121154533179273274029972648764343120454360366227609296867085751393693129946684282269737380796082741762647814800935844443493, 1003585299728442138241618739786172474341836074346983356412903232651178484164007865852681323340512406956827176253325249434459143223478630158795320316445722303141000749369087588146876087005139101967705654538148200848735795226715484701026716263131990473014248826031226350016169675911701420383849573743077161936130739955632072650333006768068396767746102320645544271946493533626477749495460960365939362830334782483616521427745117179433129272929291131199903349977861093, 528794486797786998573050589647661205854628331390578568482905276781799068613879068393786314280307765489986817827366340249545226369795434498075653554440390174127680889163962386407937584138342055553885382937486807537913781141805602397908008361192107987266566035872632130183102501118938531330140154852996630732644530954025739132771439783366022539476194754352734861357158197716623228211860189868592877935421689151152269864018399507621324672725433395533000425391708101, 63082374875671578481986217433413118060930080658278695174993640397998104913203950822096713822227514918774669078130439943184022889683633824002111416144422250644695809731240622289790840695469043596475009958463780096705571401137513331089894183226911665633164170027318352120002851940432163291498705806239158684141492080194438572549164494596965748695244152843943149994989589419519395650481254722496058552304954140980743159877918387972030837603120258130045817858729621, 120373323462979513980656435521004077312964483601298713849302793507801996545855844801219890178210569842943901523332883574699699439655256681068585396438543716728771762620808023696864023456625376138578749985774885652016790204471223404504866831356254849552890279653807176865165230965065842479979722094076544915080001416276324550993965426099480075249719779502220020343237480355441663501565965298776708377675024327374331823503627493136287447543537154779812201209689733]
ct = b'J\x08\x0c\xfe\x0eC\n\x96!\xb3\x05\xa9\x9b\xf9\n\xe3-\xf2m\xdb&.\xb5h\xe1\x0e\xd6\x89\x14\x87Z\x0b0p\xbb\xd9\x93\xd7\x1cT\xa2\xf36\x02\x8e:\\\x92'
M = int(pow(max(ns), 2 / 3))
L = matrix(ZZ, 6, 6)
L[0, 0] = M
for i in range(5):
L[0, 1 + i] = es[i]
L[i + 1, i + 1] = -ns[i]
L = L.LLL()
for i in range(6):
d = abs(L[i][0]) // M
if is_prime(d):
ps = []
for j in range(5):
tmp = factorize_multi_prime(ns[j], es[j] * d - 1)
ps.append(tmp)
key = sha3_512(str(sum(sum(psum) for psum in ps)).encode()).digest()[:16]
print(AES.new(key, AES.MODE_ECB).decrypt(ct))
# flag{9b31dd3e-aa6a-4c4d-b796-bff4e4dfe0cc}

blockchain
- 其实问题本身也不难,就是连续猜对0或1即可,起初我的思路还停留在是不是随机数的生成上可预测?最后发现,表面上如果我们选用固定的01组合,尝试1024次能一定获取flag,但是真正猜对的概率是比1/1024高的,其中存在生日攻击的思想,在这里就不证明了。




flag{ineedyou}
FMS
task
import os
import pty
from Crypto.Util.number import *
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
from hashlib import sha256
from random import randrange
from string import ascii_letters, digits
flag = os.getenv('FLAG')
class PRNG:
def __init__(self, a = None, b = None, p = None, seed = None):
"""a, b, p, seed 的选择不依赖于 PRNG 而是依赖于 random 库函数"""
self.p = p if p else getPrime(128) # 此处 getPrime 来自于 pycryptodome 库中的函数,不存在自身循环调用
self.a = a if a else randrange(1, self.p)
self.b = b if b else randrange(0, self.p)
self.state = seed if seed else randrange(0, self.p) # seed randrange(0, self.p)
def next(self):
self.state = (self.a * self.state + self.b) % self.p # LCG --> state = (a * state + b) % p
return self.state
def randbytes(self, n):
out = b''
for _ in range(n):
out += bytes([self.next() % 256]) # next % 256 for i in range(n)
return out
def choices(self, seq, k):
return [seq[self.next() % len(seq)] for _ in range(k)]
def getPrime(self, n):
while True:
num = self.randbytes(n // 8)
p = bytes_to_long(num) | (1 << (n - 1)) | 1
if isPrime(p):
return p
def getrandbits(self, n):
num = self.randbytes((n + 7) // 8)
return bytes_to_long(num) & ((1 << n) - 1)
def __repr__(self):
return f'a = {self.a}\nb = {self.b}\np = {self.p}'
prng = PRNG()
Account = {"admin": sha256(("".join(prng.choices(ascii_letters + digits, 32))).encode()).hexdigest(),
"guest": "84983c60f7daadc1cb8698621f802c0d9f9a3c3c295c810748fb048115c186ec"}
# guest --> password:guest
user = None
menu = """Flag Management System
[L]ogin
[G]et Public Key
[R]ead Flag
[E]xit"""
# Get Public key 获得 a, b, p
# 目标为还原 seed ,Account 初始化为 prng = PRNG() 之后直接采用的 choices
# L 操作可以获得验证码,采用了 PRNG 的 randbytes() 函数
if __name__ == "__main__":
while True:
print(menu)
op = input(">>> ").strip().upper()
if op == "L" or op == "LOGIN":
vcode = prng.randbytes(4).hex().rjust(8, '0')
print(f"Verification code: {vcode}")
username = input("Username: ").strip() # 用户名
password = input("Password: ").strip() # 密码
verify = input("Verification code: ").strip() # 验证码
if verify != vcode:
print("Verification code error!")
continue
if username in Account and Account[username] == sha256(password.encode()).hexdigest():
print(f"Welcome, {username}!")
user = username
else:
print("Login failed!")
elif op == "G" or op == "GET PUBLIC KEY":
print(prng)
elif op == "R" or op == "READ FLAG":
if user == "admin":
key = prng.randbytes(16)
iv = prng.randbytes(16)
aes = AES.new(key, AES.MODE_CBC, iv)
print(aes.encrypt(pad(flag.encode(), 16)).hex())
else:
print("Permission denied!")
elif op == "E" or op == "EXIT":
print("Goodbye!")
exit(0)
else:
print("Invalid option!")
analysis
- 根据题目描述或者代码分析,获取flag的思路就是,首先你需要进行随机数预测求取seed,之后登录该seed进行admin登录,然后获取得到AES加密的flag,既然有seed了,那我们就直接往后消耗next()就可以恢复key和iv了。
- 这里所说的随机数就是每次L产生输出的Verification(验证码)
- 这里也很明显,next()为一个LCG问题,再详细点就是一个HNP问题,需要注意的就是,我们需要获取足够多的数据,但是这里接收的数据必须保证HNP能够恢复seed。所以这里我是接收了200组的Verification进行规约,本地尝试了一下,200组足够了,写一个交互程序,不断地收集数据,之后再去另外一个终端求解seed,直接利用main里面的password的生成方式得到登录密码,最后获取AES加密后的密文即可。
- 这里不得不说一下,这个靶机,如果你有一段时间不操作它,他就会挂掉,第一次求解的结果就被这样挂掉了。
- 再多说一句,在你保证靶机连接还活着的时候,最好利用G来让他或者,用L的还得后续爆破。😂😂😂
get_data.py
# @Author : chatgpt-o5
from pwn import *
import re
import json
import time
HOST = "pwn-0a325d807c.challenge.xctf.org.cn"
PORT = 9999
USE_SSL = True
TARGET_CODES = 200
OUTPUT_FILE = "output.txt"
context.log_level = "error"
def get_prng_params(io):
"""发送 G 获取 a,b,p"""
io.sendlineafter(b">>>", b"G")
data = io.recvuntil(b"E]xit", drop=True).decode(errors="ignore")
# 匹配 a,b,p
a_match = re.search(r"a\s*=\s*(\d+)", data)
b_match = re.search(r"b\s*=\s*(\d+)", data)
p_match = re.search(r"p\s*=\s*(\d+)", data)
if not (a_match and b_match and p_match):
raise ValueError("无法匹配到 a,b,p 数据")
a, b, p = map(int, (a_match.group(1), b_match.group(1), p_match.group(1)))
return a, b, p
def get_verification_codes(io, count=200):
"""连续 L,收集验证码"""
codes = []
for i in range(count):
io.sendlineafter(b">>>", b"L")
try:
line = io.recvuntil(b"Verification code:", timeout=2).decode(errors="ignore")
code_line = io.recvline(timeout=1).decode(errors="ignore")
except EOFError:
break
code_match = re.search(r"([0-9a-fA-F]{8})", code_line)
if code_match:
code = code_match.group(1)
codes.append(code)
if i % 10 == 0:
print(f"[*] Collected {i+1}/{count} codes ...")
else:
continue
# 跳过 Username/Password 输入
io.sendline(b"L") # Username
io.sendline(b"L") # Password
io.sendline(b"L") # Verification code -> 错误也无所谓
return codes
def main():
print(f"[*] Connecting to {HOST}:{PORT} ...")
io = remote(HOST, PORT, ssl=USE_SSL)
io.recvuntil(b"E]xit")
# Step 1: 获取 a,b,p
a, b, p = get_prng_params(io)
print(f"[+] Got PRNG params:")
print(f" a = {a}\n b = {b}\n p = {p}")
# Step 2: 收集 200 组验证码
print("[*] Collecting verification codes ...")
codes = get_verification_codes(io, TARGET_CODES)
print(f"[+] Collected {len(codes)} verification codes.")
# Step 3: 写入文件
result = {
"a": a,
"b": b,
"p": p,
"codes": codes
}
with open(OUTPUT_FILE, "w") as f:
json.dump(result, f, indent=2)
print(f"[+] Data saved to {OUTPUT_FILE}")
print("[*] Ready to manually input admin credentials (if needed).")
io.interactive() # 保留连接,等待你手动操作
if __name__ == "__main__":
main()
search_seed.py
# sage 10.7
from Crypto.Util.number import *
from subprocess import *
from string import ascii_letters, digits
from hashlib import sha256
def flatter(M):
# compile https://github.com/keeganryan/flatter and put it in PATH
z = "[[" + "]\n[".join(" ".join(map(str, row)) for row in M) + "]]"
ret = check_output(["flatter"], input=z.encode())
from re import findall
return matrix(M.nrows(), M.ncols(), map(int, findall(b"-?\d+", ret)))
l = ['6b1bfeed', 'aef74de8', '9d23b3e3', '05338612', '5a3308f9', 'b1284a52', 'baf0a4c2', 'a42e953f', 'b1499b86', '03eb39b2', 'b7e7c3fb', 'b9dc9574', '027da1dd', 'f737b643', '85999ec6', 'cdd77858', 'd61ae49b', 'be80ab10', 'c458371d', '362fb80c', 'cc8af6bc', '4e06a93a', 'f6395bf1', '0ad0c995', '7bcd236c', '6fe615df', 'f195bb42', '8e4aefc2', 'a2492c0b', '14a75bb9', '085abee3', 'f29eea68', 'f1b5d238', '57ab0a5e', '6b22938e', 'f881b527', '178525b7', '73cd921a', 'd44c915c', '23d1ca81', '1f036582', '6a011a63', '7040b891', '7f07731a', '8dd1e594', '4cbbb4c1', 'dc1b5006', 'b036527a', '519699fc', '794abd14', '0ec9e404', 'b4fb2b32', '144befeb', '5ee886fa', '62572a81', '81b8f2c4', '8c5e0759', '65937d8c', 'e61f6979', '61d9d260', 'ca19730a', '7971b54f', '560924b9', '224dde30', '3e7e2f5e', 'bb73f3df', '51b2e175', '27eb0702', '62e581a6', '19097cd5', '80d1ed74', '24e9b0a8', '97619ffd', '1776ad1a', '15a8e79a', '6423ffd9', 'f8db28c7', 'a8188dbd', '90fbcf2f', '6bbbad77', '99520ec8', '0cf6af59', '6aeee4bd', '3e14cc66', '61b0cfa9', 'e8d90de7', '33964a36', '2d483f22', 'e2e89c61', '15fda641', '23a32073', 'ca133e61', 'd9e70213', '6405e9e0', '8a14ef9a', 'dee58027', '981956e7', '0384bed9', '953e7e6c', 'f2a02d17', '0e3ac6e6', 'a20dbb35', '0920eb64', '392d9ab1', 'd80f2ea6', 'd2e17762', 'd4b9c9be', '64dfd9d4', '2e87fbf9', 'aaa72398', '9b857bc5', '734185af', 'b8206d9f', '2e068625', 'b78544a2', '732a577b', '799b7ed3', 'd9cc7ab6', '968ee92f', 'ac36c477', 'c6bf60a9', '7c7c013a', 'c51d39fd', '01352f37', '74d9962b', 'e944438a', 'ebfc1eca', '2731a382', '1dab526d', 'c8902e5e', '62d3d744', '241bd54c', '0c4d8261', '9e22b9c5', '4ce28765', 'd330d89d', 'ff145c0c', 'e51c0d4c', '5b04f549', '397945ce', '31f3c093', 'e9821f54', '98ecf5ff', 'e55f08f8', '715ec3a3', 'ebf6f248', '5da34706', 'beb92d6d', '5f1b5cff', 'b4f6a9cb', 'f7935569', 'cc9e49c8', '6471c1d5', 'e9ec6acf', 'c5813e33', '026fe96a', 'a2817802', 'e385a6fb', '596f1744', '08b756c5', '23efd6ea', 'b4eb18f3', 'e6b4f89d', '3737fe03', '6229d4ce', '72e729d9', '89f74694', 'ab16e83c', 'fb80fb7a', '13544771', '9a59ac0f', '6bb57732', '0f25a800', '0518832c', 'c21982a3', 'f61f1d2e', '37d8defa', '3a3317fd', '56bd0eb9', '83dc44f5', 'c2a167e8', '5d3a2eee', '84f7bead', '26db914f', 'a47ea8ec', '09436d9b', '1ff38454', '86d6498c', 'e02b7943', 'd77a0f01', '161ad139', '3023d8c3', '165d345b', '1d66937d', '9f7d2aa9', 'ba4a1ddc', '36dea6d5', 'b3dd87a1', 'ed692080', '290c022e']
r = []
for rr in l:
tmp = bin(int(rr,16))[2:].zfill(32)
for i in range(4):
r.append(int(tmp[i*8:(i+1)*8],2))
h = [0] + r[:100]
a= 70662413661960838978939233394038738837
b= 190473167030056339865973654388602296753
p= 321544457139506412049945479442144216681
A = [1]
B = [0]
for i in range(1, len(h)-1):
A.append(a * A[i - 1] % p)
B.append((a * B[i - 1] + a * h[i] + b - h[i + 1]) % p)
for i in range(len(B)):
B[i] = B[i] * inverse(2 ** 8, p) % p
A = A[1:]
B = B[1:]
# print(len(A))
M = matrix(ZZ, len(A) + 2, len(A) + 2)
for i in range(len(A)):
M[i, i] = p
M[len(A), i] = A[i]
M[len(A)+1, i] = B[i]
M[i, len(A)] = M[i, len(A) + 1] = 0
M[len(A), len(A)] = 1
M[len(A)+1, len(A)+1] = 2^120
M[len(A), len(A)+1]= 0
L=flatter(M)
v = L[0]
s1 = v[-2]*2**8+h[1]
print(s1)
table = ascii_letters + digits
passwd = ''
for i in range(32):
tmp = (s1-b)*inverse(a, p)%p
passwd += table[tmp%len(table)]
s1 = tmp
passwd = passwd[::-1]
print(passwd)
# 2NtzdOLgbU9eJzZA9Hhp5FZ2bs9YrsZL
solve_flag.py
# @Author : chen_xing
from Crypto.Cipher import AES
from Crypto.Util.number import *
def fun(a, b, p, s):
return (a * s + b) % p
enc = 0x72242d138afe30fa4384dfa3250db2e876f90bb84aa39f11aae84b609291ca2a7cf6d5068c85ef51148fdfdbfe1babbd
a = 70662413661960838978939233394038738837
b = 190473167030056339865973654388602296753
p = 321544457139506412049945479442144216681
for r in range(800,1100):
key = b''
iv = b''
s = 279404651228606932570902027246647631723
for _ in range(r):
s = fun(a,b,p,s)
for i in range(16):
s = fun(a,b,p,s)
key+=bytes([s % 256])
for i in range(16):
s = fun(a,b,p,s)
iv+=bytes([s % 256])
aes = AES.new(key, AES.MODE_CBC, iv)
flag = aes.decrypt(long_to_bytes(enc))
if flag.startswith(b'flag{'):
print(flag)
# flag{brZVj2wDZL7J9uxGTeyFU4ICNgrSITTb}




- 这里后续发现看官方给的WP好像看有师傅用CUSO只取了32组验证码就进行了求解,而且脚本是一体化的,但是短时间内也没法参悟一下师傅的思路,后续有时间再学习一下。想了解思路的师傅可以移步官方WP。

2025第八届强网拟态国际精英挑战赛 -- Crypto -- WriteUp
浙公网安备 33010602011771号