分类: CTF CRYPTO WP

  • furryCTF WP

    这个比赛打的不怎么认真,现在看来应该是可以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的证据:题干名字就是密钥)

    base100:8+55/64+0x8fb1base100:每一个8位字节(不足补),先偏移+55,之后以/64+0x8f记为高位b1,再以%64+0x80记为低位b2,把[0xf0,0x9f,b1,b2]转化为EMOJI
    EMOJIAESEMOJI-AES是一系列合成算法,不展开

    这道题难点在于是3次EMOJI-AES,需要大胆尝试

    工具网页:https://txtmoji.elliot00.com/

    这道题是一个唯密文的题。难点在于猜,猜加密,猜次数

    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,信息论也不好套,要尝试,一般通过除数来构造小数

    AiM(2160)=kix+Ci+ti(2256)Ai*M*(2**160)=ki*x+Ci+ti*(2**256)

    取:2160模,得ki=-Cix-1 mod2160,得到ki的量级

    AiM/X=Ki/2160+Ci/(x2160)+296ti/xAi*M/X=Ki/2**160+Ci/(x*2**160)+2**96*ti/x

    计算下来后几者,后面的项量级都小,(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()

    签名中模板的那一档

    tiny random
    题干:

      WP:

      Encrypted

    • 古剑山2025&2024 WP

        古剑山2025
        1.CBC
        题干:
        Good job!
        
        ####*####*####*####Game Start####*####*####*####
        # '#' for conditions
        # '@' for questions
        ####@####
        # c1=aes_cbc_encode(password,iv,m1)
        # c1.encode('base64')=cHtNHbeZs4hMvPY1I3U/H5Xw9dTAYiQbNxi6hhKpD8fG+9XHS1y3vurJv+8n/eJS30zwAyUB/hZx
        +jrgTG6oYaUoxrlMnDhdtblJMiI0SXpUYkEFTzON+v5v0kKBtlY/7deS+nhRWlWm1AEfLLFx6N0z
        q22s9F0r2/HDEGTEdsiLnogqVO/f7e/GtLO7Kl6e++GQnpaKasa2KFDCaocMj7V5LfEh/Nha6N9E
        Y6zMelUIEpy56YeeZBYctJ+CT8jeNZ6lXNOEO+ZD0KNeh9xyB7++PDgwhoeumGiJIh3S+EgZ/y2U
        0vgtJ0JC6/5v27Km3btyV/dDEIGhIvx9pe1wCA==
        # m1.encode('base64')=UUxjWW9QRm1SYXhCWG9WdVhtU1JXemtza3dJR0V4ZkpDaVNMZWJ2dmVGaWhoQ0V4Slp2cHhLU2VT
        WkdLck1YY1ZCZmZPYkRmdWltWUdaTWdCcHhzaVZhYVBhWmtrd0xTbmNmY3pzeGpVRUNab0lWYkh4
        T1J2UHlRWXhlaFZqQnVWRkxHaVJDYk5FVGRxQUZjU0Vld0pRZkplZXZEUVpxc3JvUWx2WmFqVmZF
        YmVVbXdnaExXWG5iSXRHTG1WeURxQldlQWJtZnZiUEhNWVBVa2RGdmtSRU5EbldYY3NqRHhiR2tr
        b2hySHFKY3hyUENVV0tFRURBYVlCRkN3T3hvRw==
        # m2=aes_cbc_decode(password,iv,c2)
        # m2[31]=n
        # m2[54]=E
        # m2[82]=C
        # m2[117]=A
        # m2[145]=H
        # m2[189]=c
        # m2[216]=i
        # m2[248]=t
        WP:

        如题上所述,要控制2,4等相间的block中的特定字符(即PN(INDEX)),我们只知道一组C,P

        part1:如何利用已知的C,P:
        由CBC的解密可得:C0 XOR D(C1)=P1即D(C1)=P1 XOR C0,这时我们得到一个中间量S=D(C1)
        part2:控制特定位置:
        P(N)=C(N-1) XOR D(C(N)),我想通过S来控制C(N),即令C1=CN,同时解:D(C1)=D(CN)
        即S=D(CN),带会得到P(N)=C(N-1) XOR S
        加入INDEX控制,就是CN(INDEX)=PN(INDEX) XOR S(INDEX)
        from pwn import *
        import hashlib
        import base64
        import re
        from collections import defaultdict
        
        context.log_level = "info"
        BLOCK_SIZE = 16
        
        HOST = "47.107.168.16"
        PORT = 42057
        
        # ================== 工具函数 ==================
        
        def xor_bytes(a: bytes, b: bytes) -> bytes:
            return bytes(x ^ y for x, y in zip(a, b))
        
        def solve_pow(prefix: str) -> bytes:
            """
            题目:x = chr(rand(0,0xff)) + chr(rand(0,0xff)) + chr(rand(0,0x1f))
                  sha256(x).hexdigest()[0:8] == prefix
            暴力枚举,返回 x(bytes,长度 3)
            """
            log.info(f"[*] Solving PoW for prefix {prefix} ...")
            target = prefix.lower()
            for b0 in range(256):
                for b1 in range(256):
                    for b2 in range(0x20):  # 0x00 ~ 0x1f
                        x = bytes([b0, b1, b2])
                        h = hashlib.sha256(x).hexdigest()
                        if h.startswith(target):
                            log.success(f"Found x = {x.hex()} (sha256={h})")
                            return x
            raise RuntimeError("No PoW solution found (should not happen).")
        
        def build_c2(c1_b64: str, m1_b64: str, constraints):
            """
            根据已知的 c1, m1 和 m2 的若干位置约束自动构造 c2。
            constraints: [(index, char), ...] 例如 [(31,'n'), (54,'E'), ...]
            返回: (c2_bytes, c2_base64_str)
            """
            c1 = base64.b64decode(c1_b64)
            m1 = base64.b64decode(m1_b64)
        
            assert len(c1) == len(m1), "c1 和 m1 长度不一致,检查一下题目数据"
            assert len(c1) % BLOCK_SIZE == 0, "长度不是 16 的倍数?"
        
            nblocks = len(c1) // BLOCK_SIZE
            C1 = [c1[i*BLOCK_SIZE:(i+1)*BLOCK_SIZE] for i in range(nblocks)]
            P1 = [m1[i*BLOCK_SIZE:(i+1)*BLOCK_SIZE] for i in range(nblocks)]
        
            # 选 C1[1] 作为参考块:S = D(C1[1]) = P1[1] XOR C1[0]
            src_block_index = 1
            assert nblocks > 1, "至少需要两个块才行"
            S = xor_bytes(P1[src_block_index], C1[src_block_index - 1])
            src_cipher_block = C1[src_block_index]
        
            # 把约束按块分组:block_index -> [(offset, ord(ch)), ...]
            by_block = defaultdict(list)
            for pos, ch in constraints:
                if pos < BLOCK_SIZE:
                    raise ValueError(
                        f"题目在第 0 块位置 {pos} 上给了约束,目前构造没处理第 0 块"
                    )
                block_idx = pos // BLOCK_SIZE
                offset = pos % BLOCK_SIZE
                by_block[block_idx].append((offset, ord(ch)))
        
            if not by_block:
                raise ValueError("没有任何约束?")
        
            max_block = max(by_block.keys())
            num_blocks2 = max_block + 1  # 0-based
        
            # 检查是否存在连续的约束块(例:3 和 4 同时有约束,会冲突)
            constrained_blocks = sorted(by_block.keys())
            for i in range(len(constrained_blocks) - 1):
                if constrained_blocks[i] + 1 == constrained_blocks[i + 1]:
                    raise ValueError(
                        f"连续约束块 {constrained_blocks[i]} 和 {constrained_blocks[i+1]},"
                        "当前构造策略会冲突,需要手动改算法。"
                    )
        
            # 初始化 C2,全 0
            C2 = [bytearray(BLOCK_SIZE) for _ in range(num_blocks2)]
        
            # 所有有约束的块,都设置为 src_cipher_block
            for b in constrained_blocks:
                C2[b][:] = src_cipher_block
        
            # 根据每个受约束块,反推出"前一块"的对应字节
            for b, items in by_block.items():
                if b == 0:
                    raise ValueError("不应该出现 b == 0 的约束(前面已经检查过)")
                prev_b = b - 1
                for offset, ch_ord in items:
                    # P2[b][offset] = ch_ord
                    # P2[b] = S XOR C2[prev_b]
                    # => C2[prev_b][offset] = S[offset] XOR ch_ord
                    need = S[offset] ^ ch_ord
                    if C2[prev_b][offset] != 0 and C2[prev_b][offset] != need:
                        raise ValueError(
                            f"冲突:块 {prev_b} 偏移 {offset} 之前已为 "
                            f"{C2[prev_b][offset]}, 现在需要 {need}"
                        )
                    C2[prev_b][offset] = need
        
            c2 = b"".join(bytes(block) for block in C2)
            c2_b64 = base64.b64encode(c2).decode()
            return c2, c2_b64
        
        def parse_and_solve_round(text):
            """
            从一轮题目文本中解析 c1, m1, 约束,并构造 c2
            返回: (c2_bytes, c2_b64) 或 None(解析失败)
            """
            # 解析 c1
            m_c1 = re.search(
                r"c1\.encode\('base64'\)=([A-Za-z0-9+/=\s]+?)#\s*m1\.encode\('base64'\)=",
                text, re.S
            )
            if not m_c1:
                return None
            c1_b64_raw = m_c1.group(1).strip().replace("\n", "").replace("\r", "").replace(" ", "")
        
            # 解析 m1
            m_m1 = re.search(
                r"m1\.encode\('base64'\)=([A-Za-z0-9+/=\s]+?)#\s*m2=",
                text, re.S
            )
            if not m_m1:
                return None
            m1_b64_raw = m_m1.group(1).strip().replace("\n", "").replace("\r", "").replace(" ", "")
        
            # 解析约束 m2[xxx]=c
            constraints = []
            for idx, ch in re.findall(r"m2\[(\d+)\]=(.)", text):
                pos = int(idx)
                constraints.append((pos, ch))
            
            if not constraints:
                return None
        
            log.info(f"c1_b64 length = {len(c1_b64_raw)}")
            log.info(f"m1_b64 length = {len(m1_b64_raw)}")
            log.info(f"Parsed constraints: {constraints}")
        
            try:
                c2_bytes, c2_b64 = build_c2(c1_b64_raw, m1_b64_raw, constraints)
                return c2_bytes, c2_b64
            except Exception as e:
                log.error(f"build_c2 failed: {e}")
                return None
        
        # ================== 主攻击逻辑 ==================
        
        def main():
            io = remote(HOST, PORT)
        
            # ---------- 1. 读取 PoW 提示,解析前缀 ----------
            data = io.recvuntil(b"x.encode('hex')=")
            text = data.decode(errors="ignore")
            log.info("PoW banner:\n" + text)
        
            m = re.search(r"hexdigest\(\)\[0:8\]=='([0-9a-fA-F]{8})'", text)
            if not m:
                log.error("无法从题面解析出 PoW 前缀")
                return
            prefix = m.group(1)
            x = solve_pow(prefix)
        
            # 发送 x.encode('hex')
            io.sendline(x.hex().encode())
        
            round_num = 0
            accumulated_text = ""
        
            while True:
                round_num += 1
                log.info(f"========== Round {round_num} ==========")
        
                # 读取本轮题目,直到出现 @c2.encode('base64')=
                try:
                    data = io.recvuntil(b"@c2.encode('base64')=", timeout=10)
                    text = data.decode(errors="ignore")
                    log.info(f"Round {round_num} text:\n{text}")
                except EOFError:
                    log.warning("EOF received, checking for flag...")
                    break
                except Exception as e:
                    log.warning(f"Exception while receiving: {e}")
                    break
        
                # 解析并构造 c2
                result = parse_and_solve_round(text)
                if result is None:
                    log.error("Failed to parse round, trying interactive...")
                    io.interactive()
                    return
        
                c2_bytes, c2_b64 = result
        
                log.success(f"Sending c2 (base64): {c2_b64[:80]}... (len={len(c2_b64)})")
                io.sendline(c2_b64.encode())
        
                # 读取响应,检查是否成功
                try:
                    response = io.recvuntil(b"Good job!", timeout=5)
                    log.success(f"Round {round_num} passed!")
                except:
                    # 可能是最后一轮或者出错了
                    log.info("No 'Good job!' received, checking remaining output...")
                    try:
                        remaining = io.recv(timeout=2)
                        log.info(f"Remaining data: {remaining.decode(errors='ignore')}")
                        if b"flag" in remaining.lower() or b"FLAG" in remaining or b"{" in remaining:
                            log.success(f"Possible flag found!")
                    except:
                        pass
                    break
        
            # 最后尝试获取所有剩余输出
            try:
                io.settimeout(3)
                final = io.recvall(timeout=3)
                log.info(f"Final output: {final.decode(errors='ignore')}")
            except:
                pass
        
            io.interactive()
        
        if __name__ == "__main__":
            main()
        

        常见的CBC约束控制

        2.RSA
        题干:
        N = 162178605357818616394571566923155907889899677780239882906511996614607940884142045197452389471499799373787832649318837814454679970724845203557871078001956378966434166323827984964942729898095347038272003371167123553368531662277059263517900162297903110415768403265100411543878859321181606008503516896600638590699
        e1 = 35422
        c1 = 153249315480380808558746807096025628082875635601515291525075274335055878390662930254941118045696231628008256877302589689883059616503108946971165183674522403835250738176157466145855833767128209866527507862726083268576304163200171600023472544755768741118904892489037291247455823396160705615280802805803254323033
        e2 = 1033
        c2 = 5823189490163315770684717059899864988806118565674660089157163486577056500243194221873916232616081138765317598078910078375360361118674333149663483360677725162911935082290640547407140413703664960164356579153623498735889314476063673352676918268911309402784919521792079943937126634436658784515914270266106683548
        WP:
        #一眼顶真,是共模攻击,并且互质,起飞
        from Crypto.Util.number import *
        n = 162178605357818616394571566923155907889899677780239882906511996614607940884142045197452389471499799373787832649318837814454679970724845203557871078001956378966434166323827984964942729898095347038272003371167123553368531662277059263517900162297903110415768403265100411543878859321181606008503516896600638590699
        e1 = 35422
        c1 = 153249315480380808558746807096025628082875635601515291525075274335055878390662930254941118045696231628008256877302589689883059616503108946971165183674522403835250738176157466145855833767128209866527507862726083268576304163200171600023472544755768741118904892489037291247455823396160705615280802805803254323033
        e2 = 1033
        c2 = 5823189490163315770684717059899864988806118565674660089157163486577056500243194221873916232616081138765317598078910078375360361118674333149663483360677725162911935082290640547407140413703664960164356579153623498735889314476063673352676918268911309402784919521792079943937126634436658784515914270266106683548
        s1=pow(e1+e2,-1,e2)
        s2=(1-e1*s1)//e2
        t1=pow(c1,s1,n)
        t2=pow(c2,s2,n)
        m=(t1*t2)%n
        m=long_to_bytes(m)
        print(m)
        

        共模攻击

        3.近似方程
        题干:
        from Crypto.Util.number import *
        import hashlib
        
        p,x,a,b,c=getPrime(2025), getPrime(1024),getPrime(512),getPrime(1024),getPrime(1500)
        y=x**4+a*x**2+b*x+c
        print(f"y={y}")
        print(f"b={b}")
        print(f"c={c}")
        print(f"p={p}")
        flag=b'flag{'+hashlib.md5((str(a)).encode()).hexdigest().encode()+b'}'
        flag
        '''
        y=198522960435841482189432265177909868426431703074708363449219028697324701510160286719731988116839697036160581630187160949885168801231636762705713983033164840216512010109089390010468198557792366011939222563881564708155342114969230636341034212421633874868858789397938243061335664034978831542864101231007091988193863118052712382091154270467198016237288512835005671248249864343182623298497353279333896185090300689372993251851698985725825619040354352099701531339567909888327001736937441117830890673409609636796619930226667955511073115983145641056494143455805357766933615911269415380543240132925744315363193308341329870002528062545716167903459438493154302274735882612908825416096548207130441684370171413794313131775960498691561791175984389699661776179746486882233034632979256741127422204726199986374102650551713456275685579171314911783130052174900534533297618292233601037654694611306838303066884626125878765611689352475739052132349596965687310082111652949904102268706219733830038063864703811394198182986558883397487207721093367621647038297033723455527107418011037322197091733780060565430632034276705456268207898108856563488519654411483838153783153351440293627133844440601677480833571012370843618968387929873540183054860492446381685034534436
        b=174037789483961573123221843591212086149338262121485604600830887974881925500571571986993457692950300053374733237615433793104052491813933671943903946487842930332507742237430616633825365722075237337670353892075697891908329460336348924680104502864021820883975695834115061923434753902679746280494899854826747016131
        c=33472511251772997775575923606329341691183359500908766818057589728522254242596438955590397842265158831677351198820346034459567637818737702918129437591421137895764213815168420429024803177742927091662422333575499875132388315943460516679655107714170719351306979285358080183600281172752401859701765071852769889627868633217209348758684870450300228084878260106253395883903968044935866937201968348531962567937222914516096107266208665856669507873113157476771707
        p=3634071908867506965069315261429753443464716245738410040251875581513557838289276325218462157875991826224641777953866288921260305341272244121296068932207702190214606897491230548638292125061653257219859677992258434311277440482616823776560279337140379719082621412099620617217597998553091192312010588644683350990634085010622936842730027266359749795759745712453727285078472696717945991398633345949433118817923844577431455021644322229917758424788807006347476518982567210018019855197933776595555771047454297485885425728424948978147686731066201483794340469411549870237470492555193178687911573753715584786785924202386461
        '''
        WP:
        from Crypto.Util.number import *
        import hashlib
        from decimal import Decimal,getcontext#引入小数处理
        y=198522960435841482189432265177909868426431703074708363449219028697324701510160286719731988116839697036160581630187160949885168801231636762705713983033164840216512010109089390010468198557792366011939222563881564708155342114969230636341034212421633874868858789397938243061335664034978831542864101231007091988193863118052712382091154270467198016237288512835005671248249864343182623298497353279333896185090300689372993251851698985725825619040354352099701531339567909888327001736937441117830890673409609636796619930226667955511073115983145641056494143455805357766933615911269415380543240132925744315363193308341329870002528062545716167903459438493154302274735882612908825416096548207130441684370171413794313131775960498691561791175984389699661776179746486882233034632979256741127422204726199986374102650551713456275685579171314911783130052174900534533297618292233601037654694611306838303066884626125878765611689352475739052132349596965687310082111652949904102268706219733830038063864703811394198182986558883397487207721093367621647038297033723455527107418011037322197091733780060565430632034276705456268207898108856563488519654411483838153783153351440293627133844440601677480833571012370843618968387929873540183054860492446381685034534436
        b=174037789483961573123221843591212086149338262121485604600830887974881925500571571986993457692950300053374733237615433793104052491813933671943903946487842930332507742237430616633825365722075237337670353892075697891908329460336348924680104502864021820883975695834115061923434753902679746280494899854826747016131
        c=33472511251772997775575923606329341691183359500908766818057589728522254242596438955590397842265158831677351198820346034459567637818737702918129437591421137895764213815168420429024803177742927091662422333575499875132388315943460516679655107714170719351306979285358080183600281172752401859701765071852769889627868633217209348758684870450300228084878260106253395883903968044935866937201968348531962567937222914516096107266208665856669507873113157476771707
        p=3634071908867506965069315261429753443464716245738410040251875581513557838289276325218462157875991826224641777953866288921260305341272244121296068932207702190214606897491230548638292125061653257219859677992258434311277440482616823776560279337140379719082621412099620617217597998553091192312010588644683350990634085010622936842730027266359749795759745712453727285078472696717945991398633345949433118817923844577431455021644322229917758424788807006347476518982567210018019855197933776595555771047454297485885425728424948978147686731066201483794340469411549870237470492555193178687911573753715584786785924202386461
        getcontext().prec=3000#设置精度为3000位的10进制数
        x_root4=int(Decimal(y).sqrt().sqrt())#精确得出开方
        for move in range(-10,10):#设置左右偏移检查量
            x_try=x_root4+move
            if x_try<=0:#只考虑整数
                continue
            if isPrime(x_try):
                a=(y-x_try**4-b*x_try-c)//(x_try**2)
                if isPrime(a):
                    if a.bit_length()==512:
                        print("解出a")
                        md5a=hashlib.md5(str(a).encode()).hexdigest()
                        print(f"flag{{{md5a}}}")#3重{}才可以输出{}

        如题名

        4.哈希控制
        题干:
        #目标是输入值使sha256的后20位是0
        WP:

        #数据来源:前导0的网站:https://www.bitmex.com/blog/bitcoins-lowest-block-hash-values

        import hashlib
        import base64
        #自己构造b'0'*20吗,开什么玩笑
        text="00004020b97d5e09984585663a48d8de73233254ab2ee13bd72f07000000000000000000a48018a3bd388812511e9d068d9cd711a82b78d3918482cd2ee3c9bbd0b2b70b283ee75e357f141704176980"
        text=hashlib.sha256(bytes.fromhex(text)).hexdigest()
        print(text)
        text="7c4dea8e47e58b2a1f8ecf9020b95df164dbfccc0f5cfff21993a1df7d0946ae"
        text=hashlib.sha256(bytes.fromhex(text)).hexdigest()
        print(text)
        print(len(b'0000000000000000000000'))
        t="7c4dea8e47e58b2a1f8ecf9020b95df164dbfccc0f5cfff21993a1df7d0946ae".encode()
        t=base64.b64encode(t)
        print(t)

        查询数据

        古剑山2024part
        1.guess the key
        题干:
        jhjnjcjikmkfjjjkkejkkekdjgjcjnjhjnjcjiko
        WP:
        这是一个已知明文攻击,知道flag开头是flag{
        大胆猜测,j和k代表的设不同的分组,或者不同的加密
        这种情况下,没有密钥,大概率是编码或者恺撒
        编码不对,太过整齐
        恺撒处理前4个,发现偏移量是2,得到j的偏移是2,k对应{,得到偏移12
        取出来,放在恺撒处理器里面,得到flag

        比较好猜的恺撒

        2.sign in RSA
        题干:
        Crypto
        babyRSA#
        题目信息
        
        p=105570604806073931560404187362816308950408774915960751676958845800335871518600455146040240314204606944641098914858159386588868785987100524581699043605351952348586132553458702298393907476955946990849442034441882748278181148503329309660427627438266645843535466462936882505833453738522673603026747578372964995367
        q=143288358949089585215266953016278524463612148007190135453434243047032456958207376091733443584531919755660149037321119885867830905350806865862130270602628423547624190876473872180462192096873381471710899246073298439365336797201672838785511965949336068032011363484044690916570288372443303750426476423930352603827
        e=33
        c=2015688184356018702340063509729974600786840546364122789630929715337660295810961474144939260049892177486759513271253257458112942844435453563521353664294799145214833075575682837104619902593712323020851788866158742546117774717790910939444986189326649593286629046732910564929050955013637088916579175350308099506220813882274665233182543235264034038626524248300357250276274833999274982434790398489181021739913941634249265775997527901903799819193254397528348894700572493228638350806878366316533768758273322476421225382269304595973225131694907875536065669987510951854843686992445396860396865892650745594418900376500862332616
        WP:
        from Crypto.Util.number import *
        import re#这个可以去掉无效字符
        p=105570604806073931560404187362816308950408774915960751676958845800335871518600455146040240314204606944641098914858159386588868785987100524581699043605351952348586132553458702298393907476955946990849442034441882748278181148503329309660427627438266645843535466462936882505833453738522673603026747578372964995367
        q=143288358949089585215266953016278524463612148007190135453434243047032456958207376091733443584531919755660149037321119885867830905350806865862130270602628423547624190876473872180462192096873381471710899246073298439365336797201672838785511965949336068032011363484044690916570288372443303750426476423930352603827
        e=33
        c=2015688184356018702340063509729974600786840546364122789630929715337660295810961474144939260049892177486759513271253257458112942844435453563521353664294799145214833075575682837104619902593712323020851788866158742546117774717790910939444986189326649593286629046732910564929050955013637088916579175350308099506220813882274665233182543235264034038626524248300357250276274833999274982434790398489181021739913941634249265775997527901903799819193254397528348894700572493228638350806878366316533768758273322476421225382269304595973225131694907875536065669987510951854843686992445396860396865892650745594418900376500862332616
        n=p*q
        phi=(p-1)*(q-1)
        d=pow(e,-1,phi)
        m=pow(c,d,n)
        m=long_to_bytes(m)
        m=re.search(rb"flag\{.*?\}",m)#re.search()寻找,rb"flag\}(这里的\是转译,表示{是
        print(m)                      #目标而非寻找符)开头,.*?表示找多个字符,\}停止于
                                      #第一个}

        不同于普通的签到,这里还考了无效排除

        我比较喜欢的比赛,考的比较接近我学的,也有题扩展了视野,2024的RSA提醒无效排除很有启发性

      • ISCTF2025 WP

        新生赛,出的难度和题面 包含度都不如自家的0X,最后是差一道发病题AK(100%差评率的含金量),不过还是能起到复习的作用,最大的收获是学了一下无效曲线攻击,见了一下密码黑盒

        1.power tower
          题干:
          from Crypto.Util.number import *
          import random
          from numpy import number
          
          m = b'ISCTF{****************}'
          flag = bytes_to_long(m)
          n = getPrime(256)
          t = getPrime(63)
          l = pow(2,pow(2,t),n)
          c = flag ^ l
          print(t)
          print(n)
          print(c)
          
          
          '''
          t = 6039738711082505929
          n = 107502945843251244337535082460697583639357473016005252008262865481138355040617
          c = 114092817888610184061306568177474033648737936326143099257250807529088213565247
          '''
          WP:
          1.power tower  b'ISCTF{Euler_1s_v3ry|useful!!!!!}'
          实际上就是对大的次方数进行扩展欧拉化简,降低计算

          没什么好说的,学了信安数基的都会

          2.LSFR
          题干:
          import secrets
          import binascii
          
          def simple_lfsr_encrypt(plaintext, init_state):
              mask = [random.randint(0,1) for _ in range(128)]
              
              state = init_state.copy()
              for _ in range(256):
                  feedback = sum(state[i] & mask[i] for i in range(128)) % 2
                  state.append(feedback)
              
              key = bytes(int(''.join(str(bit) for bit in mask[i*8:(i+1)*8]), 2) 
                         for i in range(16))
              
              keystream = (key * (len(plaintext)//16 + 1))[:len(plaintext)]
              return bytes(p ^ k for p, k in zip(plaintext, keystream)), mask
          initState = [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]
          outputState = [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1]
          ciphertext = '4b3be165a0a0edd67ca8f143884826725107fd42d6a6'
            WP:
            1. 利用已知明文拿到部分 key
              密文是:
              4b3be165a0a0edd67ca8f143884826725107fd42d6a6
              转成 bytes 后长度为 22。根据代码,keystream = key 重复,所以:
              plaintext[i] = ciphertext[i] ^ key[i mod 16]
              已知明文前缀 ISCTF{(6 字节),于是前 6 个 key 字节可以直接算出:
              key[0..5] = ciphertext[0..5] XOR b”ISCTF{“
              算出来是:
              key[0..5] = [0x02, 0x68, 0xA2, 0x31, 0xE6, 0xDB]
              同时假设最后一个字符是 }(CTF 常见 flag 结尾),可验证:
              key[5] == ciphertext[21] ^ ord(‘}’)
              结果确实也是 0xDB,说明假设是对的。
              这一步还能顺便把一部分明文还原出来(只用前 6 个 key 字节就能解出 index 0..5 和 16..21 的明文):
              ISCTF{??????????So_s0}
              所以 flag 内部结构已经非常像:

            ISCTF{??????????So_s0}

            1. 用 initState + outputState 解出完整 mask(从而解出完整 key)
              关键点在于:整个 key 的 16 字节是由 128 位 mask 按 8 位一组拼出来的:
              key = bytes(int(”.join(str(bit) for bit in mask[i8:(i+1)8]), 2)
              for i in range(16))
              而 initState 和 outputState 是 LFSR 的内部信息:
              我们可以做一个合理的 LFSR 建模(标准做法):
              状态 s_t 是长度 128 的比特串
              初始状态 s_0 = initState
              每一轮输出一位 o_t = outputState[t]
              假设输出位是反馈位,满足:
              o_t = \sum_{i=0}^{127} mask[i] \cdot s_t[i] \pmod 2
              s_{t+1} = s_t[1:] \,|\, o_t
              这样我们就能:
            2. 从 initState 和 outputState 依次算出 每一轮的状态 s_t(完全已知)。
            3. 对每个 t 建立一条线性方程:
              o_t = s_t \cdot mask \pmod 2
              把解出来的 128 位 mask 按题目给的方式每 8 位打包成一个字节,就得到了完整的 16 字节 key。实际算出来的结果是:
              key = 02 68 A2 31 E6 DB 81 B0 49 FA AE 29 DD 3B 52 2D

            注意前 6 个字节正好就是上面“已知明文 XOR 密文”算出的结果,说明模型和方程都对上了。

            1. 用完整 key 解密密文
              最终 keystream 还是:
              keystream = (key * (len(ciphertext)//16 + 1))[:len(ciphertext)]
              plaintext = ciphertext ^ keystream
              实际解出来的明文是:
              ISCTF{lf5R_jUst_So_s0}
              完全是可读的 CTF flag 格式。
            #还是常用的已知flag头攻击
            #解LFSR的矩阵,再xor得出结果

            正常的矩阵解LFSR

              3.baby_math
              题干:
              from Crypto.Util.number import bytes_to_long
              
              print(len(flag)) 
              R = RealField(1000)
              a,b = bytes_to_long(flag[:len(flag)//2]),bytes_to_long(flag[len(flag)//2:])
              x   = R(0.75872961153339387563860550178464795474547887323678173252494265684893323654606628651427151866818730100357590296863274236719073684620030717141521941211167282170567424114270941542016135979438271439047194028943997508126389603529160316379547558098144713802870753946485296790294770557302303874143106908193100)
               
              enc = a*cos(x)+b*sin(x) 
               
              
              #1.24839978408728580181183027675785982784764821592156892598136000363397267152291738689909414790691435938223032351375697399608345468567445269769342300325192248438038963977207296241971217955178443170598629648414706345216797043374408541203167719396818925953801387623884200901703606288664141375049626635852e52
              
              WP:
              #看见构型,可以化为矩阵正交,使用格基规约
              ###sage  
              #(a, b, −1)⋅(cosx, sinx, enc)=0
              #给他转回整数,统统*10*200
              from sage.all import *
              from Crypto.Util.number import long_to_bytes
              R = RealField(5000)
              x = R("0.75872961153339387563860550178464795474547887323678173252494265684893323654606628651427151866818730100357590296863274236719073684620030717141521941211167282170567424114270941542016135979438271439047194028943997508126389603529160316379547558098144713802870753946485296790294770557302303874143106908193100")
              enc = R("1.24839978408728580181183027675785982784764821592156892598136000363397267152291738689909414790691435938223032351375697399608345468567445269769342300325192248438038963977207296241971217955178443170598629648414706345216797043374408541203167719396818925953801387623884200901703606288664141375049626635852e52")
              cosx = cos(x)
              sinx = sin(x)
              S = 10^200 
              v1 = int(cosx * S)
              v2 = int(sinx * S)
              v3 = int(-enc * S)
              M = Matrix(ZZ, [
                  [v1, 1, 0],
                  [v2, 0, 1],
                  [v3, 0, 0]
              ])
              print("开始 LLL...")
              B = M.LLL()
              print(LLL 完成")
              print("LLL 输出前 5 行:")
              print(B[:5])
              candidates = []
              for row in B:
                  a = row[1]
                  b = row[2]
                  if a != 0 and b != 0:
                      diff = abs(a*cosx + b*sinx - enc)
                      if diff < R("1e-60"):
                          print("找到可能解: ")
                          print("a =", a)
                          print("b =", b)
                          flag = long_to_bytes(a) + long_to_bytes(b)
                          candidates.append(flag)
                          print("flag =", flag)
              print("\n所有候选 flag:")
              for f in candidates:
                  print(f)

              挺新奇的题,但思路很明显,正交得0

              4.密码黑盒
              题干:

              黑盒,输入a,b,c加密内容,得到加密结果

              WP:

              一道黑盒,先逐步改变参数,得到最基本的信息。这是逐字符的ECB模式
              接下得到所有字符的加密结果,一个一个对应就行
              注意控制一样的a,b,c输入,不然会加密不一样
              这里发现a=123,b=321,c=213输入是有效的
              加密qwertyuiopasdfghjklzxcvbnm1234567890-=[]\;’,./QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_+{}|:”<>?
              这里可能会有多对1,除去收尾的{},里面无{},有-,根据uuid(用于生成动态flag),格式是
              ISCTF{b4a65e16-ecaf-429c-0000-0000000bfbc09}

              更详细的推导过程:

              from Crypto.Util.number import *
              mes=”00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00″
              print(len(mes.split()))
              123 321 213
              a 09
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              b 2a
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              c a5
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              d a2
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              e 4b
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              f 99
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              g c3
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              h 69
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              i 8a#可以得到a,b,c影响flag的输出,c影响p的输出
              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              abcd 09 2a a5 a2#可以得到是分组处理
              321 123 213
              a 30
              60 cf 4b 6f b7 90 90 30 03 33 7b 48 a5 a8 6c 09 a5 36 39 6c 90 7e 90 30 6c 03 a5 33 09 6c 81 39 48 48 18 33 09 33 30 09 36 a5 39
              b a5
              c 36
              d 5d
              e 7e
              f 33
              49 53 43 54 46 7b–ISCTF{
              原文: qwertyuiopasdfghjklzxcvbnm

              密文:

              cf 9c 4b cc 93 42 c6 8a 03 51 09 72 a2 99 c3 69 7e 1e 12 bd 90 a5 96 2a ae 33
              加密结果
              原文: 1234567890

              密文:

              90 42 bd 87 84 75 ba 6c 3c 9c
              原文: !@#$%^&*(){}|:”<>?

              密文:

              69 6f 7e 1e 12 00 33 cf 03 51 87 75 84 81 8a 63 c0 5d
              原文: QWERTYUIOPASDFGHJKLZXCVBNM

              密文:

              21 b7 57 39 1b 18 60 45 3f b1 24 d2 54 a8 4e c9 48 8d 36 15 27 0f 30 66 2d 78

                                                                                                                5

              45 d2 0f 1b a8 87 87 09 6c 99 9c ba 2a 42 93 3c 2a a5 75 93 87 4b 87 09 93 6c 2a 99 3c 93 bd 75 ba ba 84 99 3c 99 09 3c a5 2a 75
              I S C T F { { a 8 f w 7 b 2 t 9 b c 6 t { e { a t 8 b f 9 t z 6 7 7 | f 9 f a 9 c d }
              ISCTF{4a8fw7b659bc6te4a58bf9t36775f9ff9cd}
              ISCTF{4a8fw7byt9bc6t4e4at8bf9tz6775f9fa9cb}
              ISCTF{{a8fw7b2t9bc6t{e{at8bf9tz677|f9fa9cd}
              45 d2 0f 1b a8 87 2a 87 09 75 84 4b 90 75 93 4b a5 09 99 93 87 42 3c a5 93 3c 90 6c 6c 93 84 84 6c a2 3c 6c 2a 99 2a a5 9c 3c 75
              I S C T F 4 b 4 a 6 5 e
              原文: qwertyuiopasdfghjklzxcvbnm

              密文:

              4b 01 4b 6a 00 1d 9f 89 39 78 9f 6d 6a 78 39 86 58 5f 58 4e 16 6d b0 00 86 89
              原文: 1234567890

              密文:

              a6 76 1c 56 42 7c 68 a2 48 be
              原文: !@#¥%……&*()——+{}|:“《》?-=【】、;‘,。/

              密文:

              96 6e 9e ac 9a 90 90 04 14 16 74 b8 b8 50 5c 16 d4 7e 4a 8a 8c 0e 7a 2a 4e ca 62 9a ce 8e 08 66
              原文: QWERTYUIOPASDFGHJKLZXCVBNM

              密文:

              3c 46 ba 12 ce a8 30 ae 5e b8 aa 54 98 24 40 20 c4 52 cc c0 4a 84 a0 b0 80 2c
              原文: qwertyuiopasdfghjklzxcvbnm

              密文:

              32 4c 8c 34 2e d2 bc 1a 0a 5a 02 b2 8a 64 b4 86 4e ca 70 b6 36 0c 96 90 38 a4

              利用这一组数据再求一次ae 54 84 ce 24 5c 90 56 02 7c 42 8c a6 7c 7a 8c 0c 02 64 7a 56 76 48 0c 7a 48 a6 a2 a2 7a 42 42 a2 8a 48 a2 90 64 90 0c be 48 16
              ISCTF{b4a65e16-ecaf-429c-9188-558d98bfbc09}
              快看,是uuid4

              见识了一下黑盒,看见a,b,c时就应该猜得到是LCG,也可以像我一样根据唯一对应来做

              5.RSA_level_up
              题干:
              import json, secrets
              from Crypto.Util.number import getPrime, bytes_to_long
              from Crypto.Cipher import AES
              from Crypto.Util.Padding import pad
              
              e = 3
              N = getPrime(512) * getPrime(512)
              
              a2_high = a2 >> LOW_BITS
              
              aes_key = secrets.token_bytes(16)
              m = bytes_to_long(aes_key)
              
              f = a2 * (m * m) + a1 * m + a0
              
              c = (pow(m, e) + f) % N
              
              iv = secrets.token_bytes(16)
              cipher = AES.new(aes_key, AES.MODE_CBC, iv=iv)
              ct = cipher.encrypt(pad(FLAG, 16))
              
              N = 121288600621198389662246479277632294800423697823363188896668775456771641807233781416525282234787873435904747571468452950479817935684848143651716343606633656969395065588423982440884464542428742861388200306417822228591316703916504170245990423925894477848679490979364923848426643149659758241239900845544537886777
              
              c = 3756824985347508967549776773725045773059311839370527149219720084008312247164501688241698562854942756369420003479117
              
              a2_high = 9012778
              
              LOW_BITS = 16
              
              a1 = 621315
              
              a0 = 452775142
              
              iv = bf38e64bb5c1b069a07b7d1d046a9010
              
              ct = 8966006c4724faf53883b56a1a8a08ee17b1535e1657c16b3b129ee2d2e389744c943014eb774cd24a5d0f7ad140276fdec72eb985b6de67b8e4674b0bcdc4a5
              WP:

              看穿 RSA 伪装 → 发现其实是普通三次整式方程 → 利用只差 16 位的系数穷举恢复 a2 → 解三次方程得到 m → 当作 AES key 解密拿 FLAG

              ###pyhon
              from Crypto.Cipher import AES
              from Crypto.Util.Padding import unpad
              
              N = 121288600621198389662246479277632294800423697823363188896668775456771641807233781416525282234787873435904747571468452950479817935684848143651716343606633656969395065588423982440884464542428742861388200306417822228591316703916504170245990423925894477848679490979364923848426643149659758241239900845544537886777
              c = 3756824985347508967549776773725045773059311839370527149219720084008312247164501688241698562854942756369420003479117
              a2_high = 9012778
              LOW_BITS = 16
              a1 = 621315
              a0 = 452775142
              
              iv = bytes.fromhex("bf38e64bb5c1b069a07b7d1d046a9010")
              ct = bytes.fromhex("8966006c4724faf53883b56a1a8a08ee17b1535e1657c16b3b129ee2d2e389744c943014eb774cd24a5d0f7ad140276fdec72eb985b6de67b8e4674b0bcdc4a5")
              
              A = a2_high << LOW_BITS   # a2 的高位部分
              
              def solve_for_m():
                  for r in range(1 << LOW_BITS):   # 穷举低 16 位
                      a2 = A + r
              
                      def P(x):
                          return x**3 + a2*x**2 + a1*x + (a0 - c)
              
                      lo, hi = 0, 1 << 128      # m 是 16 字节
                      Plo, Phi = P(lo), P(hi)
              
                      # 我们知道真正的情况应该是 P(0)<0, P(2^128)>0
                      if not (Plo < 0 and Phi > 0):
                          continue
              
                      # 二分查找唯一实根所在的整数点
                      while hi - lo > 1:
                          mid = (lo + hi) // 2
                          v = P(mid)
                          if v == 0:
                              return r, mid
                          if v < 0:
                              lo = mid
                          else:
                              hi = mid
              
                      if P(lo) == 0:
                          return r, lo
                      if P(hi) == 0:
                          return r, hi
              
                  raise ValueError("没找到整数根")
              
              r, m = solve_for_m()
              print("r =", r)
              print("m =", m)
              aes_key = m.to_bytes(16, "big")
              print("AES key =", aes_key.hex())
              
              cipher = AES.new(aes_key, AES.MODE_CBC, iv)
              pt = unpad(cipher.decrypt(ct), 16)
              print("FLAG =", pt.decode())

              去伪存真,mod未被激活,近似方程,爆破解题

              6.baby_math:
              题干:
              from Crypto.Util.number import *
              
              p = getPrime(1024)
              
              q = getPrime(1024)
              
              N = p*q
              
              e = 65537
              
              msg = bytes_to_long(b"ISCTF{dummy_flag}")
              
              ct1 = pow(msg, e, N)
              
              ct2 = pow(msg, p+q, N)
              
              print(f"{N = }")
              
              print(f"{ct1 = }")
              
              print(f"{ct2 = }")
              
              """
              N = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
              ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
              ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789
              WP:

              常见的可以手推得计算:

              n = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
              ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
              ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789
              e=65537
              #构造的方法和共模攻击一样
              #首先由p+q根据l变形成n+1,得到c1=m**e,c2=m**(n+1)
              #构造a*e+b*(n+1)=1,使c1**a*c2**b=m(modn)
              #解a,b:构造e*a-b*(n+1)=1,即gmpy2.invert(n+1,e)=b,再得到a
              #再代回c1**a*c2**b=m(modn),得解)
              from Crypto.Util.number import *
              import gmpy2
              b=gmpy2.invert(n+1,e)
              a=(1-b*(n+1))//e
              m=(pow(ct1,a,n)*pow(ct2,b,n))%n
              m=long_to_bytes(m)
              print(m)
              

              常见的手推型RSA结构题,构造贝组定理化简

              7.ECC
              题干:
              y² = x³ + 3x + 27 (mod p)
              
              Q(0xa61ae2f42348f8b84e4b8271ee8ce3f19d7760330ef6a5f6ec992430dccdc167, 0x8a3ceb15b94ee7c6ce435147f31ca8028d1dd07a986711966980f7de20490080)
              
              k= ?
              
              最终flag请将解出k值的16进制转换为32位md5以ISCTF{}包裹提交
              WP:
              #这种情况就是我们的G点不在曲线上,但计算机不会管,只会一直做代数运算
              #方法1就是直接MITM,两边或者一遍往一起走,直到撞上(此方法仅限于k小时可以用)
              #方法2是无效曲线攻击
              #part1:逐渐加上G,(曲线加法),记录字典,找出Q点的对应
              import hashlib
              p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
              a = 3
              Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
              Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
              Qx = 0xa61ae2f42348f8b84e4b8271ee8ce3f19d7760330ef6a5f6ec992430dccdc167
              Qy = 0x8a3ceb15b94ee7c6ce435147f31ca8028d1dd07a986711966980f7de20490080
              curr_x = Gx
              curr_y = Gy
              for k in range(2, 1000000): #尝试的字典范围
                  if curr_x == Gx and curr_y == Gy:
                      slope = (3 * curr_x * curr_x + a) * pow(2 * curr_y, p - 2, p) % p
                  else:
                      slope = (Gy - curr_y) * pow(Gx - curr_x, p - 2, p) % p
                  new_x = (slope * slope - curr_x - Gx) % p
                  new_y = (slope * (curr_x - new_x) - curr_y) % p
                  curr_x = new_x
                  curr_y = new_y
                  if curr_x == Qx and curr_y == Qy:
                      print(f"k = {k}")
                      k_hex = hex(k)[2:]
                      print(f"k_hex = {k_hex}") 
                      flag_md5 = hashlib.md5(k_hex.encode()).hexdigest()
                      print(f"ISCTF{{{flag_md5}}}")
                      break
              #part2:此时b不对,但我们可以构造一个b,使G,Q在曲线上,利用G点反推b
              #这一点成立的原因是点的运算不依赖b,G在曲线上,由G生成的Q也在
              #这时候构造的曲线的阶不是大素数,而是有很多个因子的小素数
              #拆解到小素数上分别求解,然后用CRT合并#就是Pohlig–Hellman
              p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
              a = 3
              Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
              Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
              Qx = 0xa61ae2f42348f8b84e4b8271ee8ce3f19d7760330ef6a5f6ec992430dccdc167
              Qy = 0x8a3ceb15b94ee7c6ce435147f31ca8028d1dd07a986711966980f7de20490080
              #自己用py的input互动脚本做
              

              这道题就是比赛时差的那道,出题人的hint回路果然是只有自己能理解的

              到此为结

            • CISCN WP

              国赛,算是我第一个打的久负盛名的比赛,但他用实际向我证明了有名气不等于题出的好的道理(流汗黄豆),一共3道题,比赛时战绩为1道,但实际上除了混进来的RE之外的题都挺常见,算是开阔眼见了。

              ECDSA,挺标准的一道题
              题干:
              #!/usr/bin/env python3
              from ecdsa import SigningKey, NIST521p
              from hashlib import sha512
              from Crypto.Util.number import long_to_bytes
              import random
              import binascii
              import sys
              
              digest_int = int.from_bytes(sha512(b"Welcome to this challenge!").digest(), "big")
              curve_order = NIST521p.order
              priv_int = digest_int % curve_order
              priv_bytes = long_to_bytes(priv_int, 66)
              sk = SigningKey.from_string(priv_bytes, curve=NIST521p)
              vk = sk.verifying_key
              
              f_pub = open("public.pem", "wb")
              f_pub.write(vk.to_pem())
              f_pub.close()
              
              def nonce(i):
                  seed = sha512(b"bias" + bytes([i])).digest()
                  k = int.from_bytes(seed, "big")
                  return k
              
              msgs = [b"message-" + bytes([i]) for i in range(60)]
              sigs = []
              
              for i, msg in enumerate(msgs):
                  k = nonce(i)
                  sig = sk.sign(msg, k=k)
                  sigs.append((binascii.hexlify(msg).decode(), binascii.hexlify(sig).decode()))
              
              f_sig = open("signatures.txt", "w")
              for m, s in sigs:
                  f_sig.write("%s:%s\n" % (m, s))
              f_sig.close()
              -----BEGIN PUBLIC KEY-----
              MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBCmmiMNZTXuR44GdzljZErCUcNgf5
              jpCcPTL31HYx8EUdoFh4JC+4kUBFxTn7VzuHxFUBLYmNGO1Jow6QqpDfLb0B+2d4
              vs4wjNqvFZ1ET79VDt1AcgySGWX8KlAgizrmIGwXJmp1UfewMhv2f5EDbu3vVU9m
              f1WeP2aRaDHmG4ryVkg=
              -----END PUBLIC KEY-----
              #省去数据pem
              WP:

              1.已知d邪道:

              from hashlib import sha512,md5
              digest_int = int.from_bytes(sha512(b"Welcome to this challenge!").digest(), "big")
              flag=md5(str(digest_int).encode()).hexdigest()
              print(flag)

              2.常规思路:

              #思路很简单,题上直接有k,是最简单的k已知
              from hashlib import sha512,md5,sha1
              from ecdsa import NIST521p,VerifyingKey
              from Crypto.Util.number import *
              import gmpy2
              n=NIST521p.order#获取阶
              with open("pub.pem","rb")as f:
                  vk=VerifyingKey.from_pem(f.read())#读取公钥。这一步实际上没必要
              with open("signatures.txt","r")as f:
                  line=f.readline().strip()#读取第0条签名,readline只读第一行
              m_hex,sig_hex=line.split(":")#按照:分成2段
              msg=bytes.fromhex(m_hex)#这一步只是从hex()转化成了bytes
              sig=bytes.fromhex(sig_hex)
              r = int.from_bytes(sig[:66], "big")#这里用int转化成数字
              s = int.from_bytes(sig[66:], "big")#读取签名,这里我才知道签名是写在一起没有间隔的
              k = int.from_bytes(sha512(b"bias" + bytes([0])).digest(), "big") % n
              e = int.from_bytes(sha1(msg).digest(), "big")
              d = ((s * k - e) * gmpy2.invert(r, n)) % n#公式
              flag = md5((str(d)).encode()).hexdigest()
              print(flag)
              

              属于常见的已知k的思路

              Pollard P-1算法
                题干:暗示得很明显
                from Crypto.Util.number import *
                from tqdm import tqdm
                import os
                
                flag=open("./flag.txt","rb").read()
                flag=bytes_to_long(flag+os.urandom(2048//8-len(flag)))
                e=65537
                
                def get_smooth_prime(bits, smoothness, max_prime=None):
                    assert bits - 2 * smoothness > 0
                    p = 2
                    if max_prime!=None:
                        assert max_prime>smoothness
                        p*=max_prime
                        
                    while p.bit_length() < bits - 2 * smoothness:
                        factor = getPrime(smoothness)
                        p *= factor
                
                    bitcnt = (bits - p.bit_length()) // 2
                    while True:
                        prime1 = getPrime(bitcnt)
                        prime2 = getPrime(bitcnt)
                        tmpp = p * prime1 * prime2
                        if tmpp.bit_length() < bits:
                            bitcnt += 1
                            continue
                        if tmpp.bit_length() > bits:
                            bitcnt -= 1
                            continue
                        if isPrime(tmpp + 1):
                            p = tmpp + 1
                            break
                    return p
                
                p1=getPrime(512)
                q1=getPrime(512)
                r1=getPrime(512)
                s1=getPrime(512)
                n1=p1*q1*r1*s1
                assert n1>flag
                
                p=get_smooth_prime(1024,20,p1)
                q=get_smooth_prime(1024,20,q1)
                r=get_smooth_prime(1024,20,r1)
                s=get_smooth_prime(1024,20,s1)
                n=p*q*r*s
                
                print(f"[+] inner RSA modulus = {n1}")
                print(f"[+] outer RSA modulus = {n}")
                print(f"[+] Ciphertext = {pow(flag,e,n1)}")
                #省去数据流
                  WP:
                  #理解了这道题后,得到p-1=2*max_prime*20_bytes素数n个*prime1*prime2,p是1024-bit
                  #除了max_prime,都是平滑的,a判断出要用p-1
                  #手上有(getPrime())512*512*512*512得到的n1;n=p*q*r*s,p-1,q-1,r-1,s-1,max_prime=前面的512
                  #得到p-1//P(getPrime),有gcd(p-1,n1)=p,其他同理,得到所有的p,q,r,s得到n,计算m
                  #现在想怎么得到p.q.r.s现在有的就是n,就是p-1算法,详情看上面的p-1分解
                  #接下来就是有t的逐层剥离,说实话,我不太会这种有点抽象的程序实现
                  # solve_gmpy2.py
                  # Optimized for this challenge using gmpy2 (powmod/gcd/invert/is_prime)
                  
                  import gmpy2
                  from gmpy2 import mpz#加速,转化成C语言的大数字计算,更快
                  from Crypto.Util.number import long_to_bytes
                  
                  # -------------------- 题目输出(已填入) --------------------
                  n1 = mpz(16141229822582999941795528434053604024130834376743380417543848154510567941426284503974843508505293632858944676904777719167211264225017879544879766461905421764911145115313698529148118556481569662427943129906246669392285465962009760415398277861235401144473728421924300182818519451863668543279964773812681294700932779276119980976088388578080667457572761731749115242478798767995746571783659904107470270861418250270529189065684265364754871076595202944616294213418165898411332609375456093386942710433731450591144173543437880652898520275020008888364820928962186107055633582315448537508963579549702813766809204496344017389879)
                  
                  n  = mpz(484831124108275939341366810506193994531550055695853253298115538101629337644848848341479419438032232339003236906071864005366050185096955712484824249228197577223248353640366078747360090084446361275032026781246854700074896711976487694783856878403247312312487197243272330518861346981470353394149785086635163868023866817552387681890963052199983782800993485245670437818180617561464964987316161927118605512017355921555464359512280368738197370963036482455976503266489446554327046948670215814974461717020804892983665655107351050779151227099827044949961517305345415735355361979690945791766389892262659146088374064423340675969505766640604405056526597458482705651442368165084488267428304515239897907407899916127394598273176618290300112450670040922567688605072749116061905175316975711341960774150260004939250949738836358264952590189482518415728072191137713935386026127881564386427069721229262845412925923228235712893710368875996153516581760868562584742909664286792076869106489090142359608727406720798822550560161176676501888507397207863998129261472631954482761264406483807145805232317147769145985955267206369675711834485845321043623959730914679051434102698588945009836642922614296598336035078421463808774940679339890140690147375340294139027290793)
                  
                  c  = mpz(657984921229942454933933403447729006306657607710326864301226455143743298424203173231485254106370042482797921667656700155904329772383820736458855765136793243316671212869426397954684784861721375098512569633961083815312918123032774700110069081262242921985864796328969423527821139281310369981972743866271594590344539579191695406770264993187783060116166611986577690957583312376226071223036478908520539670631359415937784254986105845218988574365136837803183282535335170744088822352494742132919629693849729766426397683869482842748401000853783134170305075124230522253670782186531697976487673160305610021244587265868919495629)
                  
                  e = mpz(65537)
                  
                  
                  # -------------------- 工具:筛 primes <= Bmax(Python int 即可) --------------------
                  #这个可以复用。用来扫描范围的素数
                  def primes_upto(Bmax: int):
                      sieve = bytearray(b"\x01") * (Bmax + 1)#建立一个布尔值的列表
                      sieve[0:2] = b"\x00\x00"
                      import math
                      for i in range(2, int(math.isqrt(Bmax)) + 1):
                          if sieve[i]:
                              step = i
                              start = i * i
                              sieve[start:Bmax+1:step] = b"\x00" * (((Bmax - start) // step) + 1)
                      return [i for i in range(2, Bmax + 1) if sieve[i]]
                  
                  
                  # -------------------- Stage1 核心:算 a^{lcm(1..B)} mod N(用 gmpy2.powmod) --------------------
                  #这个可以复用a**lcm(1..B)mod n,并且还有对应素数链
                  def pow_lcm(a: mpz, B: int, N: mpz, primes_list):
                      """
                      返回 x = a^{lcm(1..B)} mod N
                      """
                      x = a % N
                      for ell in primes_list:
                          if ell > B:
                              break
                          t = ell
                          while t * ell <= B:
                              t *= ell
                          x = gmpy2.powmod(x, t, N)  # fast powmod
                      return x
                  
                  
                  # -------------------- 本题“补大因子”的命中函数(用 gmpy2.gcd / powmod) --------------------
                  #命中器复用,简称gcd,gcd(p-1,n)
                  def hit_outer_factor(N: mpz, n1_inner: mpz, B: int, primes_list, a_int: int):
                      """
                      b = a^{lcm(1..B)} mod N
                      g = gcd(b^{n1}-1, N)
                      """
                      a = mpz(a_int)
                      g0 = gmpy2.gcd(a, N)
                      if 1 < g0 < N:
                          return g0
                  
                      b = pow_lcm(a, B, N, primes_list)
                      y = gmpy2.powmod(b, n1_inner, N)
                      g = gmpy2.gcd(y - 1, N)
                      if 1 < g < N:
                          return g
                      return None
                  
                  
                  # -------------------- 外层递归分解(允许 gcd 先吐出乘积因子) --------------------
                  #逐层剥离复用
                  def factor_outer(n_outer: mpz, n1_inner: mpz, primes_list):
                      # 更丰富一点的底数集合
                      a_list = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
                  
                      B0 = 1_048_576
                      coarse = list(range(B0, 860_000, -20_000))
                      fine_steps = [5000, 2000, 1000, 500]
                  
                      def try_split_once(X: mpz):
                          if gmpy2.is_prime(X):
                              return None
                  
                          # coarse scan
                          for B in coarse:
                              for a in a_list:
                                  g = hit_outer_factor(X, n1_inner, B, primes_list, a)
                                  if g is not None:
                                      return (g, B, a)
                  
                          # fine scan
                          for step in fine_steps:
                              for B in range(B0, 860_000, -step):
                                  for a in a_list:
                                      g = hit_outer_factor(X, n1_inner, B, primes_list, a)
                                      if g is not None:
                                          return (g, B, a)
                  
                          return None
                  
                      stack = [n_outer]
                      primes = []
                  
                      while stack:
                          X = stack.pop()
                          if X == 1:
                              continue
                          if gmpy2.is_prime(X):
                              primes.append(X)
                              continue
                  
                          res = try_split_once(X)
                          if res is None:
                              raise RuntimeError(
                                  f"[!] Failed to split a composite of {int(gmpy2.bit_length(X))} bits. "
                                  f"Try extending B scan range or adding more a values."
                              )
                  
                          g, B_used, a_used = res
                          print(f"[+] split (bits={int(gmpy2.bit_length(X))}) using B={B_used}, a={a_used}, got g bits={int(gmpy2.bit_length(g))}")
                          stack.append(g)
                          stack.append(X // g)
                  
                      primes.sort()
                      return primes
                  
                  
                  # -------------------- 从外层素数 P 抽内层素数:gcd(P-1, n1) --------------------
                  def recover_inner_primes(outer_primes, n1_inner: mpz):
                      rem = n1_inner
                      inner = []
                      for P in outer_primes:
                          g = gmpy2.gcd(P - 1, rem)
                          if 1 < g < rem:
                              inner.append(g)
                              rem //= g
                      if rem != 1 and rem != n1_inner:
                          inner.append(rem)
                      inner = sorted(set(inner))
                      return inner
                  
                  
                  # -------------------- 解密内层 RSA(用 gmpy2.invert / powmod) --------------------
                  def decrypt_inner(c: mpz, e: mpz, inner_primes, n1_inner: mpz):
                      if len(inner_primes) != 4:
                          raise ValueError(f"[!] need 4 inner primes, got {len(inner_primes)}: {inner_primes}")
                  
                      phi = mpz(1)
                      for p in inner_primes:
                          phi *= (p - 1)
                  
                      d = gmpy2.invert(e, phi)
                      if d == 0:
                          raise ValueError("[!] e is not invertible mod phi (unexpected in this challenge).")
                  
                      m = gmpy2.powmod(c, d, n1_inner)
                      pt = long_to_bytes(int(m), 256)
                      return pt
                  
                  
                  def extract_flag(pt: bytes):
                      for prefix in [b"flag{", b"FLAG{", b"ctf{", b"CTF{"]:
                          if prefix in pt:
                              i = pt.index(prefix)
                              j = pt.find(b"}", i)
                              if j != -1:
                                  return pt[i:j+1]
                      return pt
                  
                  
                  def main():
                      Bmax = 1_048_576
                      print("[*] sieving primes up to", Bmax)
                      primes_list = primes_upto(Bmax)
                      print("[*] primes count:", len(primes_list))
                  
                      print("[*] factoring outer n ...")
                      outer_primes = factor_outer(n, n1, primes_list)
                      print("[+] outer primes found:", len(outer_primes))
                      for i, P in enumerate(outer_primes, 1):
                          print(f"    P{i} bits={int(gmpy2.bit_length(P))}")
                  
                      print("[*] recovering inner primes via gcd(P-1, n1):")
                      inner_primes = recover_inner_primes(outer_primes, n1)
                      print("[+] inner primes recovered:", len(inner_primes))
                      for i, p in enumerate(inner_primes, 1):
                          print(f"    p{i} bits={int(gmpy2.bit_length(p))}")
                  
                      print("[*] decrypting inner RSA ...")
                      pt = decrypt_inner(c, e, inner_primes, n1)
                      flag = extract_flag(pt)
                      print("[+] plaintext (first 80 bytes):", pt[:80])
                      print("[+] flag:", flag)
                  
                  
                  if __name__ == "__main__":
                      main()
                  #对于我这种代码低能,掌握代码摘要以便以后使用就可以了
                  #比如 lcm(..)代码复用

                  属于常见的提示了光滑的RSA,难点是写代码

                  最大的启示是要夯实基础,落实代码,不过看到密码即使AK也只有150分还是挺难崩的,再不认真要被AI取代了(???)。。。

                • DesCTF WP

                  比赛以AK收尾,但是其中1道题非常规做出,一道题AI做的,后续非常规的题仍未解出,待WP发布后更新

                  1.CHECK IN
                  题干:可以分析得到是一道简单的近似忽略
                  from sage.all import *
                  from Crypto.Util.number import getStrongPrime, inverse
                  from hashlib import *
                  while True:
                      p = getStrongPrime(512)
                      q = getStrongPrime(512)
                      if p%4==3 and q%4==3:
                          print(p,q)
                          break
                  N = p * q
                  phi_N = (p**2 + p + 1) * (q**2 + q + 1)
                  d = Integer(N)**RR(0.47)
                  e = inverse(Integer(d), phi_N)
                  flag='flag{'+md5(str(p+q).encode()).hexdigest()+'}'
                  print(f"e = {e}")
                  print(f"N = {N}")
                  print(flag)
                  """
                  e = 20285928988408708385825788658664300305494782819689883492429762785687493161646901961627732482030570554944571523044008931416609595056746847083499405860944240804200816473153171825246196297214879750749954991916614158499347588230595409852985660426387332691700171974951765953937059128044510635005259571262430221092123685629379451869171518153057333553882827808279895371867053070597655168641441209936240962391624079704514097507822408340977683148014817264999772615710237278286803551400605422497036878844692741788304043681532328471441465596285604159664321904195632202009921776619257725630740166796422445907541165144233376010917
                  N = 162318864198120848289602513685294100213662002310524040016141267082602211702801751627271587107738223466644399363879018058536864307889254050305605097781721847474240769410050480646447538698253600786017599233831714710010395996308361674973789283465587010960323042209564459904257042660293061844258544118566558516881
                  """
                  WP:属于常见题型,不展开分析
                  #签到题,正常的近似忽略处理,左右爆破
                  #核心漏洞出现在phi的量级处理上,泄露了n量级接近
                  #还直接给出了d
                  #主要的讲解在于offset的区域讨论,量级估计
                  from hashlib import md5
                  e = 20285928988408708385825788658664300305494782819689883492429762785687493161646901961627732482030570554944571523044008931416609595056746847083499405860944240804200816473153171825246196297214879750749954991916614158499347588230595409852985660426387332691700171974951765953937059128044510635005259571262430221092123685629379451869171518153057333553882827808279895371867053070597655168641441209936240962391624079704514097507822408340977683148014817264999772615710237278286803551400605422497036878844692741788304043681532328471441465596285604159664321904195632202009921776619257725630740166796422445907541165144233376010917
                  N = 162318864198120848289602513685294100213662002310524040016141267082602211702801751627271587107738223466644399363879018058536864307889254050305605097781721847474240769410050480646447538698253600786017599233831714710010395996308361674973789283465587010960323042209564459904257042660293061844258544118566558516881
                  d = Integer(Integer(N)**RR(0.47))
                  K = e * d - 1
                  #这里的K是t*phi,可以易得phi得量级接近N**2,仔细计算下来是N**2*(1+2**(-513))
                  #可以近似处理,直接K//N**2来估算t,根据上面可以得到t在1附近,左右offset10差不多了
                  k_est = K // (N**2)
                  k = None
                  for offset in range(-10, 11):
                      if K % (k_est + offset) == 0:
                          k = k_est + offset
                          break
                  phi_N = K // k
                  #接下来是一个S^2 + (N+1)S + (N^2 - N + 1 - phi_N) = 0 得方程,一元二次公式解决
                  A = 1
                  B = N + 1
                  C = N**2 - N + 1 - phi_N
                  Discriminant = B**2 - 4*A*C
                  if Discriminant.is_square():
                      S = (-B + Discriminant.sqrt()) // (2*A)
                      flag_str = 'flag{' + md5(str(S).encode()).hexdigest() + '}'
                      print(f"[+] {flag_str}")
                  else:
                      print("[-] 求解失败:判别式不是完全平方数。")

                  典型的近似忽略

                  2.签到
                  题干:
                  天命战队通过专业技术发现线索:2月28日凌晨,伊朗革命卫队某电报群紧急发送一条消息后立即撤回。有群成员截图了撤回通知,但只看到“这条消息已被撤回”。实际上,撤回的消息仍会短暂留在本地缓存中。
                  
                  天命战队专家提取到了撤回消息的文本并翻译:“坐标25.1°N, 51.3°E,目标确认,行动代号:0100---ZRPEA===ZWHCQ===Y2K7A===ZJNCA===”
                  WP:
                  这道题没有用解码,而是用了osint的思路
                  结合题目上背景,得到伊朗,2.28,经纬度3个关键词
                  先从经纬度入手,得到美军乌代德空军基地这个地址,再发散结合日期,伊朗搜索信息
                  看到以下报告:https://www.backchina.com/news/2026/03/06/1017907.html
                  搜索伊朗相关报告,得到名称
                  真实承诺4(Operation True Promise 4)
                  4与0100相符,大概就是
                  flag{真实承诺4}

                  base32?

                  3.尽人事,听天命

                  题目上有很多的干扰信息,实则看到623.75时识别出题型MT19937,发现刚好就给了连续的623.75组数据,爆破一组,逆向temper预测

                  题干:
                  import random
                  from secret import seed,yin,yang
                  
                  signs = ['大吉', '中吉', '小吉', '吉', '末吉', '凶', '大凶']
                  colors = ['赤', '橙', '黄', '青', '蓝', '紫', '黑', '白']
                  pool = []
                  count = 2495
                  bits = 32
                  kbits = 6
                  
                  def next_omen():
                      global pool
                      if not pool:
                          x = random.getrandbits(32)
                          pool = [x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff]
                      return pool.pop(0)
                  
                  def make_book(name):
                      t = next_omen()
                      a = t % 101
                      b = (t * 3 + 7) % 101
                      c = (t * 5 + 11) % 101
                      d = (t * 7 + 13) % 101
                      color = colors[t & 7]
                      sign = signs[(t >> 1) % len(signs)]
                      return '\n'.join([
                          '【天命阁命书】',
                          f'有缘人:{name}',
                          f'命途:{a}',
                          f'福缘:{b}',
                          f'财势:{c}',
                          f'劫数:{d}',
                          f'吉色:{color}',
                          f'签文:{sign}',
                          f'天命:{t}'
                      ])
                  
                  def pull(k):
                      x = 0
                      off = 0
                      while off < k:
                          x |= random.getrandbits(32) << off
                          off += 32
                      return x & ((1 << k) - 1)
                  
                  def main():
                      random.seed(seed)
                      names = [f'有缘人{i:04d}' for i in range(count)]
                      with open('命书.txt', 'w', encoding='utf-8') as f:
                          f.write('天命阁旧录\n')
                          f.write('知天命,可窥未来。\n')
                          f.write('见未来,方知真形。\n\n')
                          for name in names:
                              f.write(make_book(name))
                              f.write('\n\n')
                          bound = yin * yang
                          trace = yin ^ (yang >> kbits)
                          seal_a = bound ^ pull(bits * 2)
                          seal_b = trace ^ pull(bits)
                          f.write('【未来残页】\n')
                          f.write(f'阴阳交积封印:{seal_a}\n')
                          f.write(f'阴阳离合封印:{seal_b}\n')
                          f.write('\n')
                          f.write('flag = DesCTF{md5(str(min(yin,yang)) + "|" + str(max(yin,yang)))}\n')
                  
                  if __name__ == '__main__':
                      main()
                  #具体的数据命书就不展开了
                  WP:
                  #先回顾一下MT19937的基础知识,再展开这道题的设计
                  #&的运算,本质是模2乘,对于b'1'流,可以复制b'1'约束下的位数
                  #|的运算,本质是有1则1,^本质是模2加,这些运算优先级都低于<<
                  #pop{0}为输出列表中的第一个,后者进位,以便输出所有
                  
                  #这道题目给了2495组输出,本质是623.75组,需要爆破0.25达到可破解MT19937,之后
                  #预测seal的输出,得到方程求解
                  #我先放脚本,再解释
                  import random
                  import re
                  from hashlib import md5
                  def untemper(y):
                      y ^= (y >> 18)
                      y ^= (y << 15) & 0xefc60000
                      temp = y
                      for _ in range(7):
                          y = temp ^ ((y << 7) & 0x9d2c5680)
                      temp = y
                      y = temp ^ (y >> 11)
                      y = temp ^ (y >> 11)
                      return y & 0xffffffff
                  #我先完整的讲一遍MT19937运算,以便理解为什么只用逆向temper
                  #seed(32)-初始化至624*32(state)-twist得到state[i]-temper-输出
                  #所以只用逆向temper,恢复到state[i]内部状态,接下来程序继续进行ex(实则是624用完进入twist),达到预测
                  #进入下一组也只用上一组的数据,不需要种子(详见twist)
                  #接下来是为什么可以这么恢复,根本原因是线性
                  #^可逆向,具有可逆性(再算一遍就可以了),>>实际展开来看,高位没有污染,低位的污染来源
                  #于高位的xor,可以恢复,视觉上最后就是反一下号就可以了
                  #然后对于<<,移除了的空了0位出来,反而可以直接得到,展开发现是000000123456和123456
                  #789,逐步恢复(这一步推荐上纸笔),循环//+1次
                  #^使得mask为1的才异或,0的变0.完全可逆
                  def get_factors(n):
                      factors = set()
                      for i in range(1, int(n**0.5) + 1):
                          if n % i == 0:
                              factors.add(i)
                              factors.add(n // i)
                      return factors
                  #这一步是找因子
                  def solve():
                      with open('命书.txt', 'r', encoding='utf-8') as f:
                          content = f.read()
                      seal_a = int(re.findall(r'阴阳交积封印:(\d+)', content)[0])#正则匹配
                      #具体语法:匹配\d表示数字,+表示至少一个,()表示提取类容
                      #findall表示返回列表,[0]第一个
                      seal_b = int(re.findall(r'阴阳离合封印:(\d+)', content)[0])
                      omens = [int(x) for x in re.findall(r'天命:(\d+)', content)]
                          outputs = []
                      for i in range(0, 2492, 4):
                          val = omens[i] | (omens[i+1] << 8) | (omens[i+2] << 16) | (omens[i+3] << 24)
                          outputs.append(val)
                  #这一步是提取数据,把随机数整合起来,切割成32的块
                      for last_byte in range(256):
                          val_624 = part_624 | (last_byte << 24)
                          current_outputs = outputs + [val_624]
                          state = [untemper(x) for x in current_outputs]#逆向temper
                          random.setstate((3, tuple(state + [624]), None))
                          #这里是状态设定,MT19937类型固定3,位置,缓存
                          r_low = random.getrandbits(32)
                          r_high = random.getrandbits(32)
                          r64 = r_low | (r_high << 32)
                  #一下是因子寻找解方程
                          for yin in get_factors(bound):
                              yang = bound // yin
                              if yin ^ (yang >> 6) == trace:
                                  print(f"\n[+] 匹配成功!")
                                  print(f"    yin: {yin}, yang: {yang}")
                                  res = sorted([yin, yang])
                                  flag_str = f"{res[0]}|{res[1]}"
                                  print(f"    Flag: DesCTF{{{md5(flag_str.encode()).hexdigest()}}}")
                                  return
                  if __name__ == "__main__":
                      solve()

                    MT19937预测破解

                    4.low bit high risk

                    一看就知的HNP问题板子

                    题干:
                    from sage.all import *
                    from hashlib import md5
                    q = 0x100000000000000000001f4c8f927aed3ca752257
                    pubx = 0x8e0a0071e8cf437efec4233ff8444a4ff8adba2f
                    puby = 0xa869fce702b70799c443b450a4d41cc4f65b3eee
                    leak = 3
                    B = 2^leak
                    data = [
                    (0x525931a9ff8ef95025939a57275ecedc2730421f,0x5288ed7146c188ebda9b6c8909726c3d6f957891,0x334c301c2d861fa8cceecabc542a5cb7dd7df7d9,0x6),
                    (0x4b21047e1112dbfee487b4f23471f2fb438e268,0x82878368ef18996109bf10adae81e1acaeb9fa25,0xd4d9ec1faa9534a3fa4ff0fe78488ebf175cdfec,0x4),
                    (0xdd2e98102508e178fdf1e289ac8342250da6408f,0x38069b3213a57a077a38938d082a7590d0a21b95,0xcff1f76af8f15422bb288c8af372332cc6ace970,0x1),
                    (0xecb8547ea2a68788665e01a7025093c47f2b45de,0x6f7155ce9da5434227e48554a0bef7d7492cadb,0x53f6e1a52554436620b392dea75738b5f670d2b2,0x2),
                    (0xefb887600edf8d279f3cca868ef641e9284ae769,0x9caea57dd4681d1ab53029cf631a47277386bc72,0xce7743df557c732daff4595d8430ea8485ab3aca,0x3),
                    (0x957ec8b7a53dea95d53a5c94d595b834c2be61ca,0x1b24031194de7dac370a2f7c9be316dc14cbe3f2,0xc40b5c4c674d1f4cb99891bf342f8acebca9258b,0x5),
                    (0x8ba1946c16b7c8d98c6e01836ae0d791ecae07d9,0x6daec7923c03c56a18d764d9497c39871912fb1a,0x717b2cf60cc5416eb3f1666e79f30d538f5c9038,0x5),
                    (0x72337b25f3486e8518d8f3a4da21724cf3977246,0xff88c0ddcdcdfb98ca50b68c035434ee2e81cd1d,0x748e1c374d1efdcb3b9bd7b3c812213ddc1ab940,0x4),
                    (0xa71275186b7bbc9747c5831b1e4c75f1bd3eae7a,0x43b995ded8fddfa6365a51d547456376c8f79b88,0x6c9a0e390dc7d40900f412313dfe0deb8a5cbb45,0x6),
                    (0x926bff0ea87d5c1e8c9da39ceb01a10d1b3c0709,0xaeb5012cbaf479dd3c2d297ba3a80d344ab22f57,0xa3eff29dffaed0371d860e291c8f65eb287918ce,0x3),
                    (0xdc9e51d365f8a827988cf70c4913d987343dc74a,0xa6940f2d3f38d0d4b20c36b24f4f91b5bdee59c1,0xb3a7373eeaf10e449aca7e3cc00f6f554ff0473f,0x4),
                    (0x2bcbef8732ab1e591dff595cb1c979f90ebadf0c,0x3b629a50ab44f67f762dff710653c1fa995863c1,0x7425a16af106e5eba3a0f751baba95708ead3c0,0x1),
                    (0x6a0eadeed0b9e7e900df27d5e253968c30f0f6bd,0x47e22a97f4dfee66b8b04983bbfbfe0374fa917d,0xfadb3f2a5b347b9fa8cfdaeddecb1215f19ec707,0x7),
                    (0x884675226091712e22a0fbf1fa3c0de95fa09dae,0x6549eabd7fd5bc6832e2ab061fb02d0f1df6b19a,0xb660a3baf9d96985c3b8d420259003b8fc0a4410,0x2),
                    (0x2a81e382054ed9523f5e4d2a966252b51046325d,0x81f663abbd508d6df460a1d5a857829834a969ac,0xe51bcf400dd3fddb5b9f13fd0403b3af011f9fc6,0x4),
                    (0x25f6147e13fc52aaf92b1622134c52dff9ec282d,0x76e457adf428f8a1a82711584e336c0b3b70e94e,0x6af1ced8354c4bdf84fc55fef847848d4dad83e6,0x3),
                    (0xfe0eba650a95051d8fa04f43824d465fdad34493,0xadd5339288e5527a394a602a2f4e891dbdf8d7aa,0x169a5d1b893fa66e35ec2620bc96f73d067c9460,0x3),
                    (0xb8914a5d41cdd7ff1f0eed7e6eab2e79fabfde5b,0xf6673ed83fe9731508921bfc12773a19980e5345,0x83710a069298113cfc91d716a38e1584b2606033,0x5),
                    (0xae25b8812cc4f7fec5a14f4174328be0a254cc26,0x16381c71aa45674488d8b1a10ff0a16d4fd6c997,0xa947337c2f9d0efe9e69f3a5332c7d0887937643,0x0),
                    (0xd8bc55b669d86fe42448a83063aea36251b5fe75,0x8050afa80843f0162c7fa5323cf19f4f194f90ec,0x9207917cde2804eb97708cb3392610f716e8c5c,0x4),
                    (0xabf778fe7279f34fe6f883d56b938ec46bafb21,0xf1e96791da0ebc0981eb60fae9509f3c973d5df7,0xf3f07a604cde6a2164601357cfde0c4b2200fb44,0x5),
                    (0x8bbc50d04d2841668fc639c0a0f5ae2cd9f13e03,0xfa4107e471bd396a25b3853ec09a56c49343cfa3,0xaf2d6a8142fcf028ce8aabc31377c6d7c63bc9c3,0x7),
                    (0xd3db7034072a88a03f7a632fdc3f5a07846c79c3,0x463871a92ceba68a12ab4d02759ff1aec24c9355,0xc61b3931ecf8330d4b26b9175efa8690161d25b4,0x4),
                    (0x5d5672957260b5794e305ee24bccc07f8dd34d94,0x7c27bdada7014240c904d42c5a1a1e5f38ea9826,0x779a7fcc0582e3d901494a98b8d9aa1b8d5f5840,0x7),
                    (0x1d197eefd0a6c59ea8f3cfc69c066ce92d7f6e96,0x665a2ba8a286880c09e2c9ea9adb7479d5bc123d,0x6377c18c0cf75070627ef9613af864be815eeed6,0x4),
                    (0x9c7975f4b345048f7e2d3614d5fdcf162be0d920,0xf2142d01b4b7c2a5585c8458366c716729ee3329,0x1dd8903dafda53bfe000f606bceee5b31816f683,0x7),
                    (0x5062cb7d6e3b50df1820f5996962b5b8b1fc4617,0xaa47856eecf23e8ef0f212ed3a978f4d5564d650,0xa02ffbb157a74b3f105895cbe487c6e1da411070,0x0),
                    (0xcdfcb6ff93ca01a2755c0c8f0ad8ee04118e1b9e,0x1fdc78b5968fbd65351406a0e7cb6f45d9f26a01,0xcec3c44ec773a31fd3785a998e3526624a504705,0x3),
                    (0x65fc356da2a36d35d88c5c5792661d8fe152821c,0x20a49731ddf37504876ed4303cf8ee52426abbbe,0xf974613f265ced476f0ad2548eecffcf4b648a9e,0x7),
                    (0x59544b829fa1f696558ea62792b85e114e397433,0x23645dd35469fd873a73db34f1018f08ae7f2c24,0xe5a23255d9760df1f8d6c8ce1652e0480beb0b7d,0x2),
                    (0x8ef11fdbed1a2f64faca70aea2cac44dadd8c14c,0x640d24c485e9e04b9af2355c07cf7ad430c7ca58,0x20f0e050124bd754c13b8c2e86dbebaee2132bec,0x1),
                    (0x1b5ac91240f6450de7fc5208f0762501790e28b7,0x7991d2db2512b6463c201f0523ed863ce2a670e8,0xebf64515f997f18b726cd11a24276ef26505a409,0x6),
                    (0xba35a8c66a894fae013ac56c9d6ba538d8cbcf0b,0xcea24619e5bdd3418da925e3aebd5a3c6f64ef03,0xb9216f67fe0aa26e374b92ecf4b0c8545522785e,0x0),
                    (0xe4e86fdd765bc4d98bc807e3f56ad2f2ef8dbd15,0x67a9d34b95c25764e1026fd64a0cdadc4f894ef,0x57f0a006eb1ddbae5b7aaaa3e5a2740c1401c9e2,0x6),
                    (0xe582d66c85dda020da90ce0248057e9dff2a0120,0x8f261523dad715ddc7c992972d8cdab39a0e8920,0x2bcd65226ab00e4e1117a90b735ea287a921641a,0x2),
                    (0x62ac7d9437e54969456ae056289adeaefaccd6bb,0xe7a23830bdccf8e24a6aa1d84d94cff498f3958a,0x13d192adc3f46a9a2b624a3a93e6faf243e2120f,0x7),
                    (0xd24bfd231c4e6b4b3fe46ec642392e59bf1b7358,0x51b756a681426525f7194a66375a35185d529813,0x57a86c9d1fe7fe8ad9b05ea21239cd42bce93ca6,0x2),
                    (0xeb0501d2e40edeb6ecad416cfb5d12459de1f32a,0xc5a4cacf614bc7519130e6727126823d77b51c85,0xd86708d496f4e4265526247c79931bbc0351237c,0x0),
                    (0xb41393d8fe5adbe01ec1ae88aacf8030f990c260,0xb6997c03f903bc1add14cb98e8741647a60c62ad,0x2fa481db8208ccfa161e791631d91cc012bff387,0x5),
                    (0x851a5f6a1ff9ad28e22858aded0abe1d927f8f47,0xa35a9a8b26bcbf0a639efd5583c9830aa2834a61,0x71ed5887fc9b53af96793aa25285227e679923d0,0x6),
                    (0x36d5d74fdbb34184f56989136c19526a1e66f284,0xe2636b99dd8277a5bdf411a2ab44688704682b8b,0x8fa686e14e0c8c40f507b8e4cc8abf2d8391e13e,0x3),
                    (0x136e1685ce0dd8fa72c17db7f71ad3ec08201b0f,0xf8715b24f37af56cd40108e12d4cd65dfe47b18a,0x447eb0b48cd17036c130d2c9814df4452645562e,0x3),
                    (0x442cd9850919eef698ad67aad25dac1e609042cc,0x8879c395e3021c4c8e1d4cf3ed7556ddcfe88c98,0xaf3310936f1bf6f93698081b581b362aa4432c2f,0x0),
                    (0xe788598a42acba0d0b7b1f6ec9b230b44a477aad,0xad119581e7a04cf0b3b1f5197bc27d9684813b36,0x774ad198691047f7a63714bc633ebf66aa7d2e9d,0x0),
                    (0x96db72fa75d1f4ef567ae6b0a6a9b67b6eb925,0xb2a2d5c2c26fdf25b4ccc5981beff2fbce544bf1,0x259ef89bfdf867a25f2a45ba31e3b8f01d15ac98,0x6),
                    (0xfe84f3657569c6b2f6a820fe72ae29980bb3d3b6,0x81f40f3434d8a526ae3bdd9229e3b91436c195f2,0xd9ad8ce4bae25a93282b2d585a3ccc9f76c3cfd2,0x0),
                    (0xbd38a3ba51b95b74301f1a375039aadf45cf9500,0x981371c31ca751800cd9554d120390faa176f90,0xc687f4008be79d2f747d0d3d373d2908dc99f863,0x0),
                    (0x5cf2a3d05d937cb49929f7a5420c77a510f9b9db,0x43b40c9c33d53a2c03193c499ef7f99c19d36ed2,0x6efe5e9f33a99b6d6e2b072c52923bbbc6050ee0,0x4),
                    (0xb3096421f5e4056f23b5bab000b764a049bff24d,0x8f826e2bce70b6aa6ec454bc8e9e8cd851ebb165,0xbb9e3082a3a1bd77fd66bb03772219a944f03e29,0x7),
                    (0x3dd4cead2e79dcf86cc7917a579a2dba900bb099,0x7f75439b0103ed40729a24e7f9846b7c2ca3558,0x2ebb76dc34c83a60571f14cdf6f8261988a902bd,0x7),
                    (0x3180aeb53046ca485f501895ed61e57e8ed27b7,0x7efbf45c158b115885fb00e2ac5b5df85eef468a,0x7c97ef4e278686bce1a424a92471b21fcf3658b6,0x3),
                    (0x559fa993834a40f6fd31f8a3a2f83da980b2ef84,0x8785d04f6d97d688f90af33140889e4c7201382a,0x779f8d284898ca25426208f3a6c3b9455c70eb0d,0x7),
                    (0x49a0f529e86a638d1cb71dbd948357d390646128,0xc5c72505c3807890a11502cfc0286fdf40c924bd,0xdc242283b58e5d98803c067a4633590e5d1e5d9e,0x1),
                    (0xef75ace89af3a7791034ae6161e608384984eb34,0x61a4d32ca6bdf4f8559cf15bc9be41721575650,0x8fd9e8a6cdd86a2d960409b124453245b1c92f09,0x5),
                    (0xcf0cf859a451378f576de4e10b918fa70b0d0e02,0x66a7f51a86fe0cd0db57d2025464c1d95384c6c0,0xcc4673380c3a3cc4545e5644ebaad0ee2205af36,0x5),
                    (0xa973fdecf97847abfadc76a530cfaa51a544992f,0x64ebd081e1e5be70904723e1a786d9581ad4e5a5,0x58c16e616268863fce12b920e281ad4b1d9d2881,0x1),
                    (0x9bbcfa5f87bea52e4df986ecdb89dadf9fe7242b,0x520b4e89d3e3cd032e5c8c9cfab3f706fe49ca8c,0x198aa5c2cab8d22845c4f3ea8f710becaba98d13,0x3),
                    (0x42abe9b2d14ec440b51362694f93116cf4a8980d,0x38c3965c6f9c9699476239ea669acc598bf748b6,0xb47208202e92dbc5ed3d4319dd9e4ceeb21e9ec8,0x5),
                    (0x334732df257a5c08e42c56dcd31f3be5cfaa196e,0xe6387cab10b4e3bff5c72b7a8c47bf3f73812e0c,0x315e28210455bc5535e6f2a6dcf5a76732ad8c88,0x3),
                    (0x825347e82b6ecb7c40353d9282daf9804088f22b,0xced5ac7b578c4a95a177a283f60437a70232ff0,0xb647c743e3b4ce3ca95c586bdd14afc41d91ad09,0x4),
                    (0xf862df8e80ded401998ce913668155e078f5863f,0xa73fe4db4136c28cbfc6ee73c800548a0bd463e2,0xff0395bc6b17d90c38ba263488be5987e3b44890,0x7)
                    ]
                    n=len(data)
                    A=[]
                    C=[]
                    for h,r,s,b in data:
                        s_inv=inverse_mod(s,q)
                        A.append((r*s_inv)%q)
                        C.append(((h-b*s)*s_inv)%q)
                    M=Matrix(ZZ,n+1,n+1)
                    for i in range(n):
                        M[i,i]=q
                    for i in range(n):
                        M[n,i]=A[i]
                    M[n,n]=B
                    target=vector(C+[0])
                    M=M.stack(target)
                    print("[*] running LLL")
                    L=M.LLL()
                    for row in L:
                        d=int(row[-1])%q
                        if d==0:
                            continue
                        from ecdsa import SigningKey,SECP160r1
                        try:
                            sk=SigningKey.from_secret_exponent(d,curve=SECP160r1)
                            vk=sk.verifying_key
                    
                            if vk.pubkey.point.x()==pubx and vk.pubkey.point.y()==puby:
                                print("d =",d)
                               flag="DesCTF{"+md5(str(d).encode()).hexdigest()+"}"
                                print("FLAG =",flag)
                                break
                        except:
                            pass
                    WP:
                    #先回顾一下ECDSA的基础知识,sk是私钥对象G,vk是公钥对象Q,d是私钥(G*d=Q),h是
                    #hash处理后的信息,随机数k,x%q=r,invert(k,q)*(h+r*d)%q=s是签名对
                    #这里看到泄露多组数据(达到信息论要求),并且泄露可以用a*x+b表示,识别HNP
                    from sage.all import *
                    from hashlib import md5
                    q = 0x100000000000000000001f4c8f927aed3ca752257
                    pubx = 0x8e0a0071e8cf437efec4233ff8444a4ff8adba2f
                    puby = 0xa869fce702b70799c443b450a4d41cc4f65b3eee
                    leak = 3
                    B = 2^leak
                    data = [
                    (0x525931a9ff8ef95025939a57275ecedc2730421f,0x5288ed7146c188ebda9b6c8909726c3d6f957891,0x334c301c2d861fa8cceecabc542a5cb7dd7df7d9,0x6),
                    (0x4b21047e1112dbfee487b4f23471f2fb438e268,0x82878368ef18996109bf10adae81e1acaeb9fa25,0xd4d9ec1faa9534a3fa4ff0fe78488ebf175cdfec,0x4),
                    (0xdd2e98102508e178fdf1e289ac8342250da6408f,0x38069b3213a57a077a38938d082a7590d0a21b95,0xcff1f76af8f15422bb288c8af372332cc6ace970,0x1),
                    (0xecb8547ea2a68788665e01a7025093c47f2b45de,0x6f7155ce9da5434227e48554a0bef7d7492cadb,0x53f6e1a52554436620b392dea75738b5f670d2b2,0x2),
                    (0xefb887600edf8d279f3cca868ef641e9284ae769,0x9caea57dd4681d1ab53029cf631a47277386bc72,0xce7743df557c732daff4595d8430ea8485ab3aca,0x3),
                    (0x957ec8b7a53dea95d53a5c94d595b834c2be61ca,0x1b24031194de7dac370a2f7c9be316dc14cbe3f2,0xc40b5c4c674d1f4cb99891bf342f8acebca9258b,0x5),
                    (0x8ba1946c16b7c8d98c6e01836ae0d791ecae07d9,0x6daec7923c03c56a18d764d9497c39871912fb1a,0x717b2cf60cc5416eb3f1666e79f30d538f5c9038,0x5),
                    (0x72337b25f3486e8518d8f3a4da21724cf3977246,0xff88c0ddcdcdfb98ca50b68c035434ee2e81cd1d,0x748e1c374d1efdcb3b9bd7b3c812213ddc1ab940,0x4),
                    (0xa71275186b7bbc9747c5831b1e4c75f1bd3eae7a,0x43b995ded8fddfa6365a51d547456376c8f79b88,0x6c9a0e390dc7d40900f412313dfe0deb8a5cbb45,0x6),
                    (0x926bff0ea87d5c1e8c9da39ceb01a10d1b3c0709,0xaeb5012cbaf479dd3c2d297ba3a80d344ab22f57,0xa3eff29dffaed0371d860e291c8f65eb287918ce,0x3),
                    (0xdc9e51d365f8a827988cf70c4913d987343dc74a,0xa6940f2d3f38d0d4b20c36b24f4f91b5bdee59c1,0xb3a7373eeaf10e449aca7e3cc00f6f554ff0473f,0x4),
                    (0x2bcbef8732ab1e591dff595cb1c979f90ebadf0c,0x3b629a50ab44f67f762dff710653c1fa995863c1,0x7425a16af106e5eba3a0f751baba95708ead3c0,0x1),
                    (0x6a0eadeed0b9e7e900df27d5e253968c30f0f6bd,0x47e22a97f4dfee66b8b04983bbfbfe0374fa917d,0xfadb3f2a5b347b9fa8cfdaeddecb1215f19ec707,0x7),
                    (0x884675226091712e22a0fbf1fa3c0de95fa09dae,0x6549eabd7fd5bc6832e2ab061fb02d0f1df6b19a,0xb660a3baf9d96985c3b8d420259003b8fc0a4410,0x2),
                    (0x2a81e382054ed9523f5e4d2a966252b51046325d,0x81f663abbd508d6df460a1d5a857829834a969ac,0xe51bcf400dd3fddb5b9f13fd0403b3af011f9fc6,0x4),
                    (0x25f6147e13fc52aaf92b1622134c52dff9ec282d,0x76e457adf428f8a1a82711584e336c0b3b70e94e,0x6af1ced8354c4bdf84fc55fef847848d4dad83e6,0x3),
                    (0xfe0eba650a95051d8fa04f43824d465fdad34493,0xadd5339288e5527a394a602a2f4e891dbdf8d7aa,0x169a5d1b893fa66e35ec2620bc96f73d067c9460,0x3),
                    (0xb8914a5d41cdd7ff1f0eed7e6eab2e79fabfde5b,0xf6673ed83fe9731508921bfc12773a19980e5345,0x83710a069298113cfc91d716a38e1584b2606033,0x5),
                    (0xae25b8812cc4f7fec5a14f4174328be0a254cc26,0x16381c71aa45674488d8b1a10ff0a16d4fd6c997,0xa947337c2f9d0efe9e69f3a5332c7d0887937643,0x0),
                    (0xd8bc55b669d86fe42448a83063aea36251b5fe75,0x8050afa80843f0162c7fa5323cf19f4f194f90ec,0x9207917cde2804eb97708cb3392610f716e8c5c,0x4),
                    (0xabf778fe7279f34fe6f883d56b938ec46bafb21,0xf1e96791da0ebc0981eb60fae9509f3c973d5df7,0xf3f07a604cde6a2164601357cfde0c4b2200fb44,0x5),
                    (0x8bbc50d04d2841668fc639c0a0f5ae2cd9f13e03,0xfa4107e471bd396a25b3853ec09a56c49343cfa3,0xaf2d6a8142fcf028ce8aabc31377c6d7c63bc9c3,0x7),
                    (0xd3db7034072a88a03f7a632fdc3f5a07846c79c3,0x463871a92ceba68a12ab4d02759ff1aec24c9355,0xc61b3931ecf8330d4b26b9175efa8690161d25b4,0x4),
                    (0x5d5672957260b5794e305ee24bccc07f8dd34d94,0x7c27bdada7014240c904d42c5a1a1e5f38ea9826,0x779a7fcc0582e3d901494a98b8d9aa1b8d5f5840,0x7),
                    (0x1d197eefd0a6c59ea8f3cfc69c066ce92d7f6e96,0x665a2ba8a286880c09e2c9ea9adb7479d5bc123d,0x6377c18c0cf75070627ef9613af864be815eeed6,0x4),
                    (0x9c7975f4b345048f7e2d3614d5fdcf162be0d920,0xf2142d01b4b7c2a5585c8458366c716729ee3329,0x1dd8903dafda53bfe000f606bceee5b31816f683,0x7),
                    (0x5062cb7d6e3b50df1820f5996962b5b8b1fc4617,0xaa47856eecf23e8ef0f212ed3a978f4d5564d650,0xa02ffbb157a74b3f105895cbe487c6e1da411070,0x0),
                    (0xcdfcb6ff93ca01a2755c0c8f0ad8ee04118e1b9e,0x1fdc78b5968fbd65351406a0e7cb6f45d9f26a01,0xcec3c44ec773a31fd3785a998e3526624a504705,0x3),
                    (0x65fc356da2a36d35d88c5c5792661d8fe152821c,0x20a49731ddf37504876ed4303cf8ee52426abbbe,0xf974613f265ced476f0ad2548eecffcf4b648a9e,0x7),
                    (0x59544b829fa1f696558ea62792b85e114e397433,0x23645dd35469fd873a73db34f1018f08ae7f2c24,0xe5a23255d9760df1f8d6c8ce1652e0480beb0b7d,0x2),
                    (0x8ef11fdbed1a2f64faca70aea2cac44dadd8c14c,0x640d24c485e9e04b9af2355c07cf7ad430c7ca58,0x20f0e050124bd754c13b8c2e86dbebaee2132bec,0x1),
                    (0x1b5ac91240f6450de7fc5208f0762501790e28b7,0x7991d2db2512b6463c201f0523ed863ce2a670e8,0xebf64515f997f18b726cd11a24276ef26505a409,0x6),
                    (0xba35a8c66a894fae013ac56c9d6ba538d8cbcf0b,0xcea24619e5bdd3418da925e3aebd5a3c6f64ef03,0xb9216f67fe0aa26e374b92ecf4b0c8545522785e,0x0),
                    (0xe4e86fdd765bc4d98bc807e3f56ad2f2ef8dbd15,0x67a9d34b95c25764e1026fd64a0cdadc4f894ef,0x57f0a006eb1ddbae5b7aaaa3e5a2740c1401c9e2,0x6),
                    (0xe582d66c85dda020da90ce0248057e9dff2a0120,0x8f261523dad715ddc7c992972d8cdab39a0e8920,0x2bcd65226ab00e4e1117a90b735ea287a921641a,0x2),
                    (0x62ac7d9437e54969456ae056289adeaefaccd6bb,0xe7a23830bdccf8e24a6aa1d84d94cff498f3958a,0x13d192adc3f46a9a2b624a3a93e6faf243e2120f,0x7),
                    (0xd24bfd231c4e6b4b3fe46ec642392e59bf1b7358,0x51b756a681426525f7194a66375a35185d529813,0x57a86c9d1fe7fe8ad9b05ea21239cd42bce93ca6,0x2),
                    (0xeb0501d2e40edeb6ecad416cfb5d12459de1f32a,0xc5a4cacf614bc7519130e6727126823d77b51c85,0xd86708d496f4e4265526247c79931bbc0351237c,0x0),
                    (0xb41393d8fe5adbe01ec1ae88aacf8030f990c260,0xb6997c03f903bc1add14cb98e8741647a60c62ad,0x2fa481db8208ccfa161e791631d91cc012bff387,0x5),
                    (0x851a5f6a1ff9ad28e22858aded0abe1d927f8f47,0xa35a9a8b26bcbf0a639efd5583c9830aa2834a61,0x71ed5887fc9b53af96793aa25285227e679923d0,0x6),
                    (0x36d5d74fdbb34184f56989136c19526a1e66f284,0xe2636b99dd8277a5bdf411a2ab44688704682b8b,0x8fa686e14e0c8c40f507b8e4cc8abf2d8391e13e,0x3),
                    (0x136e1685ce0dd8fa72c17db7f71ad3ec08201b0f,0xf8715b24f37af56cd40108e12d4cd65dfe47b18a,0x447eb0b48cd17036c130d2c9814df4452645562e,0x3),
                    (0x442cd9850919eef698ad67aad25dac1e609042cc,0x8879c395e3021c4c8e1d4cf3ed7556ddcfe88c98,0xaf3310936f1bf6f93698081b581b362aa4432c2f,0x0),
                    (0xe788598a42acba0d0b7b1f6ec9b230b44a477aad,0xad119581e7a04cf0b3b1f5197bc27d9684813b36,0x774ad198691047f7a63714bc633ebf66aa7d2e9d,0x0),
                    (0x96db72fa75d1f4ef567ae6b0a6a9b67b6eb925,0xb2a2d5c2c26fdf25b4ccc5981beff2fbce544bf1,0x259ef89bfdf867a25f2a45ba31e3b8f01d15ac98,0x6),
                    (0xfe84f3657569c6b2f6a820fe72ae29980bb3d3b6,0x81f40f3434d8a526ae3bdd9229e3b91436c195f2,0xd9ad8ce4bae25a93282b2d585a3ccc9f76c3cfd2,0x0),
                    (0xbd38a3ba51b95b74301f1a375039aadf45cf9500,0x981371c31ca751800cd9554d120390faa176f90,0xc687f4008be79d2f747d0d3d373d2908dc99f863,0x0),
                    (0x5cf2a3d05d937cb49929f7a5420c77a510f9b9db,0x43b40c9c33d53a2c03193c499ef7f99c19d36ed2,0x6efe5e9f33a99b6d6e2b072c52923bbbc6050ee0,0x4),
                    (0xb3096421f5e4056f23b5bab000b764a049bff24d,0x8f826e2bce70b6aa6ec454bc8e9e8cd851ebb165,0xbb9e3082a3a1bd77fd66bb03772219a944f03e29,0x7),
                    (0x3dd4cead2e79dcf86cc7917a579a2dba900bb099,0x7f75439b0103ed40729a24e7f9846b7c2ca3558,0x2ebb76dc34c83a60571f14cdf6f8261988a902bd,0x7),
                    (0x3180aeb53046ca485f501895ed61e57e8ed27b7,0x7efbf45c158b115885fb00e2ac5b5df85eef468a,0x7c97ef4e278686bce1a424a92471b21fcf3658b6,0x3),
                    (0x559fa993834a40f6fd31f8a3a2f83da980b2ef84,0x8785d04f6d97d688f90af33140889e4c7201382a,0x779f8d284898ca25426208f3a6c3b9455c70eb0d,0x7),
                    (0x49a0f529e86a638d1cb71dbd948357d390646128,0xc5c72505c3807890a11502cfc0286fdf40c924bd,0xdc242283b58e5d98803c067a4633590e5d1e5d9e,0x1),
                    (0xef75ace89af3a7791034ae6161e608384984eb34,0x61a4d32ca6bdf4f8559cf15bc9be41721575650,0x8fd9e8a6cdd86a2d960409b124453245b1c92f09,0x5),
                    (0xcf0cf859a451378f576de4e10b918fa70b0d0e02,0x66a7f51a86fe0cd0db57d2025464c1d95384c6c0,0xcc4673380c3a3cc4545e5644ebaad0ee2205af36,0x5),
                    (0xa973fdecf97847abfadc76a530cfaa51a544992f,0x64ebd081e1e5be70904723e1a786d9581ad4e5a5,0x58c16e616268863fce12b920e281ad4b1d9d2881,0x1),
                    (0x9bbcfa5f87bea52e4df986ecdb89dadf9fe7242b,0x520b4e89d3e3cd032e5c8c9cfab3f706fe49ca8c,0x198aa5c2cab8d22845c4f3ea8f710becaba98d13,0x3),
                    (0x42abe9b2d14ec440b51362694f93116cf4a8980d,0x38c3965c6f9c9699476239ea669acc598bf748b6,0xb47208202e92dbc5ed3d4319dd9e4ceeb21e9ec8,0x5),
                    (0x334732df257a5c08e42c56dcd31f3be5cfaa196e,0xe6387cab10b4e3bff5c72b7a8c47bf3f73812e0c,0x315e28210455bc5535e6f2a6dcf5a76732ad8c88,0x3),
                    (0x825347e82b6ecb7c40353d9282daf9804088f22b,0xced5ac7b578c4a95a177a283f60437a70232ff0,0xb647c743e3b4ce3ca95c586bdd14afc41d91ad09,0x4),
                    (0xf862df8e80ded401998ce913668155e078f5863f,0xa73fe4db4136c28cbfc6ee73c800548a0bd463e2,0xff0395bc6b17d90c38ba263488be5987e3b44890,0x7)
                    ]
                    n=len(data)
                    A=[]
                    C=[]
                    for h,r,s,b in data:
                        s_inv=inverse_mod(s,q)
                        A.append((r*s_inv)%q)
                        C.append(((h-b*s)*s_inv)%q)#HNP化简
                    M=Matrix(ZZ,n+1,n+1)
                    for i in range(n):
                        M[i,i]=q
                    for i in range(n):
                        M[n,i]=A[i]
                    M[n,n]=B
                    target=vector(C+[0])
                    M=M.stack(target)#这里表示把这行加到底下
                    print("[*] running LLL")
                    L=M.LLL()
                    for row in L:
                        d=int(row[-1])%q
                        if d==0:
                            continue
                        from ecdsa import SigningKey,SECP160r1
                        try:
                            sk=SigningKey.from_secret_exponent(d,curve=SECP160r1)
                            vk=sk.verifying_key
                    #这里是检查,用G&自己算出来的d的x,y是否符合题上提供的x,y
                            if vk.pubkey.point.x()==pubx and vk.pubkey.point.y()==puby:
                                print("d =",d)
                               flag="DesCTF{"+md5(str(d).encode()).hexdigest()+"}"
                                print("FLAG =",flag)
                                break
                        except:
                            pass
                    WP:
                    #先回顾一下ECDSA的基础知识,sk是私钥对象G,vk是公钥对象Q,d是私钥(G*d=Q),h是
                    #hash处理后的信息,随机数k,x%q=r,invert(k,q)*(h+r*d)%q=s是签名对
                    #这里看到泄露多组数据(达到信息论要求),并且泄露可以用a*x+b表示,识别HNP
                    from sage.all import *
                    from hashlib import md5
                    q = 0x100000000000000000001f4c8f927aed3ca752257
                    pubx = 0x8e0a0071e8cf437efec4233ff8444a4ff8adba2f
                    puby = 0xa869fce702b70799c443b450a4d41cc4f65b3eee
                    leak = 3
                    B = 2^leak
                    data = [
                    (0x525931a9ff8ef95025939a57275ecedc2730421f,0x5288ed7146c188ebda9b6c8909726c3d6f957891,0x334c301c2d861fa8cceecabc542a5cb7dd7df7d9,0x6),
                    (0x4b21047e1112dbfee487b4f23471f2fb438e268,0x82878368ef18996109bf10adae81e1acaeb9fa25,0xd4d9ec1faa9534a3fa4ff0fe78488ebf175cdfec,0x4),
                    (0xdd2e98102508e178fdf1e289ac8342250da6408f,0x38069b3213a57a077a38938d082a7590d0a21b95,0xcff1f76af8f15422bb288c8af372332cc6ace970,0x1),
                    (0xecb8547ea2a68788665e01a7025093c47f2b45de,0x6f7155ce9da5434227e48554a0bef7d7492cadb,0x53f6e1a52554436620b392dea75738b5f670d2b2,0x2),
                    (0xefb887600edf8d279f3cca868ef641e9284ae769,0x9caea57dd4681d1ab53029cf631a47277386bc72,0xce7743df557c732daff4595d8430ea8485ab3aca,0x3),
                    (0x957ec8b7a53dea95d53a5c94d595b834c2be61ca,0x1b24031194de7dac370a2f7c9be316dc14cbe3f2,0xc40b5c4c674d1f4cb99891bf342f8acebca9258b,0x5),
                    (0x8ba1946c16b7c8d98c6e01836ae0d791ecae07d9,0x6daec7923c03c56a18d764d9497c39871912fb1a,0x717b2cf60cc5416eb3f1666e79f30d538f5c9038,0x5),
                    (0x72337b25f3486e8518d8f3a4da21724cf3977246,0xff88c0ddcdcdfb98ca50b68c035434ee2e81cd1d,0x748e1c374d1efdcb3b9bd7b3c812213ddc1ab940,0x4),
                    (0xa71275186b7bbc9747c5831b1e4c75f1bd3eae7a,0x43b995ded8fddfa6365a51d547456376c8f79b88,0x6c9a0e390dc7d40900f412313dfe0deb8a5cbb45,0x6),
                    (0x926bff0ea87d5c1e8c9da39ceb01a10d1b3c0709,0xaeb5012cbaf479dd3c2d297ba3a80d344ab22f57,0xa3eff29dffaed0371d860e291c8f65eb287918ce,0x3),
                    (0xdc9e51d365f8a827988cf70c4913d987343dc74a,0xa6940f2d3f38d0d4b20c36b24f4f91b5bdee59c1,0xb3a7373eeaf10e449aca7e3cc00f6f554ff0473f,0x4),
                    (0x2bcbef8732ab1e591dff595cb1c979f90ebadf0c,0x3b629a50ab44f67f762dff710653c1fa995863c1,0x7425a16af106e5eba3a0f751baba95708ead3c0,0x1),
                    (0x6a0eadeed0b9e7e900df27d5e253968c30f0f6bd,0x47e22a97f4dfee66b8b04983bbfbfe0374fa917d,0xfadb3f2a5b347b9fa8cfdaeddecb1215f19ec707,0x7),
                    (0x884675226091712e22a0fbf1fa3c0de95fa09dae,0x6549eabd7fd5bc6832e2ab061fb02d0f1df6b19a,0xb660a3baf9d96985c3b8d420259003b8fc0a4410,0x2),
                    (0x2a81e382054ed9523f5e4d2a966252b51046325d,0x81f663abbd508d6df460a1d5a857829834a969ac,0xe51bcf400dd3fddb5b9f13fd0403b3af011f9fc6,0x4),
                    (0x25f6147e13fc52aaf92b1622134c52dff9ec282d,0x76e457adf428f8a1a82711584e336c0b3b70e94e,0x6af1ced8354c4bdf84fc55fef847848d4dad83e6,0x3),
                    (0xfe0eba650a95051d8fa04f43824d465fdad34493,0xadd5339288e5527a394a602a2f4e891dbdf8d7aa,0x169a5d1b893fa66e35ec2620bc96f73d067c9460,0x3),
                    (0xb8914a5d41cdd7ff1f0eed7e6eab2e79fabfde5b,0xf6673ed83fe9731508921bfc12773a19980e5345,0x83710a069298113cfc91d716a38e1584b2606033,0x5),
                    (0xae25b8812cc4f7fec5a14f4174328be0a254cc26,0x16381c71aa45674488d8b1a10ff0a16d4fd6c997,0xa947337c2f9d0efe9e69f3a5332c7d0887937643,0x0),
                    (0xd8bc55b669d86fe42448a83063aea36251b5fe75,0x8050afa80843f0162c7fa5323cf19f4f194f90ec,0x9207917cde2804eb97708cb3392610f716e8c5c,0x4),
                    (0xabf778fe7279f34fe6f883d56b938ec46bafb21,0xf1e96791da0ebc0981eb60fae9509f3c973d5df7,0xf3f07a604cde6a2164601357cfde0c4b2200fb44,0x5),
                    (0x8bbc50d04d2841668fc639c0a0f5ae2cd9f13e03,0xfa4107e471bd396a25b3853ec09a56c49343cfa3,0xaf2d6a8142fcf028ce8aabc31377c6d7c63bc9c3,0x7),
                    (0xd3db7034072a88a03f7a632fdc3f5a07846c79c3,0x463871a92ceba68a12ab4d02759ff1aec24c9355,0xc61b3931ecf8330d4b26b9175efa8690161d25b4,0x4),
                    (0x5d5672957260b5794e305ee24bccc07f8dd34d94,0x7c27bdada7014240c904d42c5a1a1e5f38ea9826,0x779a7fcc0582e3d901494a98b8d9aa1b8d5f5840,0x7),
                    (0x1d197eefd0a6c59ea8f3cfc69c066ce92d7f6e96,0x665a2ba8a286880c09e2c9ea9adb7479d5bc123d,0x6377c18c0cf75070627ef9613af864be815eeed6,0x4),
                    (0x9c7975f4b345048f7e2d3614d5fdcf162be0d920,0xf2142d01b4b7c2a5585c8458366c716729ee3329,0x1dd8903dafda53bfe000f606bceee5b31816f683,0x7),
                    (0x5062cb7d6e3b50df1820f5996962b5b8b1fc4617,0xaa47856eecf23e8ef0f212ed3a978f4d5564d650,0xa02ffbb157a74b3f105895cbe487c6e1da411070,0x0),
                    (0xcdfcb6ff93ca01a2755c0c8f0ad8ee04118e1b9e,0x1fdc78b5968fbd65351406a0e7cb6f45d9f26a01,0xcec3c44ec773a31fd3785a998e3526624a504705,0x3),
                    (0x65fc356da2a36d35d88c5c5792661d8fe152821c,0x20a49731ddf37504876ed4303cf8ee52426abbbe,0xf974613f265ced476f0ad2548eecffcf4b648a9e,0x7),
                    (0x59544b829fa1f696558ea62792b85e114e397433,0x23645dd35469fd873a73db34f1018f08ae7f2c24,0xe5a23255d9760df1f8d6c8ce1652e0480beb0b7d,0x2),
                    (0x8ef11fdbed1a2f64faca70aea2cac44dadd8c14c,0x640d24c485e9e04b9af2355c07cf7ad430c7ca58,0x20f0e050124bd754c13b8c2e86dbebaee2132bec,0x1),
                    (0x1b5ac91240f6450de7fc5208f0762501790e28b7,0x7991d2db2512b6463c201f0523ed863ce2a670e8,0xebf64515f997f18b726cd11a24276ef26505a409,0x6),
                    (0xba35a8c66a894fae013ac56c9d6ba538d8cbcf0b,0xcea24619e5bdd3418da925e3aebd5a3c6f64ef03,0xb9216f67fe0aa26e374b92ecf4b0c8545522785e,0x0),
                    (0xe4e86fdd765bc4d98bc807e3f56ad2f2ef8dbd15,0x67a9d34b95c25764e1026fd64a0cdadc4f894ef,0x57f0a006eb1ddbae5b7aaaa3e5a2740c1401c9e2,0x6),
                    (0xe582d66c85dda020da90ce0248057e9dff2a0120,0x8f261523dad715ddc7c992972d8cdab39a0e8920,0x2bcd65226ab00e4e1117a90b735ea287a921641a,0x2),
                    (0x62ac7d9437e54969456ae056289adeaefaccd6bb,0xe7a23830bdccf8e24a6aa1d84d94cff498f3958a,0x13d192adc3f46a9a2b624a3a93e6faf243e2120f,0x7),
                    (0xd24bfd231c4e6b4b3fe46ec642392e59bf1b7358,0x51b756a681426525f7194a66375a35185d529813,0x57a86c9d1fe7fe8ad9b05ea21239cd42bce93ca6,0x2),
                    (0xeb0501d2e40edeb6ecad416cfb5d12459de1f32a,0xc5a4cacf614bc7519130e6727126823d77b51c85,0xd86708d496f4e4265526247c79931bbc0351237c,0x0),
                    (0xb41393d8fe5adbe01ec1ae88aacf8030f990c260,0xb6997c03f903bc1add14cb98e8741647a60c62ad,0x2fa481db8208ccfa161e791631d91cc012bff387,0x5),
                    (0x851a5f6a1ff9ad28e22858aded0abe1d927f8f47,0xa35a9a8b26bcbf0a639efd5583c9830aa2834a61,0x71ed5887fc9b53af96793aa25285227e679923d0,0x6),
                    (0x36d5d74fdbb34184f56989136c19526a1e66f284,0xe2636b99dd8277a5bdf411a2ab44688704682b8b,0x8fa686e14e0c8c40f507b8e4cc8abf2d8391e13e,0x3),
                    (0x136e1685ce0dd8fa72c17db7f71ad3ec08201b0f,0xf8715b24f37af56cd40108e12d4cd65dfe47b18a,0x447eb0b48cd17036c130d2c9814df4452645562e,0x3),
                    (0x442cd9850919eef698ad67aad25dac1e609042cc,0x8879c395e3021c4c8e1d4cf3ed7556ddcfe88c98,0xaf3310936f1bf6f93698081b581b362aa4432c2f,0x0),
                    (0xe788598a42acba0d0b7b1f6ec9b230b44a477aad,0xad119581e7a04cf0b3b1f5197bc27d9684813b36,0x774ad198691047f7a63714bc633ebf66aa7d2e9d,0x0),
                    (0x96db72fa75d1f4ef567ae6b0a6a9b67b6eb925,0xb2a2d5c2c26fdf25b4ccc5981beff2fbce544bf1,0x259ef89bfdf867a25f2a45ba31e3b8f01d15ac98,0x6),
                    (0xfe84f3657569c6b2f6a820fe72ae29980bb3d3b6,0x81f40f3434d8a526ae3bdd9229e3b91436c195f2,0xd9ad8ce4bae25a93282b2d585a3ccc9f76c3cfd2,0x0),
                    (0xbd38a3ba51b95b74301f1a375039aadf45cf9500,0x981371c31ca751800cd9554d120390faa176f90,0xc687f4008be79d2f747d0d3d373d2908dc99f863,0x0),
                    (0x5cf2a3d05d937cb49929f7a5420c77a510f9b9db,0x43b40c9c33d53a2c03193c499ef7f99c19d36ed2,0x6efe5e9f33a99b6d6e2b072c52923bbbc6050ee0,0x4),
                    (0xb3096421f5e4056f23b5bab000b764a049bff24d,0x8f826e2bce70b6aa6ec454bc8e9e8cd851ebb165,0xbb9e3082a3a1bd77fd66bb03772219a944f03e29,0x7),
                    (0x3dd4cead2e79dcf86cc7917a579a2dba900bb099,0x7f75439b0103ed40729a24e7f9846b7c2ca3558,0x2ebb76dc34c83a60571f14cdf6f8261988a902bd,0x7),
                    (0x3180aeb53046ca485f501895ed61e57e8ed27b7,0x7efbf45c158b115885fb00e2ac5b5df85eef468a,0x7c97ef4e278686bce1a424a92471b21fcf3658b6,0x3),
                    (0x559fa993834a40f6fd31f8a3a2f83da980b2ef84,0x8785d04f6d97d688f90af33140889e4c7201382a,0x779f8d284898ca25426208f3a6c3b9455c70eb0d,0x7),
                    (0x49a0f529e86a638d1cb71dbd948357d390646128,0xc5c72505c3807890a11502cfc0286fdf40c924bd,0xdc242283b58e5d98803c067a4633590e5d1e5d9e,0x1),
                    (0xef75ace89af3a7791034ae6161e608384984eb34,0x61a4d32ca6bdf4f8559cf15bc9be41721575650,0x8fd9e8a6cdd86a2d960409b124453245b1c92f09,0x5),
                    (0xcf0cf859a451378f576de4e10b918fa70b0d0e02,0x66a7f51a86fe0cd0db57d2025464c1d95384c6c0,0xcc4673380c3a3cc4545e5644ebaad0ee2205af36,0x5),
                    (0xa973fdecf97847abfadc76a530cfaa51a544992f,0x64ebd081e1e5be70904723e1a786d9581ad4e5a5,0x58c16e616268863fce12b920e281ad4b1d9d2881,0x1),
                    (0x9bbcfa5f87bea52e4df986ecdb89dadf9fe7242b,0x520b4e89d3e3cd032e5c8c9cfab3f706fe49ca8c,0x198aa5c2cab8d22845c4f3ea8f710becaba98d13,0x3),
                    (0x42abe9b2d14ec440b51362694f93116cf4a8980d,0x38c3965c6f9c9699476239ea669acc598bf748b6,0xb47208202e92dbc5ed3d4319dd9e4ceeb21e9ec8,0x5),
                    (0x334732df257a5c08e42c56dcd31f3be5cfaa196e,0xe6387cab10b4e3bff5c72b7a8c47bf3f73812e0c,0x315e28210455bc5535e6f2a6dcf5a76732ad8c88,0x3),
                    (0x825347e82b6ecb7c40353d9282daf9804088f22b,0xced5ac7b578c4a95a177a283f60437a70232ff0,0xb647c743e3b4ce3ca95c586bdd14afc41d91ad09,0x4),
                    (0xf862df8e80ded401998ce913668155e078f5863f,0xa73fe4db4136c28cbfc6ee73c800548a0bd463e2,0xff0395bc6b17d90c38ba263488be5987e3b44890,0x7)
                    ]
                    n=len(data)
                    A=[]
                    C=[]
                    for h,r,s,b in data:
                        s_inv=inverse_mod(s,q)
                        A.append((r*s_inv)%q)
                        C.append(((h-b*s)*s_inv)%q)#HNP化简
                    M=Matrix(ZZ,n+1,n+1)
                    for i in range(n):
                        M[i,i]=q
                    for i in range(n):
                        M[n,i]=A[i]
                    M[n,n]=B
                    target=vector(C+[0])
                    M=M.stack(target)#这里表示把这行加到底下
                    print("[*] running LLL")
                    L=M.LLL()
                    for row in L:
                        d=int(row[-1])%q
                        if d==0:
                            continue
                        from ecdsa import SigningKey,SECP160r1
                        try:
                            sk=SigningKey.from_secret_exponent(d,curve=SECP160r1)
                            vk=sk.verifying_key
                    #这里是检查,用G&自己算出来的d的x,y是否符合题上提供的x,y
                            if vk.pubkey.point.x()==pubx and vk.pubkey.point.y()==puby:
                                print("d =",d)
                               flag="DesCTF{"+md5(str(d).encode()).hexdigest()+"}"
                                print("FLAG =",flag)
                                break
                        except:
                            pass

                    HNP泄露

                    至此,4道题AK,结束,继续学习