分类: 未分类

  • 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回路果然是只有自己能理解的

          到此为结