吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1929|回复: 1
收起左侧

[CTF] [GoogleCTF2023]LEAST COMMON GENOMINATOR?

[复制链接]
Twilightl 发表于 2023-7-23 17:14
本帖最后由 Twilightl 于 2023-7-23 17:16 编辑

Challenge Name: LEAST COMMON GENOMINATOR?

Description:

Someone used this program to send me an encrypted message
but I can't read it! It uses something called an LCG, do you know what
it is? I dumped the first six consecutive values generated from it but
what do I do with it?!

题目附件:

  • generate.py

    • from secret import config
      from Crypto.PublicKey import RSA
      from Crypto.Util.number import bytes_to_long, isPrime
      class LCG:
      lcg_m = config.m#a
      lcg_c = config.c#b
      lcg_n = config.n#n
      def __init__(self, lcg_s):
          self.state = lcg_s
      def next(self):
          self.state = (self.state * self.lcg_m + self.lcg_c) % self.lcg_n
          return self.state
      if __name__ == '__main__':
      assert 4096 % config.it == 0
      assert config.it == 8
      assert 4096 % config.bits == 0
      assert config.bits == 512
      # Find prime value of specified bits a specified amount of times
      seed = 211286818345627549183608678726370412218029639873054513839005340650674982169404937862395980568550063504804783328450267566224937880641772833325018028629959635
      lcg = LCG(seed)
      primes_arr = []
      dump = True
      items = 0
      dump_file = open("dump.txt", "w")
      primes_n = 1
      while True:
          for i in range(config.it):
              while True:
                  prime_candidate = lcg.next()
                  if dump:
                      dump_file.write(str(prime_candidate) + '\n')
                      items += 1
                      if items == 6:
                          dump = False
                          dump_file.close()
                  if not isPrime(prime_candidate):
                      continue
                  elif prime_candidate.bit_length() != config.bits:
                      continue
                  else:
                      primes_n *= prime_candidate
                      primes_arr.append(prime_candidate)
                      break
          # Check bit length
          if primes_n.bit_length() > 4096:
              print("bit length", primes_n.bit_length())
              primes_arr.clear()
              primes_n = 1
              continue
          else:
              break
      # Create public key 'n'
      n = 1
      for j in primes_arr:
          n *= j
      print("[+] Public Key: ", n)
      print("[+] size: ", n.bit_length(), "bits")
      # Calculate totient 'Phi(n)'
      phi = 1
      for k in primes_arr:
          phi *= (k - 1)
      # Calculate private key 'd'
      d = pow(config.e, -1, phi)
      # Generate Flag
      assert config.flag.startswith(b"CTF{")
      assert config.flag.endswith(b"}")
      enc_flag = bytes_to_long(config.flag)
      assert enc_flag < n
      # Encrypt Flag
      _enc = pow(enc_flag, config.e, n)
      with open ("flag.txt", "wb") as flag_file:
          flag_file.write(_enc.to_bytes(n.bit_length(), "little"))
      # Export RSA Key
      rsa = RSA.construct((n, config.e))
      with open ("public.pem", "w") as pub_file:
          pub_file.write(rsa.exportKey().decode())
  • dump.txt

    • 2166771675595184069339107365908377157701164485820981409993925279512199123418374034275465590004848135946671454084220731645099286746251308323653144363063385
      6729272950467625456298454678219613090467254824679318993052294587570153424935267364971827277137521929202783621553421958533761123653824135472378133765236115
      2230396903302352921484704122705539403201050490164649102182798059926343096511158288867301614648471516723052092761312105117735046752506523136197227936190287
      4578847787736143756850823407168519112175260092601476810539830792656568747136604250146858111418705054138266193348169239751046779010474924367072989895377792
      7578332979479086546637469036948482551151240099803812235949997147892871097982293017256475189504447955147399405791875395450814297264039908361472603256921612
      2550420443270381003007873520763042837493244197616666667768397146110589301602119884836605418664463550865399026934848289084292975494312467018767881691302197
  • public.pem

    • -----BEGIN PUBLIC KEY-----
      MIICITANBgkqhkiG9w0BAQEFAAOCAg4AMIICCQKCAgACnR8r4GemZPmX2+zLsBgz
      qHanMd0pbEGFRRldNezYX9A3HT99peociEbEMUnUaVWuDbzHJX7drG8s/exQW4XF
      fE5lGy+D0gSkJfQS1komUxic6iWH/1bZnU6rWFJlpbIzy/3IMx4QIx5cbOA0SsLu
      AomMEi4ZERGLxm2ta7ZZZuEYVYIa9/mrlXYkTgi1fxLguT35ykHNk5Rm8e8Q8KF/
      V2pQ3CQIQYZra2WLGNsxOXW7FLttmMyzgi4WQjLE/SVMs7Th5lGkjmXoQpMcc0Zh
      kL3H0vMHWtQeclqsE+QXgAUQFshiSb0auf69y/H+R+qJCO0jRgBz3OVudSx91oSB
      GaF7DTfFu3LsgJvMDRAdhPgdlLLzlR0PldVq1jKwjs1dWce2R5r4B0dnXqPrxLuu
      A/WNp3ni3jp6AL2y7MKn2AylPUEr+/fQ6+B33wuIHcZiXHdYYPvemehtCf1WCV4Q
      /C10Q3E6PK6R+dncE7ZUg0U3qnA84rAZUwweGLUD2yXngHMxDLLRv44Uv28XFvl3
      5kFrlJhIhxtx/Fon70EKNboDCT8UXJ5ZlMyt47WBmYGp7FZbafbH6coLAQr1LQCy
      HCJYimu7lXr9eGYixE93xXHJ3KIJPaZGmhW3qbj3B8ZxrIvGjkZtHqiw+OCNj343
      Q44DknQ8F3CwBmZUmBxZSQIDAQAB
      -----END PUBLIC KEY-----

