
这个比赛打的不怎么认真,现在看来应该是可以AK的(其中不会的那道AI能出),只能遗憾离场了。
很多题型都是变形后的基础题,能够很好地练习基础,有复习的价值。
GZRSA
题干:
from flask import Flask
import random
from Crypto.Util.number import bytes_to_long, getPrime
import os
import time
app = Flask(__name__)
ACTUAL_FLAG = os.environ.get('GZCTF_FLAG', 'furryCTF{default_flag_here}')
def gcd(a, b):
while b:
a, b = b, a % b
return a
flag = bytes_to_long(ACTUAL_FLAG.encode())
random.seed(flag)
p = getPrime(512, randfunc=random.randbytes)
eq = getPrime(512, randfunc=random.randbytes)
N = p * q
phi = (p-1) * (q-1)
random.seed(flag+int(time.time()))
e = random.randint(1023, 65537)
while gcd(e, phi) != 1:
e = random.randint(1023, 65537)
m = flag
c = pow(m, e, N)
@app.route('/')
def index():
return f'''<html>
<head><title>GZRSA-furryCTF</title></head>
<body style="background-color: black; color: white; font-family: monospace; padding: 20px;">
<div style="border: 1px solid white; padding: 20px; word-wrap: break-word; overflow-wrap: break-word;">
请查收你本题的flag:<br><br>
N = {N}<br>
e = {e}<br>
c = {c}<br>
</div>
</body>
</html>'''
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0', port=5000)
WP:
分析RSA无果,给的e正常大小,无法维纳攻击,从app生成找漏洞(数据不足624,排除MT)
当时以为是很深奥的方法,没想到尝试几次就可以出结果
分析随机数的生成,pq用的随机seed,e的seed为时间加上flag,看起来没有问题
这时关闭再开启容器,发现n居然没变,这么说来,只有time影响的e的seed才发生了改变
现在就有了2组数据,同n不同e,要是互质,就可以共模攻击
现在要做的就是多开关容器,使得出现互质或者gcd=2的情况,这样易于处理
假设我们那到了互质的数据,构造贝祖定理,得出结果
import gmpy2
from Crypto.Util.number import long_to_bytes
N = int(
"1021225536509134223391530013482367539851527069506838316910965079648134447549992"
"9404522710814946540812674969345526094950131686425927734840552992552014051347377"
"5193949296939773021967990066981132721308976212787465562803173841984717260336172"
"678440263223345559360029795246235249193857928606876149578978015597977441"
)
e1 = 27631
e2 = 9535
c1 = int(
"2550977028039901881631918541935023070226182105702642050789354096209774018399171"
"8149243608817246195450793104108881683079805384983156432767679720687537629879647"
"6269874454263112723961371932251897185261604617563211656138135844416657024456373"
"21245832803246307868825271066472590106824348073558508029736230612270896"
)
c2 = int(
"8014190140424954759926262651407639175141645025057885428742831869578726213790878"
"3127283489373912060986487120158787079042871826065916665431134556622479519756716"
"0752336896034475591311160927709226505155435245796088438997102565899742404091049"
"48300146837081459781594952880814624006439718798920887589908445076562503"
)
g, s, t = gmpy2.gcdext(e1, e2)
if g != 1:
raise ValueError(f"e1 和 e2 不互质,gcd = {g},不能直接做标准共模攻击")
if s < 0:
c1 = gmpy2.invert(c1, N)
s = -s
if t < 0:
c2 = gmpy2.invert(c2, N)
t = -t
m = (gmpy2.powmod(c1, s, N) * gmpy2.powmod(c2, t, N)) % N
print("m =", m)
print("plaintext =", long_to_bytes(int(m)))
很有启发性的题目,伪RSA的一种
0x4A
题干:
🧅🎗️🪖🙃🦄🍊🍧🪵🎉💩🩱🏪🥡🦺⛳🏦🍙🏟️🎁🦓🎃😇😂🍨🐻🦐🥼🥮🍇🪵🎓🧀😀🏬🎣🏟️🦞🤣🍕🍃👓🤿🧱🌵🦍🏟️🥍🏓🍞🏥🏓😆🥎🏭🐄🍎🥟🥢✨🏸⛲🐏🐶🦀🙂🌿🍄🗽🍄🥥🎋🎳😛🍞😗😃🧉🏟️🧀🍞🌴🍵🕍🩳🥟🎽🐨🍉🏞️🥎🍙🍤😁🏨🔇🙂🥍😛🎣🦝🦐🍵🪴🌿🏢🎿👺🫖🐮👛😛🏭🥎🏘️😘🥭🍟🎳🦁🥮🕶️🍍🐼🏦🥦🎑🐧🎗️🐴⛸️🫑🐵☕🎈🍂🎟️🎩🍉🥭🔇🩲🍔🎆🕋🎑🧨🥦🐮🥝🌰🍵🐨🐴🍞🥠🏛️🎳💄👑🎊🧱🦝🧨🐸👝🦀🐷🎍💄🦪🤡🎟️🔇💎🏭🏑😅📣🐻🩱👾🦊😍🥭🥕🌿🏸⛩️🐶🪨🦐🥒💩🐪👚🍅🧅🍘🏪🐨🐑😇✨🍭🥭👑😗🙂🍡🌲🦍🎈🎿👾🐢👘👹🍥🍊🍵🎿🩲🛕🏩😃🏦🩲🍯🦓🌾🐶😀💄🥭🏅🥲👛🥟😅🧉🪹🐩🐗🍂🏞️😉🎟️😙🧅🦺🥲😘🏯😇🏑🏛️🏰🥕🥑🏗️🏭📣🐊🍟😄😅🏛️🎈🏀🏩🤡🎊😁🍈🏗️🙃😗🎽🐐🩲😗🏪🧀😉👾🎑💎🥝🏒😘🥮🍭🎈🍦🐮🐑🫖😘🍞🐷🥑🏩🐗🗼😉🏪🦬🍞🍞🥰🌳🍞🎟️🐏🦺🐨🪴📣🧉😃🌾⛑️🧉⛸️🐻😅🍊🍼🏘️😗💄🤿🥝🎳🌳🍵⛲🍟😉🍌🦀💒🐸🏅🏀🐊🪹😈😇🦍🌿🎃📯🙃🐄🍑🦐🎟️🎃🤠🙃🙃😛🌿😈🐴🐧🏰🎉🍉💒😄⛳🫘🎏🙃🥟🍨🍎🍞🍍🎏🐑🍕🍀🥮🎗️⚽🎩🐸🍋🐏👺🌁🍧🐽🧅🥑🕌⛲🐢🐻🎃🫒🤣🍌🗼💒🐂⛪🍞👻😘🥏🐏🦍🍑😋🥽🤠🍕🦑🍄🥤🧅🥭🥏🎗️🥡🥊😙🎑😍👺🍵🍉🐻😘🍃🐲🙃🦞🐼🤩🐽🥬🔇🗼🏘️⛸️🐑🎋🍈🐗😋🍌🏭😇🍀🍯🍧🎐🍧🐑🎣🐪🥮🍭🐏🥔🌳🥤😇🎎🧀🗼🏥☕🐼🦁🐮🍔🌵🥡⛺🏪🦁💒🥍🐵🍔🕍⛲🍈🤩🧨🥦😋⛩️🦐🐸🦬🥍🏗️🦝🍙🏩🥽🏟️🎿🎈🐮🏢🏦👛🍦🐗🥲🐃🐨🐃🍍🐵😂🦁🥠🦀🏰😈🦄🩲🍼🐗🏬😂⛪🍒🍨🌶️🏸🫐🥰🫖🏗️🐗🍡🍼🤡🕌🐵🎖️⚽🌳🐷🛖🍒👚🍃🦁🏬😅🏰🐮🍣🌴💎🏏💩🪖🎐👝🌵📯🥦🍀🌳🪨☕🫑🦁🌁🎽💩🥔🥝🥕👽🍵🏓💩🍂👛🪴🥕🏦🐯🍼🏁🥅🍤🍕🥽🍈☕🏤👻🐮🎖️🍕🗼✨🐶🐷🍟🦁🎳👝🍇🥜🏏🏒⛩️🍦🏆🎍🦌🍀🍎🍵🍡🧀🐩👝🍕😀🗼👜🏣🌽🍭🏣🥒🏟️😚🥢🌽⚽🍍🦧🎖️😍🐮🎖️🐯🗼🩳🌽🐗🍌😆🛖🎃🕶️🍼🪵🦑😁🍓😁😄🥊🏰🎏🙂🥠👺🍕🥍🍨🗼🐐😘🎆🐼🥢🥽🪖🎋👻🐴🥝👻🥮🧀🐗🥔🎋🎳🐨🍚🏦🐏🥭🍐🎽🤠🎄🥅🕋⛺😀🐏🏉🐢🌁🎍🍧😄🌽🍤😉🐽👓🍁🏸🌾🌴🏞️😀🍼😘🌽👜🥜😅🧀🥜🎎💀🏘️🤣🐒🫘🎈😍🍍🌰🦬🌾🥍🏟️🕌🏣🐄🦧🥲👺🌁🥛🍵🥝🍮🐐👺🌳😆🏒🤿🧉🥑🍦🏗️🍧😀🍜🏸🎽🏑🍒⛲🎇🐪⛺⛩️🍤🍔🍑🍕👚🍆⛑️🍙🫠🎗️👛👘🏬🎀🎄🏒👛🪨🐪🏘️🥍🎎🥏🎿🦁🎗️🩲🤠😁🏭🥎🦺😁🍌🍣🍀🤖🧀👻🎁⛲🤡💀🏓😋🫑😗🥽🦓🌶️🥝😆🎈🥭🐵🏑🌿💀⛲🦓🛖🍓😈🥝🦀🌰⛺💄🐽🧱⛩️😉🤣🏁🐯🏪🐄🛖🧧👛⛩️🍁😋🏁🕶️🥰🏆🫑🐪🎉🎐⛪⛳💒🏸🍈😚🍙💒🫒🍘🦌🏢🦄🥅⛩️🫑🍞🍑🎗️🍒🦬👹🌽🫠🫑🦁😆😙⛩️😘🍧🐵🥛🐮🦄🍣🦞🎗️🤣🙂🍃🦓🎎🍒🍭🦞🌾🧄🦀👺🦞🎆🍎🛖🧉🥦😆🪴🥡🙃🍵🍵🦓🏰🏢🦀👻🦺🍕😸😂🥋🪵🍄🏢🥭🥦🐊🐢⛳🍟🐩🪹🎿👛🐗🐪🎖️🫒🐵🎏🛖🥒👜🎣🐺🪖👝👻🎓🍓🧉🐄🏛️🎐🏓🥼💎👻👙🥥🏁🧄☕👻😙👾🎳🍌🐩🐐🥊🐯💒🏗️😆🧅🌾🏬🩲🎩🏒😃💎🧉⛪💀🎋😉🎖️🧱🫖🏸🦬🎈👔🏣📣🫒🧧🎗️🏩🍣😈🐩😋🎋🤿🕋🥽🧧🥬🐺🍡😂🎏🍧🍀🍘🍮🦪🏏💀🍮🍯🎩🥥🐃😍👻🍨🥎🥜🐐😁🎁👾🎏🍦🍦🍈🪵🎗️🏅🎋👔🥛🎁🌾🧧😇🎓😋⛪🐩🦍🐃🌁🍧🐧🍦🍄🧧🫐🦞🍍🦪👜🌰🥽🏸🥑🥅🥠🎁🐽🦝🗽🏬🍎🍣🦓🍵🏬🌵🏢🍑🌰🥟🥎🏬🦞🦝🎊⚽🕍🏁📯🩳😉🥏😂🎩🏓🏒🥜🐧🐼🎳🎃👙🩳🎽🐂🌵🫖🦓⛸️🌳☕😉🍟🪨🥑🍼🍑🍑👝🥊🎁🥭🥍🐂🥬🍔🌲🥝⛩️🥢🪨⛺🧉🏬🏅🥤🏏⛩️⛳🌽🧱🤿😂😸🏑🍃🧨🧄🏭🐄👙🍑🏤🏤🎑⛩️🍌🏬🏯🍨🎩🏰🍙📯🍤⛪🥦⛳⛸️👝🩳🥟😈🦬🐼🥏⛳⛳🩱🧄🐲🏰🐗🥋🥲⛳🥭🥅😀🏣🫒⛩️🥎🐴😁😃🤣😆😃⛑️🐺🏉🍒🏸🍯🦝🐗🍨🍉🫖🕋🍵🐴🎉😙🥟🍒🎇🏉🛖🏅🎿🎣🗼🍑😗😋🍙🎓🙂🥍🍌🪵👑🌁🍣🍈🍣👙🏘️🍅🥕👓⛪🎟️🧀🐗🍒🐧🤖🥰👜🎄🐯🛕🙃🥛🦓🎁👜📯🎄🧀🏣🐂🍟😈🎊🎑🦍🐪🤡🐢🧧🐯🏘️🎽🎇🪨🧉⚽💀🏏🧅🐄🍄🥊🙂😚🐗🫠🎖️🐢🧨🥥😅🌾😚🍀🗽💀⛩️🐯🧄🤠🧨🌾🐯🐑🧱⛺📯🍀💩🍌🍉🥛🥰🩲🐼🤖🍀🍦😂🥎🦧🌲🪨🦺😆⛳🐵🪵🏦🥲🫒🐢😇🌾🦄👜🐏🏒🥭🏆🥒🦬🐼🍐🏢🏁🐒🤠🎓🥒🌲🩳🍦🍥🐗🐄🍎🕌😇⛩️🤩🍡😘🐄🎳📯🦝🏀💎🐯👺🦀😁⛲🦁🤠🌴🎀🎁🍁🍵🦄✨🌾💒⛩️⚽🎈🧧🥡🎀🍀🩲🥼🥽🥦🏪🏢🥬🍎🌵🎉🎓😸🛕🎣🥬🏀🤿🏏😚🌁✨🦊🕶️🤖🕍🪨🐶👔🦁🏣🕍⛑️🎉🍙😄🏛️🥑🐪🍎😇⛑️⛪🌲🥕🐧🕋🍯📯🥮🌰🏣👓😋😘🦬👓🐨🍕🍀😗🍔🎳🍕🩱🛕🪴🐻🍓👔👑🐶🦄🎀😈🩱🏅🏛️💩👾🥠🏒🐼😂🐏🥡🎀🏟️🥟🧅🐺💀🌶️🍵🎁🍼👛😍💒😅🦍👹👑🦍🌴😙🩳⛪🥢🍍🐮🏅🏆🎍🐩👛🐨🎃🍦🥽🛖🫐🐼🐯🍊🥦🥰🍘🔇😍🫐🥦🏪👚🎀🧧👔✨⛑️🎄🥢🍮🏣🏉📣🏞️🐺🥕👽🍇🪖🪨🍟🍒🍨🥅🏢🤣🩲🍘🍂🏦🥜🍍🏆⛪🤣🦝🦑😁
WP:
首先猜测是什么加密,简单替换首先排除,太长了,之后是base100,EMOJI-AES
(还有EMOJI-AES的证据:题干名字就是密钥)
这道题难点在于是3次EMOJI-AES,需要大胆尝试
这道题是一个唯密文的题。难点在于猜,猜加密,猜次数
hide
题干:
解析题目根本模型,i=6,Bi=Ai*m modx,Ci=Bi mod2256,m=2160*flag
一字符转化成8bit,题目是后面加上0x00*20,8转2,一个0转24
from random import randint
from Crypto.Util.number import *
from secret import flag
assert len(flag) == 44
def pad(f):
return f + b'\x00'*20
def GA(n, x):
A = []
for i in range(n):
A.append(randint(1, x))
return A
def GB(A, m, x, n):
B = []
for i in range(n):
B.append(A[i] * m % x)
return B
def GC(B, n):
C = []
for i in range(n):
C.append(B[i] % 2**256)
return C
def main():
m = bytes_to_long(pad(flag))
x = getPrime(1024)
A = GA(6, x)
B = GB(A, m, x, 6)
C = GC(B, 6)
print('x = ',x)
print('A = ',A)
print('C = ',C)
if __name__ == '__main__':
main()
"""
x = 110683599327403260859566877862791935204872600239479993378436152747223207190678474010931362186750321766654526863424246869676333697321126678304486945686795080395648349877677057955164173793663863515499851413035327922547849659421761457454306471948196743517390862534880779324672233898414340546225036981627425482221
A = [7010037768323492814068058948174853511882398276332776121585079407678330793092800035269526181957255399672652011111654741599608887098109580353765882969176288829698783809623046145668133636075432524440915257579561871685314889370489860185806532259458628868370653070766497850259451961004644017942384235055797395644, 74512008367681391576615422563769111304299667679061047768808113939982483619544887008328862272153828562552333088496906580861267829681506163090926448703049851520594540919689526223471861426095725497571027934265222847996257902446974751505984356357598199691411825903191674839607030952271799209449395136250172915515, 25171034166045065048766468088478862083654896262788374008686766356983492064821153256216151343757671494619313358321028585201126451603499400800590845023208694587391285590589998721718768705028189541469405249485448442978139438800274489463915526151654081202939476333828109332203871789408483221357748609311358075355, 52306344268758230793760445392598730662254324962115084956833680450776226191926371213996086940760151950121664838769606693834086936533634419430890689801544767742709480565738473278968217081629697632917059499356891370902154113670930248447468493869766005495777084987102433647416014761261066086936748326218115032801, 2648050784571648217531939202354197938389512824250133239934656370441229591673153566810342978780796842103474408026748569769289860666767084333212674530469910686231631759794852701142391634889712214232039601137248325291058095314745786903631551946386508619385174979529538717455213294397556550354362466891057541888, 4166766374977094264345277893694623030532483103866451849932564813429296670145052328195058889292880408332777827251072855711166381389290737203475814458557602354827802370340106885546253665151376153287179701847638247208647055846230060548340862356687738774258116075051088973344675967295352247188827680132923498399]
C = [96354217664113218713079763550257275104215355845815212539932683912934781564627, 30150406435560693444237221479565769322093520010137364328243360133422483903497, 70602489044018616453691889149944654806634496215998208471923855476473271019224, 48151736602211661743764030367795232850777940271462869965461685371076203243825, 103913167044447094369215280489501526360221467671774409004177689479561470070160, 84110063463970478633592182419539430837714642240603879538426682668855397515725]
"""
WP:
识别题型:高位HNP,实际上不好识别,一眼还以为是HSSP,信息论也不好套,要尝试,一般通过除数来构造小数
取:2160模,得ki=-Cix-1 mod2160,得到ki的量级
计算下来后几者,后面的项量级都小,(X是21024,得到每一项都小于0),就是HNP
还原回去,就是模X*2160,构造矩阵
X*2**160
X*2**160
X*2**160
X*2**160 0
A1*2**160 A2*2**160 A3*2**160 A6*2**160 S
这里的S是控制位 ,保证最后一条不大小独立于矩阵,S=X/M=2672
得到 小 小 小…S*M,处理得到M
from Crypto.Util.number import long_to_bytes
x = 110683599327403260859566877862791935204872600239479993378436152747223207190678474010931362186750321766654526863424246869676333697321126678304486945686795080395648349877677057955164173793663863515499851413035327922547849659421761457454306471948196743517390862534880779324672233898414340546225036981627425482221
A = [
7010037768323492814068058948174853511882398276332776121585079407678330793092800035269526181957255399672652011111654741599608887098109580353765882969176288829698783809623046145668133636075432524440915257579561871685314889370489860185806532259458628868370653070766497850259451961004644017942384235055797395644,
74512008367681391576615422563769111304299667679061047768808113939982483619544887008328862272153828562552333088496906580861267829681506163090926448703049851520594540919689526223471861426095725497571027934265222847996257902446974751505984356357598199691411825903191674839607030952271799209449395136250172915515,
25171034166045065048766468088478862083654896262788374008686766356983492064821153256216151343757671494619313358321028585201126451603499400800590845023208694587391285590589998721718768705028189541469405249485448442978139438800274489463915526151654081202939476333828109332203871789408483221357748609311358075355,
52306344268758230793760445392598730662254324962115084956833680450776226191926371213996086940760151950121664838769606693834086936533634419430890689801544767742709480565738473278968217081629697632917059499356891370902154113670930248447468493869766005495777084987102433647416014761261066086936748326218115032801,
2648050784571648217531939202354197938389512824250133239934656370441229591673153566810342978780796842103474408026748569769289860666767084333212674530469910686231631759794852701142391634889712214232039601137248325291058095314745786903631551946386508619385174979529538717455213294397556550354362466891057541888,
4166766374977094264345277893694623030532483103866451849932564813429296670145052328195058889292880408332777827251072855711166381389290737203475814458557602354827802370340106885546253665151376153287179701847638247208647055846230060548340862356687738774258116075051088973344675967295352247188827680132923498399
]
C = [
96354217664113218713079763550257275104215355845815212539932683912934781564627,
30150406435560693444237221479565769322093520010137364328243360133422483903497,
70602489044018616453691889149944654806634496215998208471923855476473271019224,
48151736602211661743764030367795232850777940271462869965461685371076203243825,
103913167044447094369215280489501526360221467671774409004177689479561470070160,
84110063463970478633592182419539430837714642240603879538426682668855397515725
]
n = 6
T = 2^160
invx = inverse_mod(x, T)
k0 = [int((-c * invx) % T) for c in C]
S = 2^672
B = Matrix(ZZ, n+1, n+1)
for i in range(n):
B[i, i] = x * T
for j in range(n):
B[n, j] = A[j] * T
B[n, n] = S
target = vector(ZZ, [k0[i] * x for i in range(n)] + [0])
Bred = B.LLL()
G, _ = Bred.gram_schmidt()
w = vector(QQ, target)
for i in reversed(range(Bred.nrows())):
c = ZZ(round((w * G[i]) / (G[i] * G[i])))
w -= c * Bred[i]
closest = target - vector(ZZ, w)
diff = target - closest
M = abs(diff[-1]) // S
flag = long_to_bytes(int(M), 44)
print(flag)
很有练习意义的HNP,可以训练模型识别能力,找突破口能力
lazy singer
题干:
import os
import hashlib
import random
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from ecdsa import SECP256k1
from ecdsa.ecdsa import Public_key, Private_key, Signature
curve = SECP256k1
G = curve.generator
n = curve.order
d = random.randint(1, n-1)
pub_point = d * G
aes_key = hashlib.sha256(str(d).encode()).digest()
flag_str = os.getenv("GZCTF_FLAG", "flag{test_flag}")
FLAG = flag_str.encode()
def get_signature(msg_bytes, k_nonce):
h = hashlib.sha256(msg_bytes).digest()
z = int.from_bytes(h, 'big')
k_point = k_nonce * G
r = k_point.x() % n
k_inv = pow(k_nonce, -1, n)
s = (k_inv * (z + r * d)) % n
return (r, s)
def main():
print("Welcome to the Lazy ECDSA Signer!")
print("I can sign any message for you, but I won't give you the flag directly.")
cipher = AES.new(aes_key, AES.MODE_ECB)
encrypted_flag = cipher.encrypt(pad(FLAG, 16))
print(f"Encrypted Flag (hex): {encrypted_flag.hex()}")
k_nonce = random.randint(1, n-1)
while True:
try:
print("\n[1] Sign a message")
print("[2] Exit")
choice = input("Option: ").strip()
if choice == '1':
msg = input("Enter message to sign: ").strip()
if not msg: continue
r, s = get_signature(msg.encode(), k_nonce)
print(f"Signature (r, s): ({r}, {s})")
else:
break
except Exception as e:
print("Error.")
break
if __name__ == "__main__":
main()
WP:
经典的ECDSA,k nonce复用,取2个数据s1-s2=k-1(z1-z2)得到k,解得d=(sk-z)r-1 modn
from pwn import *
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from ecdsa import SECP256k1
import re
HOST = "example.com"
PORT = 1337
n = SECP256k1.order
def H(m: bytes) -> int:
return int.from_bytes(hashlib.sha256(m).digest(), "big")
def inv(x, mod):
return pow(x, -1, mod)
def parse_sig(line: bytes):
# Signature (r, s): (...., ....)
m = re.search(rb"Signature \(r, s\): \((\d+), (\d+)\)", line)
if not m:
raise ValueError(f"bad signature line: {line!r}")
return int(m.group(1)), int(m.group(2))
io = remote(HOST, PORT)
io.recvuntil(b"Encrypted Flag (hex): ")
enc_hex = io.recvline().strip().decode()
enc_flag = bytes.fromhex(enc_hex)
def get_sig(msg: bytes):
io.recvuntil(b"Option: ")
io.sendline(b"1")
io.recvuntil(b"Enter message to sign: ")
io.sendline(msg)
line = io.recvline().strip()
while b"Signature (r, s):" not in line:
line = io.recvline().strip()
return parse_sig(line)
m1 = b"a"
m2 = b"b"
r1, s1 = get_sig(m1)
r2, s2 = get_sig(m2)
print("[*] r1 =", r1)
print("[*] s1 =", s1)
print("[*] r2 =", r2)
print("[*] s2 =", s2)
assert r1 == r2, "nonce not reused? unexpected"
z1 = H(m1)
z2 = H(m2)
k = ((z1 - z2) * inv((s1 - s2) % n, n)) % n
d = ((s1 * k - z1) * inv(r1, n)) % n
print("[*] recovered k =", k)
print("[*] recovered d =", d)
aes_key = hashlib.sha256(str(d).encode()).digest()
cipher = AES.new(aes_key, AES.MODE_ECB)
flag = unpad(cipher.decrypt(enc_flag), 16)
print("[+] flag =", flag.decode())
io.close()
签名中模板的那一档




