沦嘻亟 发表于 3 天前

2025LilCTF -- Crypto -- WriteUp

2025LilCTF -- Crypto -- WriteUp

对称!Just Decrypt

task
"""Just Decrypt - A simple LilCTF warmup challenge."""

from random import Random
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad


FLAG = b""
key = Random(2025).randbytes(16)

print(AES.new(key, AES.MODE_CBC, iv=FLAG).encrypt(pad(FLAG, 16)).hex())

# ae39cfab1ba8d38fc3761216c393caf16e3c3f13fe57e2dedd52f1b13072fa93df405c7e731a193cabe5fd88ee3241f79aded62d139faba8c767a3b8efc5a855analysis

[*]AES的key不变,我们只需要根据AES - CBC前后存在异或的性质进行求解即可。
[*]已知flag前七个字节为LILCTF{ --> iv的前七个字节为flag --> flag = decrypt(ciphertext[:7]) ^ b'LILCTF{'
[*]因此flag的第一段我们只缺少flag与flag两个可视化字符,我们进行一个爆破。
[*]iv = flag[:16] ^ decrypt(ciphertext[:16]),最后根据iv == flag判定是否爆破成功。

exp
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from pwn import xor

ciphertext = bytes.fromhex("ae39cfab1ba8d38fc3761216c393caf16e3c3f13fe57e2dedd52f1b13072fa93df405c7e731a193cabe5fd88ee3241f79aded62d139faba8c767a3b8efc5a855")
key = b'\xbc\xd8\xc8\x8e\x81\xf8+\x15\x82\x17V\xa5\xa3\x87h\xd6'
# print(len(ciphertext)) 64
aes1 = AES.new(key, AES.MODE_ECB)
# print(my_aes.decrypt(ciphertext))
temp = aes1.decrypt(ciphertext[:16])
for i in range(32, 127):
    for j in range(32, 127):
      mask = b'LILCTF{' + bytes() + bytes()
      message0 = mask + xor(temp[:7], b'LILCTF{')
      iv = xor(temp, message0)
      aes2 = AES.new(key, AES.MODE_CBC, iv)
      flag = unpad(aes2.decrypt(ciphertext), 16)
      if flag == iv:
            print(flag)
# b'LILCTF{b1a6labl4@#$%_H4v3_fUn_W1tH_y0Ur_sYmM3try_3NcRyPt10n!}'ez_math

task
from sage.all import *
from Crypto.Util.number import *

flag = b'LILCTF{test_flag}'
lambda1 = bytes_to_long(flag[:len(flag)//2])
lambda2 = bytes_to_long(flag)
p = getPrime(512)
def mul(vector, c):
    return *c, vector*c]

v1 = # v1 =
v2 = # v2 =

A = matrix(GF(p), )
B = matrix(GF(p), )

"""
A = [
    ,
   
]

B = [
    ,
   
]

          
B =             *
          

B = diag(flag1, flag2) * A --> C = A ^ -1 * B = A ^ -1 * diag(flag1, flag2) * A

diag(flag1, flag2) ~ C --> diag(flag1, flag2)的迹和行列式与C对应相等
"""
C = A.inverse() * B

print(f'p = {p}')
print(f'C = {str(C).replace(" ", ",").replace("\n", ",").replace("[,", "[")}')

# p = 9620154777088870694266521670168986508003314866222315790126552504304846236696183733266828489404860276326158191906907396234236947215466295418632056113826161
# C = ,analysis
一道简单的线性代数的问题,相关的分析在task的注释中。主要应用的就是相似矩阵的特性。
exp
from Crypto.Util.number import *
from gmpy2 import iroot

p = 9620154777088870694266521670168986508003314866222315790126552504304846236696183733266828489404860276326158191906907396234236947215466295418632056113826161
C = [
    ,
   
]

a, b, c, d = C, C, C, C
# tr = flag1 + flag2
tr = (a + d) % p
# det = flag1 * flag2
det = (a * d - b * c) % p

temp = iroot(tr ** 2 - 4 * det, 2)
flag1 = (tr + temp) // 2
flag2 = tr - flag1

flag = b'LILCTF{' + long_to_bytes(flag1) + long_to_bytes(flag2) + b'}'
print(flag)
# b'LILCTF{It_w4s_the_be5t_of_times_1t_wa5_the_w0rst_of_t1me5}'mid_math

task
from sage.all import *
from Crypto.Util.number import *
from tqdm import tqdm
from random import randint
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

flag = b'LILCTF{test_flag}'

p = getPrime(64)
P = GF(p)

key = randint(2 ** 62, p)
print(f"key = {key}")
def mul(vector, c):
    return * c, vector * c, vector * c, vector * c, vector * c]

v1 =
v2 =
v3 =
v4 =
v5 =
a, b, c, d, e = getPrime(64), getPrime(64), getPrime(64), getPrime(64),0

A = matrix(P, )
B = matrix(P, )
C = A.inverse() * B
D = C ** key

"""
B = [
    , a * v1, a * v1, a * v1, a * v1],
    , b * v2, b * v2, b * v2, b * v2],
    , c * v3, c * v3, c * v3, c * v3],
    , d * v4, d * v4, d * v4, d * v4],
   
]

   
   
B = * A
   
   

   
C = A ^ -1 * B = A ^ -1 * diag(a, b, c, d, 0) * A --> C ~ diag(a, b, c, d, 0) -->
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)
D.eigenvalue = C.eigenvalue ** key

"""
key = pad(long_to_bytes(key), 16)
aes = AES.new(key, AES.MODE_ECB)
msg = aes.encrypt(pad(flag, 64))

print(f"p = {p}")
print(f'C = {}'.replace('(', '[').replace(')', ']'))
print(f'D = {}'.replace('(', '[').replace(')', ']'))
print(f"msg = {msg}")

# p = 14668080038311483271
# C = [, , , , ]
# D = [, , , , ]
# 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
from sage.all import *
from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad, pad
import itertools

p = 14668080038311483271
C = [
    ,
    ,
    ,
    ,
   
]
D = [
    ,
    ,
    ,
    ,
   
]

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"

P = GF(p)

C = matrix(P, C)
D = matrix(P, D)

eigC = C.eigenvalues()
eigD = D.eigenvalues()

eigC =
eigD =

for lc, ld in itertools.product(eigC, eigD):
    try:
      key = discrete_log(ld, lc)
      if C ** key == D:
            print(f"key = {key}")
            break
    except (ValueError, ArithmeticError):
      continue

key = pad(long_to_bytes(int(key)), 16)
my_aes = AES.new(key, mode = AES.MODE_ECB)
flag = unpad(my_aes.decrypt(msg), 64)
print(flag)

"""
key = 5273966641785501202
b'LILCTF{Are_y0u_5till_4wake_que5t1on_m4ker!}'
"""baaaaaag

task
from Crypto.Util.number import *
import random
from Crypto.Cipher import AES
import hashlib
from Crypto.Util.Padding import pad
from secret import flag

p = random.getrandbits(72)
assert len(bin(p)) == 72

a =
b = 0
t = p
for i in a:
    temp = t % 2
    b += temp * i
    t = t >> 1

key = hashlib.sha256(str(p).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
flag = pad(flag,16)
ciphertext = cipher.encrypt(flag)

print(f'a = {a}')
print(f'b = {b}')
print(f"ciphertext = {ciphertext}")

'''
a =
b = 34962396275078207988771864327
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'
'''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
from sage.all import Matrix, ZZfrom Crypto.Util.number import *from Crypto.Cipher import AESimport hashlibfrom Crypto.Util.Padding import unpada = 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 = 2    L = 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)
页: [1]
查看完整版本: 2025LilCTF -- Crypto -- WriteUp