Crypto
签到
1.txt:
你在一个程序员的电脑里发现了一个名为 ’flag.txt‘ 的文件,里面只有一串神秘数字:
密文:102 108 97 103 123 112 111 108 97 114 99 116 102 125
提示 计算机的世界里,只有 0 和 1。转 ascii 码就行。
exp.py:
c = "102 108 97 103 123 112 111 108 97 114 99 116 102 125"for i in c.split(): print(chr(int(i)), end="")# flag{polarctf}一封情书
题目描述.txt:
实验室的小王终于鼓起勇气要向小李表白了。为了证明情书真的是自己写的,他决定使用ECDSA数字签名。
他精心选择了一条椭圆曲线(secp256k1,就是比特币用的那条),生成了自己的私钥,然后写了两条消息:
"I love you, Li!"
"Will you be my girlfriend?"
为了确保安全,他对每条消息都进行了签名。
但是,小王犯了一个致命的密码学错误——他在两次签名中使用了相同的随机数k!
你作为旁观者,截获了他的消息和签名。你能帮他找回私钥吗?
提示:私钥就是flag,格式为flag{私钥的十六进制}。已知条件.txt:
已知数据如下:# 椭圆曲线参数 secp256k1n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141# 两封情书的内容msg1 = "I love you, Li!"msg2 = "Will you be my girlfriend?"# 两封情书的签名 (r, s)# 注意:r1 == r2,表明使用了相同的随机数kr1 = 0x2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4cs1 = 0x4c2e1a3b5d7f9e8c6a4b2d1e3f5a7c9b8e6d4f2a1c3e5b7d9f0a2c4e6f8a0b2cr2 = 0x2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4cs2 = 0x9a8c6e4d2b0f1e3c5a7b9d8e6f4a2c0d1e3f5a7b9c8d6e4f2a0b1c3d5e7f9a8bprint("请根据以上信息恢复私钥d,flag格式为 flag{hex(d)}")感觉最近见到好多次了,ECDSA 随机数复用问题,可以之前博客找找,这里不赘述了。
exp.py:
from hashlib import sha256from gmpy2 import invert
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141msg1 = b"I love you, Li!"msg2 = b"Will you be my girlfriend?"r1 = 0x2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4cs1 = 0x4c2e1a3b5d7f9e8c6a4b2d1e3f5a7c9b8e6d4f2a1c3e5b7d9f0a2c4e6f8a0b2cr2 = 0x2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4c6e8f0a2b4c6d8e0f2a4cs2 = 0x9a8c6e4d2b0f1e3c5a7b9d8e6f4a2c0d1e3f5a7b9c8d6e4f2a0b1c3d5e7f9a8bz1 = int.from_bytes(sha256(msg1).digest(), "big")z2 = int.from_bytes(sha256(msg2).digest(), "big")k = ((z1 - z2) * invert(s1 - s2, n)) % nd = ((s1 * k - z1) * invert(r1, n)) % nprint(f"flag{{{hex(d)[2:]}}}")# flag{734fc83fb33713821e4c3bc3b7c2968d585ec299976e4a19bb94feaa072e0a52}XOR流密码密钥重用
题目.txt:
某加密系统使用自定义的流密码方案:1. 用户提供密钥key2. 系统将key重复扩展至与明文等长3. 逐字节XOR加密
管理员用同一密钥加密了两个文件:- 一个英文文章(已知内容,但不知道确切用词)- 一个包含flag的简短消息(未知)
你能利用密钥重用漏洞恢复flag吗?output.txt:
XOR Stream Cipher Challenge============================================================已知明文大致内容:一篇关于 'quick brown fox' 的英文段落已知明文精确长度:380 字节密文1 (hex):04c4257bf7daca53b15470dc4041d4e636c3387becdace40a9547dd84a449ab238c96037e7d5da10be1b75800f62d2af238c303ae8c8d151b75471c14142dbaf3edf603ef0cad149fa1877da5b53c8e63fca602feeca8375b4137ec75c5e9aa73cdc283ae4cad710bb0032c24a57c9b270c32e38e3818379ae547bdd0f55d5ab3dc32e37ff8fd643bf1032c840449ab235df3432e8c88344a30477d95d5fcea322df603ae8cb8353b51962db5b53c8e63bc93939e9ced154a95832cf41529aa03fde603fefdcd35cbb0d7bc04816dfbe31c13037e3dc835fbc5474c14142c9e870f8283ea6cac242b61d77dd5b16d1a83fdb2e7be7dfd355bb0673c04c539aa9368c3433efdc8340b20673dd4a16d3b570ca3234eb8fd758bf547ecf5b539aa839c2252fe3cacd44b25471cb4142cfb429826016e7c1da10aa117dde43539aae31da257bf3dcc654fa007ac75c16c9a33ed82535e5ca8344b55462dc4e55ceaf33c9602feecaca42fa1c73c04b41c8af24c52e3ca6dcc859b6186180
Flag密文长度:44 字节密文2 (hex):36c0213cfdd79342850621db5c53e5ab64c72528d9dcd742e9157ff14c07caae63de1f6ae8dcc653af0677d3
提示:同一密钥被用于加密两段明文根据output.txt得到段落的异或密文和flag的异或密文,通过flag的固定前缀格式flag{异或出key的前缀,再用key的前缀去异或段落发现The q,根据output.txt里的提示quick brown fox猜测段落开头为The quick brown fox,异或得到一段密钥,其中发现有重复,恢复密钥,然后异或解出flag。
exp.py:
from Crypto.Util.strxor import strxor
c_flag = bytes.fromhex("36c0213cfdd79342850621db5c53e5ab64c72528d9dcd742e9157ff14c07caae63de1f6ae8dcc653af0677d3")c_letter = bytes.fromhex("04c4257bf7daca53b15470dc4041d4e636c3387becdace40a9547dd84a449ab238c96037e7d5da10be1b75800f62d2af238c303ae8c8d151b75471c14142dbaf3edf603ef0cad149fa1877da5b53c8e63fca602feeca8375b4137ec75c5e9aa73cdc283ae4cad710bb0032c24a57c9b270c32e38e3818379ae547bdd0f55d5ab3dc32e37ff8fd643bf1032c840449ab235df3432e8c88344a30477d95d5fcea322df603ae8cb8353b51962db5b53c8e63bc93939e9ced154a95832cf41529aa03fde603fefdcd35cbb0d7bc04816dfbe31c13037e3dc835fbc5474c14142c9e870f8283ea6cac242b61d77dd5b16d1a83fdb2e7be7dfd355bb0673c04c539aa9368c3433efdc8340b20673dd4a16d3b570ca3234eb8fd758bf547ecf5b539aa839c2252fe3cacd44b25471cb4142cfb429826016e7c1da10aa117dde43539aae31da257bf3dcc654fa007ac75c16c9a33ed82535e5ca8344b55462dc4e55ceaf33c9602feecaca42fa1c73c04b41c8af24c52e3ca6dcc859b6186180")flag_prefix = b"flag{"key_prefix = "".join(hex(i)[2:] for i in strxor(c_flag[:5], flag_prefix))print(strxor(bytes.fromhex(key_prefix), c_letter[:5]).decode())# The q# output.txt: quick brown foxletter_prefix = b"The quick brown fox "key_ = "".join(hex(i)[2:] for i in strxor(letter_prefix, c_letter[:len(letter_prefix)]))print(key_)# 50ac405b86afa330da7412ae2f36bac650ac405bkey = bytes.fromhex("50ac405b86afa330da7412ae2f36bac6")flag = ""for i in range(len(c_flag)): flag += chr(c_flag[i] ^ key[i % len(key)])print(flag)# flag{x0r_r3use_m4kes_str3am_c1ph3r_1nsecure}RSA攻击
challenge.txt:
"""某公司给两名员工分配了RSA密钥对,管理员偷懒使用了相同的模数n,只分配了不同的e。现在截获了两份密文,已知它们加密了相同的明文(即flag)。请从 output.txt 中恢复flag。
提示: - 两份密文加密的是同一消息 - gcd(e1, e2) = 1"""
# output.txt 中包含:# n, e1, e2, c1, c2# 你的任务:解密得到flagoutput.txt:
模数 n = 13812575233672721831586447583537566876653330486388935409787324333890787459392340450466602667504564680439365520897560873428017286096972445000317824251067352767983648512628776119679123400768824503694790917456261015793839979622036029611045745581363369351857864086686963496317673425630514828633413586909763949795187270764002509197362846908721600263590407640239331435797743946639068968182530714992497969629250766233642006666869043197198488505558710080081572718303651084249757629984467851536523131561671672489611342354506102975683280634931335250787164325776630303410430197355308594589794345127372612129749874742848505962957指数 e1 = 65537指数 e2 = 17密文 c1 = 6070418361005764781666022160782201020887766530217726892023574250703991153557153150240365562631823866925399109653692772429273414466157925616984969604480345833056708745589264326707421262501098443511684348192232914773363078866001499635599832817468918612502325969087574855976873314002597693535529314223131401211725375960723298442955172141723469659923837266222074788068850377594521429498262678342651354197024627444164288711810799491130391148471163552225195175015155522706829274469375372001014646432745594081482121724200720169564704735134585990761451469788279800252372582853001296020279841151437121368396563208194238176809密文 c2 = 10333074300444651393936782269258556921403986428158959194325049613051485082847482400799333224207225002899420584885380779122331681690914097226669296406031455480685880093806047826997202684091610029196843015145312932541842991056212933838748027848354582851989374719190041121737024050736144878626494196879779470357938007923163393755461501521926143809013879106438359634585413111911930506853827052788328813877660360961030885521473428344868672139024952576892377942170827101770540081503574982983989347495232393714702165354007286096839200607023742050117961927827236261835001175781713994427455900056065253089202845028635992697862
提示: 两份密文加密的是相同的明文(flag)共模攻击,gcdext秒了。
exp.py:
from Crypto.Util.number import long_to_bytesfrom gmpy2 import gcdext
n = 13812575233672721831586447583537566876653330486388935409787324333890787459392340450466602667504564680439365520897560873428017286096972445000317824251067352767983648512628776119679123400768824503694790917456261015793839979622036029611045745581363369351857864086686963496317673425630514828633413586909763949795187270764002509197362846908721600263590407640239331435797743946639068968182530714992497969629250766233642006666869043197198488505558710080081572718303651084249757629984467851536523131561671672489611342354506102975683280634931335250787164325776630303410430197355308594589794345127372612129749874742848505962957e1 = 65537e2 = 17c1 = 6070418361005764781666022160782201020887766530217726892023574250703991153557153150240365562631823866925399109653692772429273414466157925616984969604480345833056708745589264326707421262501098443511684348192232914773363078866001499635599832817468918612502325969087574855976873314002597693535529314223131401211725375960723298442955172141723469659923837266222074788068850377594521429498262678342651354197024627444164288711810799491130391148471163552225195175015155522706829274469375372001014646432745594081482121724200720169564704735134585990761451469788279800252372582853001296020279841151437121368396563208194238176809c2 = 10333074300444651393936782269258556921403986428158959194325049613051485082847482400799333224207225002899420584885380779122331681690914097226669296406031455480685880093806047826997202684091610029196843015145312932541842991056212933838748027848354582851989374719190041121737024050736144878626494196879779470357938007923163393755461501521926143809013879106438359634585413111911930506853827052788328813877660360961030885521473428344868672139024952576892377942170827101770540081503574982983989347495232393714702165354007286096839200607023742050117961927827236261835001175781713994427455900056065253089202845028635992697862g, s1, s2 = gcdext(e1, e2)m = pow(c1, s1, n) * pow(c2, s2, n) % nprint(long_to_bytes(m).decode())# flag{c0mm0n_m0dulus_1s_d4ng3r0us}Shamir
shamir.py:
from Crypto.Util.number import bytes_to_longimport random
p = "XXX"# REDACTED - prime lostflag = b"flag{...}"secret = bytes_to_long(flag)
k = 5n = 11
coeffs = [secret] + [random.randint(1, p-1) for _ in range(k-1)]shares = []for i in range(1, n+1): x = random.randint(1, p-1) # 实际 x 是随机选取的 y = sum(c * pow(x, j, p) for j, c in enumerate(coeffs)) % p shares.append((x, y))
print(shares)生成的秘密分片.txt:
生成的秘密分片:[(13825276559652663759456053593154923232020771238254924190105602129554442740903032538098062820337983638666056784818726026705226866679025611690838448584570200, 19012813120561778249910002377121545519300396863416796577430580565668955435109529853661026703963191587511794739652897381447200605465672082042748885989744402), (14989248861487876756545923532577464423717630626792629221618966203158382671849012765703938440292173459828333463382287156647477649833759229415415422006446622, 1656433892597578744823177014342869528132831200379451998967521640131825487494819099422022469838825418150730143438520616267294835254347450196350209174872775), (19193170771688324398963345493388616208257949680877900104979298799760166459827906171423469189582755008620842357080263827095038929588780308148621589260541422, 11420248910634302383712371357580971808319584342845033562709305079257609558334879243688210930475525301635690020652329269939235513202907874912193579010147639), (18777091659417137576603135959549361738394745875776533930983699353415679891339311594674388484175296875080132898946694787449577170540182756514019328107408039, 9704588552249224055741700389530593621449542838333557625043239604844884216427066269916242710825967541084869521646880935759182920024727659925664328119325004), (14287513785577058854224398359692453526128916947865468956393138998889401907577994975977127911557142483281724809006107854288358113197720626510491043303548938, 9770438332979961381243902918934813992264072842817997713173849346168822219848231350591767294014602573834792519783840064045899272301954841421098105680418195), (15119386315728257486056813314318552552131776852359374571135536516700837163067296684378970563219592314591010021093834609706121742207654051417055052071557349, 16692084219568517724580051441903204713362782163474624605007356230785148566081431738623045160758806438045544385291581669748734947320653414449300238328109834), (21639299360306429790518264840030705977452919783601050938080982219887611170051387045460766025557892361751023229841353839566899377685975938928635556686547189, 12343877060822660195641885868676444926185745514478427502000391547786522673431926278446194312565987755982555714259193644278522945366156482829701926440766436), (17403781572025005208843063451017304109237698250797299652792725200086960681154790951373046337507380799261125197889969541906772099793896620488753295096504560, 19150670008423170996379784798328231445600406963296913739761096531018281916219407400122538102243817197525100016408303024079773707274831692716031708315774805), (13712268494862445248911494067355982992182490419234876397649838374491191895372155289722641937870164145755937780023138602530807219076237280105050726711219910, 1791011308314909339397751948386556426199638075952445414959762706679206743326931052440210268620207102528545976021104436487643745311936337923164621066436060), (21991384930267151269802069003579123930799446461196461214557072106672776944086736799413877206434356469442093165424509519266137102480781842658606739163403874, 14963223947878308999984311524851337448763815509922889823520921933718980739751743032849959416282177018557805255468910634606302831448277324417065732420585144), (20641737678873745759238644473878987874377780512320373213801366359879139450580105650792376384552918292291784843752265971609206700166575172878621369499660576, 21115775840010891534972527491920868611647594882864057129786366769672854596717667891296204137876321305451520048412806215332780594549883808548319082816815511)]题目给出了Shamir Secret Sharing的加密脚本。核心逻辑如下:
secret = bytes_to_long(flag)
k = 5n = 11
coeffs = [secret] + [random.randint(1, p-1) for _ in range(k-1)]
for i in range(1, n+1): x = random.randint(1, p-1) y = sum(c * pow(x, j, p) for j, c in enumerate(coeffs)) % p shares.append((x, y))其中secret是多项式的常数项,阈值k = 5,所以多项式次数为 4。题目给出了 11 个分片(x, y),但隐藏了模数p。多项式形式为:
目标是恢复secret = f(0)。
虽然p被隐藏了,但是所有分片都满足同一个 4 次多项式。对于任意 6 个点,我们都可以构造矩阵:
由于模p下这些点满足 4 次多项式关系,所以该矩阵在模p下行列式为 0。也就是说,在整数域中计算得到的行列式一定是p的倍数。因此我们可以对多组 6 个点计算行列式,然后取它们的gcd,从而恢复出p的倍数。再分解gcd,找出最大的素因子基本就是p。然后在GF(p)上取任意 5 个点做 Lagrange 插值,取插值多项式在 0 处的值即可得到secret。
exp.py:
# SageMath 10.7from itertools import combinationsfrom math import gcdfrom Crypto.Util.number import long_to_bytes
shares = [(13825276559652663759456053593154923232020771238254924190105602129554442740903032538098062820337983638666056784818726026705226866679025611690838448584570200, 19012813120561778249910002377121545519300396863416796577430580565668955435109529853661026703963191587511794739652897381447200605465672082042748885989744402), (14989248861487876756545923532577464423717630626792629221618966203158382671849012765703938440292173459828333463382287156647477649833759229415415422006446622, 1656433892597578744823177014342869528132831200379451998967521640131825487494819099422022469838825418150730143438520616267294835254347450196350209174872775), (19193170771688324398963345493388616208257949680877900104979298799760166459827906171423469189582755008620842357080263827095038929588780308148621589260541422, 11420248910634302383712371357580971808319584342845033562709305079257609558334879243688210930475525301635690020652329269939235513202907874912193579010147639), (18777091659417137576603135959549361738394745875776533930983699353415679891339311594674388484175296875080132898946694787449577170540182756514019328107408039, 9704588552249224055741700389530593621449542838333557625043239604844884216427066269916242710825967541084869521646880935759182920024727659925664328119325004), (14287513785577058854224398359692453526128916947865468956393138998889401907577994975977127911557142483281724809006107854288358113197720626510491043303548938, 9770438332979961381243902918934813992264072842817997713173849346168822219848231350591767294014602573834792519783840064045899272301954841421098105680418195), (15119386315728257486056813314318552552131776852359374571135536516700837163067296684378970563219592314591010021093834609706121742207654051417055052071557349, 16692084219568517724580051441903204713362782163474624605007356230785148566081431738623045160758806438045544385291581669748734947320653414449300238328109834), (21639299360306429790518264840030705977452919783601050938080982219887611170051387045460766025557892361751023229841353839566899377685975938928635556686547189, 12343877060822660195641885868676444926185745514478427502000391547786522673431926278446194312565987755982555714259193644278522945366156482829701926440766436), (17403781572025005208843063451017304109237698250797299652792725200086960681154790951373046337507380799261125197889969541906772099793896620488753295096504560, 19150670008423170996379784798328231445600406963296913739761096531018281916219407400122538102243817197525100016408303024079773707274831692716031708315774805), (13712268494862445248911494067355982992182490419234876397649838374491191895372155289722641937870164145755937780023138602530807219076237280105050726711219910, 1791011308314909339397751948386556426199638075952445414959762706679206743326931052440210268620207102528545976021104436487643745311936337923164621066436060), (21991384930267151269802069003579123930799446461196461214557072106672776944086736799413877206434356469442093165424509519266137102480781842658606739163403874, 14963223947878308999984311524851337448763815509922889823520921933718980739751743032849959416282177018557805255468910634606302831448277324417065732420585144), (20641737678873745759238644473878987874377780512320373213801366359879139450580105650792376384552918292291784843752265971609206700166575172878621369499660576, 21115775840010891534972527491920868611647594882864057129786366769672854596717667891296204137876321305451520048412806215332780594549883808548319082816815511)]k = 5deg = k - 1g = 0for comb in combinations(shares, deg + 2): mat = [] for x, y in comb: mat.append([ZZ(x) ** j for j in range(deg + 1)] + [ZZ(y)]) D = abs(Matrix(ZZ, mat).det()) if D != 0: g = D if g == 0 else gcd(g, D)fac = factor(g)p = max([int(q) for q, e in fac if q.is_prime()])F = GF(p)R.<X> = PolynomialRing(F)points = [(F(x), F(y)) for x, y in shares[:k]]poly = R.lagrange_polynomial(points)secret = int(poly(0))flag = long_to_bytes(secret).decode()print(flag)# flag{shamir_p_recovery_test}RC4
202606_CRYPTO_中_PolarD&N_CTF_RC4.txt:
雨墨很喜欢 RC4,但他觉得普通 RC4 太简单了。于是他做了点小改动……
我们截获了两段密文,看起来和 RC4 有关,但又不太一样。
已知:flag 格式为 flag{...}密钥长度 ≤ 16使用的是 标准 RC4 KSA + PRGA
你能还原出 flag 吗?
c1 = 63dc968e6fbd78425b1aa80deca5dddd5bc2773d4c11bf3ac2 = 71d89e9a4b8648297043be0de9f0d0a328f228557863db47key=64327473646C3973646C393361326866626D686949513D3DRC4 是流密码,加密过程是明文与密钥流异或。如果同一 RC4 密钥流被用于加密两段不同明文,则:
两段密文异或后:
密钥流被完全抵消,问题退化为已知明文攻击。
题目给出c1,c2,key,先处理key字段。对其进行 hex 解码,得到 Base64 字符串,继续 Base64 解码得到wklv_lv_wkh_nhb!,观察可知这是 Caesar +3 编码,向回移 3 位得到this_is_the_key!,该字符串长度为 16,而密文长度为 24,因此将其补零到 24 字节:this_is_the_key!\x00\x00\x00\x00\x00\x00\x00\x00。由于两段密文复用了同一段 RC4 keystream,因此:
exp.py:
from base64 import b64decodefrom Crypto.Util.strxor import strxor
def caesar_alpha(s: bytes, shift: int) -> bytes: out = bytearray() for ch in s: if 65 <= ch <= 90: out.append((ch - 65 + shift) % 26 + 65) elif 97 <= ch <= 122: out.append((ch - 97 + shift) % 26 + 97) else: out.append(ch) return bytes(out)
c1 = bytes.fromhex("63dc968e6fbd78425b1aa80deca5dddd5bc2773d4c11bf3a")c2 = bytes.fromhex("71d89e9a4b8648297043be0de9f0d0a328f228557863db47")key_hex = "64327473646C3973646C393361326866626D686949513D3D"# key 字段:hex -> base64 -> Caesar(-3)key_b64 = bytes.fromhex(key_hex)key_rot = b64decode(key_b64)known = caesar_alpha(key_rot, -3)# c2 对应明文为 this_is_the_key!,补 0 到密文长度known_plain = known.ljust(len(c1), b"\x00")# RC4 同 keystream 复用:c1 ^ c2 = p1 ^ p2flag = strxor(strxor(c1, c2), known_plain)print(flag.decode())# flag{RC4_1s_n0t_s0_h4rd}Some information may be outdated









