找回密码
 立即注册
首页 业界区 安全 2025LilCTF -- Crypto -- WriteUp

2025LilCTF -- Crypto -- WriteUp

沦嘻亟 昨天 00:49
2025LilCTF -- Crypto -- WriteUp

[WARM UP] 对称!Just Decrypt

task
  1. """Just Decrypt - A simple LilCTF warmup challenge."""
  2. from random import Random
  3. from Crypto.Cipher import AES
  4. from Crypto.Util.Padding import pad
  5. FLAG = b""
  6. key = Random(2025).randbytes(16)
  7. print(AES.new(key, AES.MODE_CBC, iv=FLAG[9:25]).encrypt(pad(FLAG, 16)).hex())
  8. # ae39cfab1ba8d38fc3761216c393caf16e3c3f13fe57e2dedd52f1b13072fa93df405c7e731a193cabe5fd88ee3241f79aded62d139faba8c767a3b8efc5a855
复制代码
analysis

  • AES的key不变,我们只需要根据AES - CBC前后存在异或的性质进行求解即可。

    • 已知flag前七个字节为LILCTF{ --> iv的前七个字节为flag[9:16] --> flag[9:16] = decrypt(ciphertext[:7]) ^ b'LILCTF{'
    • 因此flag的第一段我们只缺少flag[7]与flag[8]两个可视化字符,我们进行一个爆破。
    • iv = flag[:16] ^ decrypt(ciphertext[:16]),最后根据iv == flag[9:25]判定是否爆破成功。

exp
  1. from Crypto.Cipher import AES
  2. from Crypto.Util.Padding import unpad
  3. from pwn import xor
  4. ciphertext = bytes.fromhex("ae39cfab1ba8d38fc3761216c393caf16e3c3f13fe57e2dedd52f1b13072fa93df405c7e731a193cabe5fd88ee3241f79aded62d139faba8c767a3b8efc5a855")
  5. key = b'\xbc\xd8\xc8\x8e\x81\xf8+\x15\x82\x17V\xa5\xa3\x87h\xd6'
  6. # print(len(ciphertext)) 64
  7. aes1 = AES.new(key, AES.MODE_ECB)
  8. # print(my_aes.decrypt(ciphertext))
  9. temp = aes1.decrypt(ciphertext[:16])
  10. for i in range(32, 127):
  11.     for j in range(32, 127):
  12.         mask = b'LILCTF{' + bytes([i]) + bytes([j])
  13.         message0 = mask + xor(temp[:7], b'LILCTF{')
  14.         iv = xor(temp, message0)
  15.         aes2 = AES.new(key, AES.MODE_CBC, iv)
  16.         flag = unpad(aes2.decrypt(ciphertext), 16)
  17.         if flag[9:25] == iv:
  18.             print(flag)
  19. # b'LILCTF{b1a6labl4@#$%_H4v3_fUn_W1tH_y0Ur_sYmM3try_3NcRyPt10n!}'
复制代码
ez_math

task
  1. from sage.all import *
  2. from Crypto.Util.number import *
  3. flag = b'LILCTF{test_flag}'[7:-1]
  4. lambda1 = bytes_to_long(flag[:len(flag)//2])
  5. lambda2 = bytes_to_long(flag[len(flag)//2:])
  6. p = getPrime(512)
  7. def mul(vector, c):
  8.     return [vector[0]*c, vector[1]*c]
  9. v1 = [getPrime(128), getPrime(128)] # v1 = [a, b]
  10. v2 = [getPrime(128), getPrime(128)] # v2 = [c, d]
  11. A = matrix(GF(p), [v1, v2])
  12. B = matrix(GF(p), [mul(v1, lambda1), mul(v2, lambda2)])
  13. """
  14. A = [
  15.     [a, b],
  16.     [c, d]
  17. ]
  18. B = [
  19.     [a * flag1, b * flag1],
  20.     [c * flag2, d * flag2]
  21. ]
  22.     [flag1, 0]      [a, b]
  23. B =             *
  24.     [0, flag2]      [c, d]
  25. B = diag(flag1, flag2) * A --> C = A ^ -1 * B = A ^ -1 * diag(flag1, flag2) * A
  26. diag(flag1, flag2) ~ C --> diag(flag1, flag2)的迹和行列式与C对应相等
  27. """
  28. C = A.inverse() * B
  29. print(f'p = {p}')
  30. print(f'C = {str(C).replace(" ", ",").replace("\n", ",").replace("[,", "[")}')
  31. # p = 9620154777088870694266521670168986508003314866222315790126552504304846236696183733266828489404860276326158191906907396234236947215466295418632056113826161
  32. # C = [7062910478232783138765983170626687981202937184255408287607971780139482616525215270216675887321965798418829038273232695370210503086491228434856538620699645,7096268905956462643320137667780334763649635657732499491108171622164208662688609295607684620630301031789132814209784948222802930089030287484015336757787801],[7341430053606172329602911405905754386729224669425325419124733847060694853483825396200841609125574923525535532184467150746385826443392039086079562905059808,2557244298856087555500538499542298526800377681966907502518580724165363620170968463050152602083665991230143669519866828587671059318627542153367879596260872]
复制代码
analysis
一道简单的线性代数的问题,相关的分析在task的注释中。主要应用的就是相似矩阵的特性。
exp
  1. from Crypto.Util.number import *
  2. from gmpy2 import iroot
  3. p = 9620154777088870694266521670168986508003314866222315790126552504304846236696183733266828489404860276326158191906907396234236947215466295418632056113826161
  4. C = [
  5.     [7062910478232783138765983170626687981202937184255408287607971780139482616525215270216675887321965798418829038273232695370210503086491228434856538620699645,7096268905956462643320137667780334763649635657732499491108171622164208662688609295607684620630301031789132814209784948222802930089030287484015336757787801],
  6.     [7341430053606172329602911405905754386729224669425325419124733847060694853483825396200841609125574923525535532184467150746385826443392039086079562905059808,2557244298856087555500538499542298526800377681966907502518580724165363620170968463050152602083665991230143669519866828587671059318627542153367879596260872]
  7. ]
  8. a, b, c, d = C[0][0], C[0][1], C[1][0], C[1][1]
  9. # tr = flag1 + flag2
  10. tr = (a + d) % p
  11. # det = flag1 * flag2
  12. det = (a * d - b * c) % p
  13. temp = iroot(tr ** 2 - 4 * det, 2)[0]
  14. flag1 = (tr + temp) // 2
  15. flag2 = tr - flag1
  16. flag = b'LILCTF{' + long_to_bytes(flag1) + long_to_bytes(flag2) + b'}'
  17. print(flag)
  18. # b'LILCTF{It_w4s_the_be5t_of_times_1t_wa5_the_w0rst_of_t1me5}'
复制代码
mid_math

task
  1. from sage.all import *
  2. from Crypto.Util.number import *
  3. from tqdm import tqdm
  4. from random import randint
  5. from Crypto.Cipher import AES
  6. from Crypto.Util.Padding import pad
  7. flag = b'LILCTF{test_flag}'
  8. p = getPrime(64)
  9. P = GF(p)
  10. key = randint(2 ** 62, p)
  11. print(f"key = {key}")
  12. def mul(vector, c):
  13.     return [vector[0] * c, vector[1] * c, vector[2] * c, vector[3] * c, vector[4] * c]
  14. v1 = [getPrime(64), getPrime(64), getPrime(64), getPrime(64), getPrime(64)]
  15. v2 = [getPrime(64), getPrime(64), getPrime(64), getPrime(64), getPrime(64)]
  16. v3 = [getPrime(64), getPrime(64), getPrime(64), getPrime(64), getPrime(64)]
  17. v4 = [getPrime(64), getPrime(64), getPrime(64), getPrime(64), getPrime(64)]
  18. v5 = [getPrime(64), getPrime(64), getPrime(64), getPrime(64), getPrime(64)]
  19. a, b, c, d, e = getPrime(64), getPrime(64), getPrime(64), getPrime(64),  0
  20. A = matrix(P, [v1, v2, v3, v4, v5])
  21. B = matrix(P, [mul(v1, a), mul(v2, b), mul(v3, c), mul(v4, d), mul(v5, e)])
  22. C = A.inverse() * B
  23. D = C ** key
  24. """
  25. B = [
  26.     [a * v1[0], a * v1[1], a * v1[2], a * v1[3], a * v1[4]],
  27.     [b * v2[0], b * v2[1], b * v2[2], b * v2[3], b * v2[4]],
  28.     [c * v3[0], c * v3[1], c * v3[2], c * v3[3], c * v3[4]],
  29.     [d * v4[0], d * v4[1], d * v4[2], d * v4[3], d * v4[4]],
  30.     [0, 0, 0, 0, 0]
  31. ]
  32.     [a, 0, 0, 0, 0]
  33.     [0, b, 0, 0, 0]
  34. B = [0, 0, c, 0, 0] * A
  35.     [0, 0, 0. d, 0]
  36.     [0, 0, 0, 0, 0]
  37.    
  38. C = A ^ -1 * B = A ^ -1 * diag(a, b, c, d, 0) * A --> C ~ diag(a, b, c, d, 0) -->
  39. D = C ** key = A ^ -1 * diag(a, b, c, d, 0) ** key * A --> D ~ diag(a, b, c, d, 0) ** key --> D ~ diag(a ** key % p, b ** key % p, c ** key % p, d ** key % p, 0)
  40. D.eigenvalue = C.eigenvalue ** key
  41. """
  42. key = pad(long_to_bytes(key), 16)
  43. aes = AES.new(key, AES.MODE_ECB)
  44. msg = aes.encrypt(pad(flag, 64))
  45. print(f"p = {p}")
  46. print(f'C = {[i for i in C]}'.replace('(', '[').replace(')', ']'))
  47. print(f'D = {[i for i in D]}'.replace('(', '[').replace(')', ']'))
  48. print(f"msg = {msg}")
  49. # p = 14668080038311483271
  50. # C = [[11315841881544731102, 2283439871732792326, 6800685968958241983, 6426158106328779372, 9681186993951502212], [4729583429936371197, 9934441408437898498, 12454838789798706101, 1137624354220162514, 8961427323294527914], [12212265161975165517, 8264257544674837561, 10531819068765930248, 4088354401871232602, 14653951889442072670], [6045978019175462652, 11202714988272207073, 13562937263226951112, 6648446245634067896, 13902820281072641413], [1046075193917103481, 3617988773170202613, 3590111338369894405, 2646640112163975771, 5966864698750134707]]
  51. # D = [[1785348659555163021, 3612773974290420260, 8587341808081935796, 4393730037042586815, 10490463205723658044], [10457678631610076741, 1645527195687648140, 13013316081830726847, 12925223531522879912, 5478687620744215372], [9878636900393157276, 13274969755872629366, 3231582918568068174, 7045188483430589163, 5126509884591016427], [4914941908205759200, 7480989013464904670, 5860406622199128154, 8016615177615097542, 13266674393818320551], [3005316032591310201, 6624508725257625760, 7972954954270186094, 5331046349070112118, 6127026494304272395]]
  52. # msg = b"\xcc]B:\xe8\xbc\x91\xe2\x93\xaa\x88\x17\xc4\xe5\x97\x87@\x0fd\xb5p\x81\x1e\x98,Z\xe1n`\xaf\xe0%:\xb7\x8aD\x03\xd2Wu5\xcd\xc4#m'\xa7\xa4\x80\x0b\xf7\xda8\x1b\x82k#\xc1gP\xbd/\xb5j"
复制代码
analysis
C和D的特征值之间的离散对数关系可以求解key进行求解flag,证明在解题分析的时候也写在了task的注释中。
这道题相当于是ez_math的升级版,因为在ez_math中我利用的是相似方阵的迹和行列式相等。这里使用的是相似矩阵的特征值是相等的。两者都可以进行简单的证明,或许在线性代数的课程中我们都以结论的形式进行记忆。注意,因为在求解特征值的过程中,我们是经过特征多项式求解的,所以在顺序的对应关系上可能存在乱序的关系,所以exp中使用简单的组合避免了这一情况。
exp
  1. from sage.all import *
  2. from Crypto.Util.number import *
  3. from Crypto.Cipher import AES
  4. from Crypto.Util.Padding import unpad, pad
  5. import itertools
  6. p = 14668080038311483271
  7. C = [
  8.     [11315841881544731102, 2283439871732792326, 6800685968958241983, 6426158106328779372, 9681186993951502212],
  9.     [4729583429936371197, 9934441408437898498, 12454838789798706101, 1137624354220162514, 8961427323294527914],
  10.     [12212265161975165517, 8264257544674837561, 10531819068765930248, 4088354401871232602, 14653951889442072670],
  11.     [6045978019175462652, 11202714988272207073, 13562937263226951112, 6648446245634067896, 13902820281072641413],
  12.     [1046075193917103481, 3617988773170202613, 3590111338369894405, 2646640112163975771, 5966864698750134707]
  13. ]
  14. D = [
  15.     [1785348659555163021, 3612773974290420260, 8587341808081935796, 4393730037042586815, 10490463205723658044],
  16.     [10457678631610076741, 1645527195687648140, 13013316081830726847, 12925223531522879912, 5478687620744215372],
  17.     [9878636900393157276, 13274969755872629366, 3231582918568068174, 7045188483430589163, 5126509884591016427],
  18.     [4914941908205759200, 7480989013464904670, 5860406622199128154, 8016615177615097542, 13266674393818320551],
  19.     [3005316032591310201, 6624508725257625760, 7972954954270186094, 5331046349070112118, 6127026494304272395]
  20. ]
  21. msg = b"\xcc]B:\xe8\xbc\x91\xe2\x93\xaa\x88\x17\xc4\xe5\x97\x87@\x0fd\xb5p\x81\x1e\x98,Z\xe1n`\xaf\xe0%:\xb7\x8aD\x03\xd2Wu5\xcd\xc4#m'\xa7\xa4\x80\x0b\xf7\xda8\x1b\x82k#\xc1gP\xbd/\xb5j"
  22. P = GF(p)
  23. C = matrix(P, C)
  24. D = matrix(P, D)
  25. eigC = C.eigenvalues()
  26. eigD = D.eigenvalues()
  27. eigC = [lam for lam in eigC if lam != P(0)]
  28. eigD = [mu for mu in eigD if mu != P(0)]
  29. for lc, ld in itertools.product(eigC, eigD):
  30.     try:
  31.         key = discrete_log(ld, lc)
  32.         if C ** key == D:
  33.             print(f"key = {key}")
  34.             break
  35.     except (ValueError, ArithmeticError):
  36.         continue
  37. key = pad(long_to_bytes(int(key)), 16)
  38. my_aes = AES.new(key, mode = AES.MODE_ECB)
  39. flag = unpad(my_aes.decrypt(msg), 64)
  40. print(flag)
  41. """
  42. key = 5273966641785501202
  43. b'LILCTF{Are_y0u_5till_4wake_que5t1on_m4ker!}'
  44. """
复制代码
baaaaaag

task
  1. from Crypto.Util.number import *
  2. import random
  3. from Crypto.Cipher import AES
  4. import hashlib
  5. from Crypto.Util.Padding import pad
  6. from secret import flag
  7. p = random.getrandbits(72)
  8. assert len(bin(p)[2:]) == 72
  9. a = [getPrime(90) for _ in range(72)]
  10. b = 0
  11. t = p
  12. for i in a:
  13.     temp = t % 2
  14.     b += temp * i
  15.     t = t >> 1
  16. key = hashlib.sha256(str(p).encode()).digest()
  17. cipher = AES.new(key, AES.MODE_ECB)
  18. flag = pad(flag,16)
  19. ciphertext = cipher.encrypt(flag)
  20. print(f'a = {a}')
  21. print(f'b = {b}')
  22. print(f"ciphertext = {ciphertext}")
  23. '''
  24. a = [965032030645819473226880279, 699680391768891665598556373, 1022177754214744901247677527, 680767714574395595448529297, 1051144590442830830160656147, 1168660688736302219798380151, 796387349856554292443995049, 740579849809188939723024937, 940772121362440582976978071, 787438752754751885229607747, 1057710371763143522769262019, 792170184324681833710987771, 912844392679297386754386581, 906787506373115208506221831, 1073356067972226734803331711, 1230248891920689478236428803, 713426848479513005774497331, 979527247256538239116435051, 979496765566798546828265437, 836939515442243300252499479, 1185281999050646451167583269, 673490198827213717568519179, 776378201435505605316348517, 809920773352200236442451667, 1032450692535471534282750757, 1116346000400545215913754039, 1147788846283552769049123803, 994439464049503065517009393, 825645323767262265006257537, 1076742721724413264636318241, 731782018659142904179016783, 656162889354758353371699131, 1045520414263498704019552571, 1213714972395170583781976983, 949950729999198576080781001, 1150032993579134750099465519, 975992662970919388672800773, 1129148699796142943831843099, 898871798141537568624106939, 997718314505250470787513281, 631543452089232890507925619, 831335899173370929279633943, 1186748765521175593031174791, 884252194903912680865071301, 1016020417916761281986717467, 896205582917201847609656147, 959440423632738884107086307, 993368100536690520995612807, 702602277993849887546504851, 1102807438605649402749034481, 629539427333081638691538089, 887663258680338594196147387, 1001965883259152684661493409, 1043811683483962480162133633, 938713759383186904819771339, 1023699641268310599371568653, 784025822858960757703945309, 986182634512707587971047731, 1064739425741411525721437119, 1209428051066908071290286953, 667510673843333963641751177, 642828919542760339851273551, 1086628537309368288204342599, 1084848944960506663668298859, 667827295200373631038775959, 752634137348312783761723507, 707994297795744761368888949, 747998982630688589828284363, 710184791175333909291593189, 651183930154725716807946709, 724836607223400074343868079, 1118993538091590299721647899]
  25. b = 34962396275078207988771864327
  26. ciphertext = b'Lo~G\xf46>\xd609\x8e\x8e\xf5\xf83\xb5\xf0\x8f\x9f6&\xea\x02\xfa\xb1_L\x85\x93\x93\xf7,`|\xc6\xbe\x05&\x85\x8bC\xcd\xe6?TV4q'
  27. '''
复制代码
analysis

  • 显而易见,我们拿到的数据有a,b以及flag经过AES加密之后的密文,解决问题的关键就是获得p以得到key对ciphertext进行AES的解密获取flag。
  • 根据题目名称以及b的计算过程,可以知晓这就是一个背包问题。针对于这个背包问题,其实就是根据a,b去还原p的二进制位,我们构造方程式的格求解即可。
  • 注意,针对于GF(2)中的格,我们采用2x - 1令其定义域为{-1, 1}提高规约效率。这里我先使用了LLL进行规约,发现并不能准确地规约出我们想要地结果;之后BKZ进行规约结果优化,记得适当调整block_size的大小,不断地进行增大以增加规约的准确性。如果前者没有针对于2x-1的变化,block_size增大到一定量的时候也是可以准确规约出p的。
  • 针对于BKZ规约之后的结果,我们进行p的检验。

    • 最后一列必须为0 --> (sum(x_i*a_i*C) - b*C = 0 → sum(x_i*a_i) = b)
    • 前n列元素绝对值≤1(对应2x_i - 1 ∈ {-1,1},即x_i = (元素 + 1) // 2)

exp
[code]from sage.all import Matrix, ZZfrom Crypto.Util.number import *from Crypto.Cipher import AESimport hashlibfrom Crypto.Util.Padding import unpada = [965032030645819473226880279, 699680391768891665598556373, 1022177754214744901247677527, 680767714574395595448529297, 1051144590442830830160656147, 1168660688736302219798380151, 796387349856554292443995049, 740579849809188939723024937, 940772121362440582976978071, 787438752754751885229607747, 1057710371763143522769262019, 792170184324681833710987771, 912844392679297386754386581, 906787506373115208506221831, 1073356067972226734803331711, 1230248891920689478236428803, 713426848479513005774497331, 979527247256538239116435051, 979496765566798546828265437, 836939515442243300252499479, 1185281999050646451167583269, 673490198827213717568519179, 776378201435505605316348517, 809920773352200236442451667, 1032450692535471534282750757, 1116346000400545215913754039, 1147788846283552769049123803, 994439464049503065517009393, 825645323767262265006257537, 1076742721724413264636318241, 731782018659142904179016783, 656162889354758353371699131, 1045520414263498704019552571, 1213714972395170583781976983, 949950729999198576080781001, 1150032993579134750099465519, 975992662970919388672800773, 1129148699796142943831843099, 898871798141537568624106939, 997718314505250470787513281, 631543452089232890507925619, 831335899173370929279633943, 1186748765521175593031174791, 884252194903912680865071301, 1016020417916761281986717467, 896205582917201847609656147, 959440423632738884107086307, 993368100536690520995612807, 702602277993849887546504851, 1102807438605649402749034481, 629539427333081638691538089, 887663258680338594196147387, 1001965883259152684661493409, 1043811683483962480162133633, 938713759383186904819771339, 1023699641268310599371568653, 784025822858960757703945309, 986182634512707587971047731, 1064739425741411525721437119, 1209428051066908071290286953, 667510673843333963641751177, 642828919542760339851273551, 1086628537309368288204342599, 1084848944960506663668298859, 667827295200373631038775959, 752634137348312783761723507, 707994297795744761368888949, 747998982630688589828284363, 710184791175333909291593189, 651183930154725716807946709, 724836607223400074343868079, 1118993538091590299721647899]b = 34962396275078207988771864327ciphertext = b'Lo~G\xf46>\xd609\x8e\x8e\xf5\xf83\xb5\xf0\x8f\x9f6&\xea\x02\xfa\xb1_L\x85\x93\x93\xf7,`|\xc6\xbe\x05&\x85\x8bC\xcd\xe6?TV4q'n = 72C = 2 ** 100   # C > sum(a) 2 ** (90 + 6) --> 2 ** 100# print(C > sum(a))L = Matrix(ZZ, n + 1, n + 1)for i in range(n):    L[i, i] = 2    L[i, -1] = a * Cfor i in range(n):    L[-1, i] = -1L[-1, -1] = -b * C# L = L.LLL()# print(L)L = L.BKZ(block_size = 26)# print(L)for idx, row in enumerate(L):    # 1. 最后一列必须为0 --> (sum(x_i*a_i*C) - b*C = 0 → sum(x_i*a_i) = b)    # 2. 前n列元素绝对值≤1(对应2x_i - 1 ∈ {-1,1},即x_i = (元素 + 1) // 2)    if row[-1] != 0:        continue    if not all(abs(x)

相关推荐

您需要登录后才可以回帖 登录 | 立即注册