作者: ryin

  • 古剑山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,结束,继续学习

                • CRYPTO的基础认知

                  • 1.CRYPTO IS
                  • CTF含义上指的是密码破解,与密码研发割裂较大
                  • 2.CRYPTO INCLUDE
                  • 以下列举一些常见的CRYPTO题型:古典密码,密码分组的破解(ECB for instance),RSA的破解,ECC的破解,格密码的分析等
                  • 3。CRYPTO MEAN
                  • 就是解数学题,工具是电脑和经验

                  CRYPTO去魅:

                  CTF CRYPTO内容:python/sage题干,根据柯克霍夫原则,会给出完整的加密过程,出了密钥以外全公开,求解密钥等(这里不讨论黑盒),要求密码,数论分析能力,python写程序,读程序能力(sage)

                  for instance:

                  from hashlib import *
                  from secrets import randbelow
                  from ecdsa import SigningKey, SECP160r1, util
                  
                  leak = 3
                  total = 61
                  mask = (1 << leak) - 1
                  
                  def main():
                      sk = SigningKey.generate(curve=SECP160r1)
                      vk = sk.verifying_key
                      q = SECP160r1.order
                      print(hex(vk.pubkey.point.x()))
                      print(hex(vk.pubkey.point.y()))
                      d = sk.privkey.secret_multiplier
                      flag = "DesCTF{" + md5(str(d).encode()).hexdigest() + "}"
                      for i in range(total):
                          msg = f"msg-{i}".encode()
                          digest = sha1(msg).digest()
                          h = int.from_bytes(digest, "big") % q
                          k = randbelow(q - 1) + 1
                          sig = sk.sign_digest(digest, sigencode=util.sigencode_string, k=k)
                          r, s = util.sigdecode_string(sig, q)
                          print(f"({hex(h)}, {hex(int(r))}, {hex(int(s))}, {hex(k & mask)}),")
                  
                  
                  if __name__ == "__main__":
                      main()
                  #数据暂时省略

                  以上是一个简单的MT19937预测,原理是逆向随机数产生的MT19937随机数生成器的temper部分得到内部状态流从而预测接下来的输出,基本上可以快速地通过特征识别出题型,解题脚本如下:

                  #签到题,正常的近似忽略处理,左右爆破
                  #核心漏洞出现在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("[-] 求解失败:判别式不是完全平方数。")

                  出了可以快速识别题型地类别,还有像RSA之类需要积累处理经验特异化地题型,还有misc向的唯密文加密,这类算是押宝了,很难在没有提前认知时做出来

                  🧅🎗️🪖🙃🦄🍊🍧🪵🎉💩🩱🏪🥡🦺⛳🏦🍙🏟️🎁🦓🎃😇😂🍨🐻🦐🥼🥮🍇🪵🎓🧀😀🏬🎣🏟️🦞🤣🍕🍃👓🤿🧱🌵🦍🏟️🥍🏓🍞🏥🏓😆🥎🏭🐄🍎🥟🥢✨🏸⛲🐏🐶🦀🙂🌿🍄🗽🍄🥥🎋🎳😛🍞😗😃🧉🏟️🧀🍞🌴🍵🕍🩳🥟🎽🐨🍉🏞️🥎🍙🍤😁🏨🔇🙂🥍😛🎣🦝🦐🍵🪴🌿🏢🎿👺🫖🐮👛😛🏭🥎🏘️😘🥭🍟🎳🦁🥮🕶️🍍🐼🏦🥦🎑🐧🎗️🐴⛸️🫑🐵☕🎈🍂🎟️🎩🍉🥭🔇🩲🍔🎆🕋🎑🧨🥦🐮🥝🌰🍵🐨🐴🍞🥠🏛️🎳💄👑🎊🧱🦝🧨🐸👝🦀🐷🎍💄🦪🤡🎟️🔇💎🏭🏑😅📣🐻🩱👾🦊😍🥭🥕🌿🏸⛩️🐶🪨🦐🥒💩🐪👚🍅🧅🍘🏪🐨🐑😇✨🍭🥭👑😗🙂🍡🌲🦍🎈🎿👾🐢👘👹🍥🍊🍵🎿🩲🛕🏩😃🏦🩲🍯🦓🌾🐶😀💄🥭🏅🥲👛🥟😅🧉🪹🐩🐗🍂🏞️😉🎟️😙🧅🦺🥲😘🏯😇🏑🏛️🏰🥕🥑🏗️🏭📣🐊🍟😄😅🏛️🎈🏀🏩🤡🎊😁🍈🏗️🙃😗🎽🐐🩲😗🏪🧀😉👾🎑💎🥝🏒😘🥮🍭🎈🍦🐮🐑🫖😘🍞🐷🥑🏩🐗🗼😉🏪🦬🍞🍞🥰🌳🍞🎟️🐏🦺🐨🪴📣🧉😃🌾⛑️🧉⛸️🐻😅🍊🍼🏘️😗💄🤿🥝🎳🌳🍵⛲🍟😉🍌🦀💒🐸🏅🏀🐊🪹😈😇🦍🌿🎃📯🙃🐄🍑🦐🎟️🎃🤠🙃🙃😛🌿😈🐴🐧🏰🎉🍉💒😄⛳🫘🎏🙃🥟🍨🍎🍞🍍🎏🐑🍕🍀🥮🎗️⚽🎩🐸🍋🐏👺🌁🍧🐽🧅🥑🕌⛲🐢🐻🎃🫒🤣🍌🗼💒🐂⛪🍞👻😘🥏🐏🦍🍑😋🥽🤠🍕🦑🍄🥤🧅🥭🥏🎗️🥡🥊😙🎑😍👺🍵🍉🐻😘🍃🐲🙃🦞🐼🤩🐽🥬🔇🗼🏘️⛸️🐑🎋🍈🐗😋🍌🏭😇🍀🍯🍧🎐🍧🐑🎣
                  #只截取了一部分作为参考

                  以上是一道EMOJI-AES的唯密文破译,有信息0x4A,后者大概率是密钥用来破解密文,但是在没有基础时,很难联想到EMOJI-AES,并且这道题要求破解3次,启发我们要敢于尝试(在像格的题型,RSA的题型,爆破的范围在数学支持下鼓励反复调教)

                  CRYPTO个人学习路径

                  我上手时0代码基础,电脑认知勉强>=steam游戏管家,现在对密码有了最浅的了解,分享我的来的坑坑洼洼,以便后面的学子参考

                  • 下列步骤具有先后性
                  • 1.建立基础的认知:自学python语法到一般水平,后面见一个学一个,学习适量的信息安全数学基础,以便RSA理解,ECC理解
                  • 2.从古典密码,base编码等入手,学会基础的hash爆破(建立爆破思维)
                  • 3.了解最基础的RSA,掌握其经典处理
                  • 4.在做题中逐步接触到简单的ECB,ECC,随机数,格,建立自己的理解体系
                  • 5.CTF的比赛是无穷的,走得多块只取决于脚步
                  • #基础,多复现,代码落实到手,别养成AI依赖,对于模板不熟悉的题,让AI只负责写脚本,但思路一定要是自己给的

                  页: 1 2