题目分析:

  • 分析源代码,整体思路是读取预设参数,使用LCG生成RSA中的参数phi,读取预设e生成n,使用RSA加密flag
  • 其中,解题的关键是通过LCA的output(dump.txt给出),反推LCA的生成参数:a、b、m。

    • 关于LCG,线性同余发生器,可参考ctf之lcg算法
    • 这里给出攻击代码:
    • from functools import reduce
      from math import gcd
      from Crypto.Util.number import *
      def egcd(a, b):
      if a == 0:
          return (b, 0, 1)
      else:
          g, y, x = egcd(b % a, a)
          return (g, x - (b // a) * y, y)
      def modinv(a, m):
      g, x, y = egcd(a, m)
      if g != 1:
          raise Exception('modular inverse does not exist')
      else:
          return x % m
      def crack_unknown_increment(states, modulus, multiplier):
      increment = (states[1] - states[0]*multiplier) % modulus
      return modulus, multiplier, increment
      def crack_unknown_multiplier(states, modulus):
      multiplier = (states[2] - states[1]) * modinv(states[1] - states[0], modulus) % modulus
      return crack_unknown_increment(states, modulus, multiplier)
      def crack_unknown_modulus(states):
      diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]
      zeroes = [t2*t0 - t1*t1 for t0, t1, t2 in zip(diffs, diffs[1:], diffs[2:])]
      modulus = abs(reduce(gcd, zeroes))
      return crack_unknown_multiplier(states, modulus)
      # N[i+1] = (A*N[i]+B) % M
      # A,B,N均未知
      sequence = []
      modulus, multiplier, increment = crack_unknown_modulus(sequence)
      print('A = '+str(multiplier))
      print('B = '+str(increment))
      print('N = '+str(modulus))
  • 攻击后可得到LCG初始参数:
    from Crypto.PublicKey import RSA
    from Crypto.Util.number import bytes_to_long, isPrime
    class LCG:
    lcg_m = 99470802153294399618017402366955844921383026244330401927153381788409087864090915476376417542092444282980114205684938728578475547514901286372129860608477#a
    lcg_c = 3910539794193409979886870049869456815685040868312878537393070815966881265118275755165613835833103526090552456472867019296386475520134783987251699999776365#b
    lcg_n = 8311271273016946265169120092240227882013893131681882078655426814178920681968884651437107918874328518499850252591810409558783335118823692585959490215446923#n
    def __init__(self, lcg_s):
        self.state = lcg_s
    def next(self):
        self.state = (self.state * self.lcg_m + self.lcg_c) % self.lcg_n
        return self.state
    if __name__ == '__main__':
    it = 8
    bits = 512
    # Find prime value of specified bits a specified amount of times
    seed = 211286818345627549183608678726370412218029639873054513839005340650674982169404937862395980568550063504804783328450267566224937880641772833325018028629959635
    lcg = LCG(seed)
    primes_arr = []
    dump = True
    items = 0
    dump_file = open("dump.txt", "w")
    primes_n = 1
    while True:
        for i in range(it):
            while True:
                prime_candidate = lcg.next()
                if dump:
                    dump_file.write(str(prime_candidate) + '\n')
                    items += 1
                    if items == 6:
                        dump = False
                        dump_file.close()
                if not isPrime(prime_candidate):
                    continue
                elif prime_candidate.bit_length() != bits:
                    continue
                else:
                    primes_n *= prime_candidate
                    primes_arr.append(prime_candidate)
                    break
        # Check bit length
        if primes_n.bit_length() > 4096:
            print("bit length", primes_n.bit_length())
            primes_arr.clear()
            primes_n = 1
            continue
        else:
            break
    for i in primes_arr:
        print(i)
    phi = 1
    for k in primes_arr:
        phi *= (k - 1)
    print(phi)
  • 之后就是基本RSA解密

    • 特别的:RSA的公钥以public.pem文件形式给出,需要转换
    • 这里使用网站解析:http://www.hiencode.com/pub_asys.html
    • 当然也可以使用Python相关库导入
    • 编写python脚本
    • from Crypto.Util.number import *
      from gmpy2 import *
      e=65537
      n=10663197782188755187683519128391607889384236984841159980368295444757556251666173181966270935627381363634363152017932100870866073743196496182631686860974529519304898483583880797787662017633083156395595834399833548697123723014690019039843286516441722069672629491734333533874814655021750465470744221908153042891598629847474248035637833322061522018106952433195747728295433960640630861246440503259390376775374597599893181929337896828585045200809527092809746018806372033463639511758548910283175609247004446838778595246305426570138737826179346237355482797652195577697810275921391495040635386160960077290295503041318571091585994232128977189250560450541724526298324540333633756525782039764692046496665886338829810667477580556894564708344208454824227841439832096019161139930247745872364451624685509376111571650368725564985474387879414080347347860850162991841345901292668284154455326375190710973306072342463052980587717861754724857153296737480485351289440257347649463959856275061657492903860650820592573032713540474706170687783458640870091611869081448943812812946839710972240290444677129959352614435646729998203754847928052523568784250017348717982594389028978174915940120215557880850880860400503991453968452316505964854586987874049061874850121
      with open(r'D:\lenovo\VSCode\CTF\7.22\c\flag.txt','rb') as f:
      c=bytes_to_long(f.read()[::-1])
      # print(c)
      phi=10663197782188755187683519128391607889384236984841159980368295444757556251666173181966270935627381363634363152017932100870866073743196496182631686860974518215336308559118375893619890700566492246455484248865065942975919518821420696894418516412087824875580336264450895120608590786960103732463735259314746627602481490634183029017002524008299865576550974115842994899362462506740342026543406560282128252586317741411826809367436511777686104024771128452674932531192224723706907716833848808135180104501764984240012323401024049549978818892958211947253027021172432101248326724880191387361026527894934644325582519289043602145078962059823083375709403213297514989173849682349374277191142325479424357500368940265794006074137733272137342565970150847115890972043431768285064555903295753465581583657708894234169997201812684367717581685538245496933190164547560072929740493318805568286958724231450156740155971287257415601496588835565287706802963284818961466920678551895969101307349683566564580517648582979443095366832488807574064804819371853182596765904847800309068939076791323026159289764642558267730090790476527577604463134018573846651149743622527934870659053517579542096949282004235077015296802375481771769578980224915514371840316985391540016742400
      d=gmpy2.invert(e,phi)
      flag=gmpy2.powmod(c,d,n)
      print(long_to_bytes(flag))
  • 得到flag:

    • CTF{C0nGr@tz_RiV35t_5h4MiR_nD_Ad13MaN_W0ulD_b_h@pPy}

免费评分

参与人数 3威望 +1 吾爱币 +22 热心值 +2 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
lalicorne + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

NightGlow 发表于 2023-7-24 13:53
这份密码学的writeup写的太好了!向大佬学习!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 13:58

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表