Skip to content

第三届黄河流域公安院校网络空间安全技能挑战赛

约 3578 字大约 12 分钟

crypto

2025-06-08

Sandwitch

简单padding的coppersmith

from Crypto.Util.number import *

n = 130210658110511504736422597261591182174531847806532340762131145212035478695205314931974421838392310731226415266775095601890938846830080329061111533796518633011922277343217149648494987341818402753017296362015915834670450122261511337212801488239810623226740266516836721952886027130703886460578247562781194524199
c = 58274335440051115211211273605191310114692293785750437685473044454042062899661976407492451518086227780147882738264722645944582899451063113444881286175099872016956825274378613983870549046907444680021237171113596116147511706486372974792692071549068969896395366667516390709069131700584308236332248449116109156503
e = 3

pad1 = b'easy_problem'
pad2 = b'How_to_solve_it'

P.<x> = PolynomialRing(Zmod(n))

f = ((bytes_to_long(pad1)*2^(15*8+39*8)+x*2^(15*8)+bytes_to_long(pad2))^e - c).monic()

roots = f.small_roots(X=2^(39*8),beta=0.5,epsilon=0.01)

print(long_to_bytes(int(roots[0])))
# b'flag{A_C0pper5mi1tH_4Ues7iOn_SplIt_Pad}'

因式分解

tellasecret.py

import string
from secret import hint
from secret import encrypt
import random

dicts = string.ascii_lowercase +"{=}"
key = (''.join([random.choice(dicts) for i in range(4)])) * 8

assert(len(hint) == 32)
assert(len(key) == 32)

cipher = encrypt(hint, key) # vigenere
print(cipher)

# cp=wmaunapgimjfpopeblvup=aywqygb

维吉尼亚解密,使用itertools的product(可重复遍历组合)而不是combination(不可重复遍历组合),对结果搜索tellasecret

import string
import itertools

dicts = string.ascii_lowercase +"{=}"
dicts1 = {i:index for index,i in enumerate(dicts)}
dicts2 = {index:i for index,i in enumerate(dicts)}

def vigenere_decrypt(cipher, key):
    message = ''
    for i in range(len(cipher)):
        message += dicts2[(dicts1[cipher[i]] - dicts1[key[i]]) % len(dicts)]
    return message

str = 'cp=wmaunapgimjfpopeblvup=aywqygb'

keys = itertools.product(dicts, repeat=4)
for k in keys:
    key = ''.join(k)*8
    message = vigenere_decrypt(str, key)
    print(message,file=open('output.txt','a'))

# tellasecret{a=secert}keepsilentt

因式分解.py

from Crypto.Util.number import *
from gmpy2 import*
from secret import flag,a,b,c

m = bytes_to_long(flag)
p = getPrime(256)
q = getPrime(256)
n = p * q
e = 65537
_q = int(bin(q)[2:][::-1] , 2)
c = pow(m,e,n)

print('n =',n)
print('c =',c)

'''
n = 7688109450918412752403544831281002390909833419780604228031807748258766149305710928557842935597759373483911172486806200079137977020089610947423466744079981
c = 6470273779347221033316093386019083111753019159457126878637258794718443144439812725263309232245307744208957171971247518708231996986359926490571921925899978
'''

assert a**3+b**3+c**3 == 3*a*b*c
gift = secert**3 - 9*secert + 8
print(gift)

assert 3*(p ^ _q) == a + b + c

#16174454302590604301534105361719250538317088773024913985896374029052621214070408075926265229111851489902642328975085914458074453963086159246933939207642987161923181946601656883349077418380372857072224674380642689142603970810010050

解方程得到secret,即得到a,又assert a**3+b**3+c**3 == 3*a*b*c -> a=b=c->p^_q =a,剪枝得p,q

import sympy
g = 16174454302590604301534105361719250538317088773024913985896374029052621214070408075926265229111851489902642328975085914458074453963086159246933939207642987161923181946601656883349077418380372857072224674380642689142603970810010050
a = sympy.Symbol('a')
f = a**3 - 9*a + 8 - g
result = sympy.solve([f],[a])[0][0]
print(result)

from Crypto.Util.number import *
e = 65537
n = 7688109450918412752403544831281002390909833419780604228031807748258766149305710928557842935597759373483911172486806200079137977020089610947423466744079981
c = 6470273779347221033316093386019083111753019159457126878637258794718443144439812725263309232245307744208957171971247518708231996986359926490571921925899978

p0_q = result
test = bin(p0_q)[2:].zfill(256)

def find(ph,qh,pl,ql):
    l = len(ph)
    tmp0 = int(ph + '0'*(256-2*l) + pl, 2)
    tmp1 = int(ph + '1'*(256-2*l) + pl, 2)

    tmq0 = int(qh + '0'*(256-2*l) + ql, 2)
    tmq1 = int(qh + '1'*(256-2*l) + ql, 2)

    if tmp0 * tmq0 > n:
        return
    if tmp1 * tmq1 < n:
        return
    if l>0 and int(pl,2)*int(ql,2) % 2**(l-1) != n % 2**(l-1):
        return

    if l == 128:
        p = tmp0
        if n % p == 0:
            q = n // p
            print(long_to_bytes(pow(c,inverse(e, (p-1)*(q-1)),n)))
            return
    else:
        if test[l] == "1" and test[255 - l] == "1":
            find(ph + "1", qh + "0", "1" + pl, "0" + ql)
            find(ph + "0", qh + "0", "1" + pl, "1" + ql)
            find(ph + "1", qh + "1", "0" + pl, "0" + ql)
            find(ph + "0", qh + "1", "0" + pl, "1" + ql)
        elif test[l] == "1" and test[255 - l] == "0":
            find(ph + "1", qh + "0", "0" + pl, "0" + ql)
            find(ph + "0", qh + "0", "0" + pl, "1" + ql)
            find(ph + "1", qh + "1", "1" + pl, "0" + ql)
            find(ph + "0", qh + "1", "1" + pl, "1" + ql)
        elif test[l] == "0" and test[255 - l] == "1":
            find(ph + "0", qh + "0", "1" + pl, "0" + ql)
            find(ph + "0", qh + "1", "0" + pl, "0" + ql)
            find(ph + "1", qh + "0", "1" + pl, "1" + ql)
            find(ph + "1", qh + "1", "0" + pl, "1" + ql)
        elif test[l] == "0" and test[255 - l] == "0":
            find(ph + "0", qh + "0", "0" + pl, "0" + ql)
            find(ph + "1", qh + "0", "0" + pl, "1" + ql)
            find(ph + "0", qh + "1", "1" + pl, "0" + ql)
            find(ph + "1", qh + "1", "1" + pl, "1" + ql)

find('','','','')
# b'flag{80a59062-9bbf-99a3-6af0-a24e94032163}'

Lattice

from Crypto.Util.number import *
from Crypto.Cipher import AES
import os
# from secret import flag
import numpy as np

flag = b"flag{fake_flag}"

def gen(q, n, N, sigma):
    t = np.random.randint(0, high=q // 2, size=n) 
    s = np.concatenate([np.ones(1, dtype=np.int32), t]) 
    A = np.random.randint(0, high=q // 2, size=(N, n)) 
    e = np.round(np.random.randn(N) * sigma**2).astype(np.int32) % q
    b = ((np.dot(A, t) + e).reshape(-1, 1)) % q
    P = np.hstack([b, -A])
    return P, s

def enc(P, M, q):
    N = P.shape[0]
    n = len(M)
    r = np.random.randint(0, 2, (n, N))
    Z = np.zeros((n, P.shape[1]), dtype=np.int32)
    Z[:, 0] = 1
    C = np.zeros((n, P.shape[1]), dtype=np.int32)
    for i in range(n):
        C[i] = (np.dot(P.T, r[i]) + (np.floor(q / 2) * Z[i] * M[i])) % q
    return C

q = 127
n = 3
N = int(1.1 * n * np.log(q))
sigma = 1.0

P, s = gen(q, n, N, sigma)

def prep(s):
    return np.array([int(b) for char in s for b in f"{ord(char):08b}"], dtype=np.int32)

hint = 
C = enc(P, prep(hint), q)
P = P.tolist()
C = C.tolist()
print(f"{P=}")
print(f"{C=}")

'''
P=[]
C=[]
'''

iv = 
key = os.urandom(16)
encrypted = AES.new(key=key, iv=iv, mode=AES.MODE_CBC).encrypt(b"".join([np.pad(i.encode(), 16) for i in flag]))

leak = 
print(leak)
print(key)
print(encrypted)

'''
-3.257518803980229925210589904230583482986646342139415561576950148286382674434770529248486501793457710730252401258721482142654716015216299244487794967600132597049154513815052213387666360825101667524635777006510550117512116441539852315185793280311905620746025669520152068447372368293640072502196959919309286241
b'\x8fj\x94\x98-\x1fd\xd5\x89\xbe\xa9*Tu\x90\xb7'
b'\x9fT@\xbc\x82\x8esQ\x1e\xd8\x1d\xdb\x9b\xb4\xf8rU\xc8\xa0\xcb\xaf H\xa9.\x04\x1e\xd2\x92\x1f\x0fBja-\x965x\xa8@\xc9x\xf9\xaf\x87\xd1\xa5}\xfc\x1b\xe0#\xc3m\xc9\x8973\x1c\x1f\x13\x8f\xb2a\xae\xa9]\xb9\xc2\xe8\x83A\x80\x13g\xc9a\x1c<\x8a\x9c&\xd9\xbd\x06\xef\xba9\xb0\x03\x9f\x022\xc9\x13\x9a\xffXPG\xc6o\xc0\xeaV7)XG9L\x84N7U\xe3Wn0G\x8e\xd3\x04(\n\x08\xb9\x17\xe6\xf1\xaa\xb7\x8a@$\x16\x13\x06A\x00\xc9Z\xdf\x7fQ\xc9\x08\xb4\xf3P\xfcpe\xe2\xeb\x96\x0e(-\xde\x17\xd1\x01\x1c_\x82\x8b\x9fw\xc8\x86\xfbw\xb5\xf7\xd0\xc8\x1784\xe3?\x00\x0b.)\xb7\xbc\x8e{\xe0\xae\x8d$\x0f\x19\'\xb6\xee@d\x00\xd9\x84\x8c\x0e\xa3,\xc6a\xa3\xba*1\xfd<\xfd\x18\xd6\x9e\x8c4\x8e#\xfd\xbd&0R\xeddE,\xed\xb6\x1e\x00\x11\xa6K\xd3\x1dT\x8c5\x8e\x00\xea\x10\xe9\'u"B#\xa1#\xd8\xe3\xf5j\xbc\x94M\xda\xe3\xcb*\xf0W1\xa0\x80\x1d\xfc\xbfo\x01?(da\r\xb6\x86\xd0\x90\x88Z\xa1`B\x89\x89\x89\xb3v\xa5\xf0\xe0\x0c\x8e\xcc+P\xfc\xfd#\x83\xe9\x93\x96\n\xf2\xa5\xfb\xc3\xc5\xaa\x9e\x89\x93\xb6\xf5\xea\x8c%NY\xc3\x0eR\xfas\xa1\x13\xf2/*\xce\x8b_:_r\xeb\xbe\x0b\x8a\x8c\x97\x7f|m}\xae\xa9I\x95\xcc\xe7\x80\xa5yC4\x1f5\xa4P\xc5\xbf.\xf9V\xe8|\xbb\xc3\xcb\x98&\'JB\x99\x94\xc0\r$\x0b\xbe48u\xeb\xca\xa1\xfbb\xd8_R\x97\x8e\xaeI\xfc\xc2\xb2\xd2#@\xec\x16\xf1\xd7eCQ\x1cO\x13\xca\xb5\xd3\x1a\xb1\xf1_D\x80\x06\xa5\xbe\xbev\xbd\xd6\xbb\x9a\xc9x\x9cf:\xcb>\xa2\xe1\xcad\xde]aw\xa0\xdc\xb2\xb3{+\x85\x8d\x8b\xc5\rT\xcc\xd9X\xd5\x9b\r<\x99m\xb8b6s\xbfp\x0eo~\xe9&\xb2{\xbe\xee\x93\xd2N1\\\x94\x968IWO7\xcb\xb6e\x80\xf7\x9air\xb2~\x17\x1cF\x0f\x82T]RBX\xdex\x13\x85\xfa\xcd-\xce\xdc\xe4\xe5^\x99u\xb5\x01\xd0-\xc3C\xcd\xc4y6\xb7\x9d|L1\xe74\xf7\x8cH\xe9\xa9\xfav\n\xec;\xf2\xa2w\xfb\x13_b\r)z!\xa3\xc8\xa8\xc2\xd2\x10\x00\x11\x11\r\xb2&\xfb\x04&\x84">x6l[\x06n>\xa0\xbe\x9c`\xa7\x9e\xe0\xfb\x85\x91\xc4,\xcf\xac\xe11@a\xed3@\xfd}\x8e\xfaTp\xcb7\xe7\xbf\xd4\xe0~b\xd9\xe0<\xba\x81\xd4"e\xfc\x939|j#0H\x86\xf8\x0b\x03\xd2\xe8\xf5\xe55\xdc\xc8\x06\\\xb7)\xcc\x9b\'\xf12'
'''

解法一

第一段:LWE

from sage.modules.free_module_integer import IntegerLattice
import numpy as np

# ====slove_t====
def Babai(B, t):
    B = IntegerLattice(B, lll_reduce=True).reduced_basis
    G = B.gram_schmidt()[0]
    b = t
    for i in reversed(range(B.ncols())):
        b -=  B[i] * ((b * G[i]) / (G[i] * G[i])).round()
    return t - b

P=[[87, -27, -52, -29], [57, -41, -24, -60], [76, -17, -55, -37], [75, -46, -33, -21], [121, -55, -33, -34], [47, -4, -34, -45], [112, -33, -44, -16], [74, -44, -5, -25], [20, -21, -16, -49], [89, -21, -54, -24], [18, -23, -53, -1], [35, -40, -4, -29], [105, -54, -2, -8], [44, -24, -43, -36], [111, -15, -15, -54]]
P = np.array(P)
A_list= list(-P[:,1:])
b_list= list(P[:,0])
q = 127 

# b = A*x+e mod q
A = matrix(ZZ, A_list)
b = vector(ZZ, b_list)
r = A.nrows()
c = A.ncols()

pIr = q*identity_matrix(r)
M = block_matrix([[pIr], [A.transpose()]])  
br = Babai(M, b)
print(f'e = {b-br}')
R = IntegerModRing(q)
Ar = matrix(R, A_list)
t = Ar.solve_right(br)
print(f't = {t}')
s = np.concatenate([np.ones(1, dtype=np.int32), t])

# e = (0, 1, -1, 1, 0, -1, 1, 0, 0, -1, -1, 0, -1, 0, 1)
# t = (26, 24, 54)

第二段:hint

from Crypto.Util.number import long_to_bytes

# ====slove_hint====
s = np.concatenate([np.ones(1, dtype=np.int32), t])
C=[]
m = list(np.dot(C,s) % q)

hint=''
for i in m: 
    if int(i) > q - 15 or int(i) < 15:
        hint += '0'
    else:
        hint += '1'
print(long_to_bytes(int(hint, 2)))
# b"Congratulations,you're amazing!Here's a hint: sin(iv) + leak * cos(iv) = 0, keep it up! @V@"

第三段:三角格规约求iv

from Crypto.Util.number import long_to_bytes

# ====slove_iv====
t = 3.257518803980229925210589904230583482986646342139415561576950148286382674434770529248486501793457710730252401258721482142654716015216299244487794967600132597049154513815052213387666360825101667524635777006510550117512116441539852315185793280311905620746025669520152068447372368293640072502196959919309286241
a = arctan(t)
ts = 2^1024

A = int(a*ts)
Pi = int((pi).n(1024)*ts)

G = Matrix([[1,0,-ts],[0,1,int(Pi)],[0,0,A]])
m = G.LLL()[0][0]
iv = long_to_bytes(int(m))
print(f'iv = {iv}')

# b'?\xaa =t\xbc\xddQ\xac/yq\x13\xc3\x7f\xb9'

第四段:AES解密+unpad

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad

iv = b'?\xaa =t\xbc\xddQ\xac/yq\x13\xc3\x7f\xb9'
key = b'\x8fj\x94\x98-\x1fd\xd5\x89\xbe\xa9*Tu\x90\xb7'
c = b'\x9fT@\xbc\x82\x8esQ\x1e\xd8\x1d\xdb\x9b\xb4\xf8rU\xc8\xa0\xcb\xaf H\xa9.\x04\x1e\xd2\x92\x1f\x0fBja-\x965x\xa8@\xc9x\xf9\xaf\x87\xd1\xa5}\xfc\x1b\xe0#\xc3m\xc9\x8973\x1c\x1f\x13\x8f\xb2a\xae\xa9]\xb9\xc2\xe8\x83A\x80\x13g\xc9a\x1c<\x8a\x9c&\xd9\xbd\x06\xef\xba9\xb0\x03\x9f\x022\xc9\x13\x9a\xffXPG\xc6o\xc0\xeaV7)XG9L\x84N7U\xe3Wn0G\x8e\xd3\x04(\n\x08\xb9\x17\xe6\xf1\xaa\xb7\x8a@$\x16\x13\x06A\x00\xc9Z\xdf\x7fQ\xc9\x08\xb4\xf3P\xfcpe\xe2\xeb\x96\x0e(-\xde\x17\xd1\x01\x1c_\x82\x8b\x9fw\xc8\x86\xfbw\xb5\xf7\xd0\xc8\x1784\xe3?\x00\x0b.)\xb7\xbc\x8e{\xe0\xae\x8d$\x0f\x19\'\xb6\xee@d\x00\xd9\x84\x8c\x0e\xa3,\xc6a\xa3\xba*1\xfd<\xfd\x18\xd6\x9e\x8c4\x8e#\xfd\xbd&0R\xeddE,\xed\xb6\x1e\x00\x11\xa6K\xd3\x1dT\x8c5\x8e\x00\xea\x10\xe9\'u"B#\xa1#\xd8\xe3\xf5j\xbc\x94M\xda\xe3\xcb*\xf0W1\xa0\x80\x1d\xfc\xbfo\x01?(da\r\xb6\x86\xd0\x90\x88Z\xa1`B\x89\x89\x89\xb3v\xa5\xf0\xe0\x0c\x8e\xcc+P\xfc\xfd#\x83\xe9\x93\x96\n\xf2\xa5\xfb\xc3\xc5\xaa\x9e\x89\x93\xb6\xf5\xea\x8c%NY\xc3\x0eR\xfas\xa1\x13\xf2/*\xce\x8b_:_r\xeb\xbe\x0b\x8a\x8c\x97\x7f|m}\xae\xa9I\x95\xcc\xe7\x80\xa5yC4\x1f5\xa4P\xc5\xbf.\xf9V\xe8|\xbb\xc3\xcb\x98&\'JB\x99\x94\xc0\r$\x0b\xbe48u\xeb\xca\xa1\xfbb\xd8_R\x97\x8e\xaeI\xfc\xc2\xb2\xd2#@\xec\x16\xf1\xd7eCQ\x1cO\x13\xca\xb5\xd3\x1a\xb1\xf1_D\x80\x06\xa5\xbe\xbev\xbd\xd6\xbb\x9a\xc9x\x9cf:\xcb>\xa2\xe1\xcad\xde]aw\xa0\xdc\xb2\xb3{+\x85\x8d\x8b\xc5\rT\xcc\xd9X\xd5\x9b\r<\x99m\xb8b6s\xbfp\x0eo~\xe9&\xb2{\xbe\xee\x93\xd2N1\\\x94\x968IWO7\xcb\xb6e\x80\xf7\x9air\xb2~\x17\x1cF\x0f\x82T]RBX\xdex\x13\x85\xfa\xcd-\xce\xdc\xe4\xe5^\x99u\xb5\x01\xd0-\xc3C\xcd\xc4y6\xb7\x9d|L1\xe74\xf7\x8cH\xe9\xa9\xfav\n\xec;\xf2\xa2w\xfb\x13_b\r)z!\xa3\xc8\xa8\xc2\xd2\x10\x00\x11\x11\r\xb2&\xfb\x04&\x84">x6l[\x06n>\xa0\xbe\x9c`\xa7\x9e\xe0\xfb\x85\x91\xc4,\xcf\xac\xe11@a\xed3@\xfd}\x8e\xfaTp\xcb7\xe7\xbf\xd4\xe0~b\xd9\xe0<\xba\x81\xd4"e\xfc\x939|j#0H\x86\xf8\x0b\x03\xd2\xe8\xf5\xe55\xdc\xc8\x06\\\xb7)\xcc\x9b\'\xf12'
aes = AES.new(key=key, iv=iv, mode=AES.MODE_CBC)
m = aes.decrypt(c)
mm = [m[i:i + 16] for i in range(0, len(m), 16)]
flag = b''.join([unpad(i, 16) for i in mm])
print(flag)
# b'flag{6ef25d1e-bb76-8e53-dbc4-1e56585f9aa9}'

解法二

CBC的特征+flag的第一个字符f被pad为16位,直接异或出iv

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

encrypted = b'\x9fT@\xbc\x82\x8esQ\x1e\xd8\x1d\xdb\x9b\xb4\xf8rU\xc8\xa0\xcb\xaf H\xa9.\x04\x1e\xd2\x92\x1f\x0fBja-\x965x\xa8@\xc9x\xf9\xaf\x87\xd1\xa5}\xfc\x1b\xe0#\xc3m\xc9\x8973\x1c\x1f\x13\x8f\xb2a\xae\xa9]\xb9\xc2\xe8\x83A\x80\x13g\xc9a\x1c<\x8a\x9c&\xd9\xbd\x06\xef\xba9\xb0\x03\x9f\x022\xc9\x13\x9a\xffXPG\xc6o\xc0\xeaV7)XG9L\x84N7U\xe3Wn0G\x8e\xd3\x04(\n\x08\xb9\x17\xe6\xf1\xaa\xb7\x8a@$\x16\x13\x06A\x00\xc9Z\xdf\x7fQ\xc9\x08\xb4\xf3P\xfcpe\xe2\xeb\x96\x0e(-\xde\x17\xd1\x01\x1c_\x82\x8b\x9fw\xc8\x86\xfbw\xb5\xf7\xd0\xc8\x1784\xe3?\x00\x0b.)\xb7\xbc\x8e{\xe0\xae\x8d$\x0f\x19\'\xb6\xee@d\x00\xd9\x84\x8c\x0e\xa3,\xc6a\xa3\xba*1\xfd<\xfd\x18\xd6\x9e\x8c4\x8e#\xfd\xbd&0R\xeddE,\xed\xb6\x1e\x00\x11\xa6K\xd3\x1dT\x8c5\x8e\x00\xea\x10\xe9\'u"B#\xa1#\xd8\xe3\xf5j\xbc\x94M\xda\xe3\xcb*\xf0W1\xa0\x80\x1d\xfc\xbfo\x01?(da\r\xb6\x86\xd0\x90\x88Z\xa1`B\x89\x89\x89\xb3v\xa5\xf0\xe0\x0c\x8e\xcc+P\xfc\xfd#\x83\xe9\x93\x96\n\xf2\xa5\xfb\xc3\xc5\xaa\x9e\x89\x93\xb6\xf5\xea\x8c%NY\xc3\x0eR\xfas\xa1\x13\xf2/*\xce\x8b_:_r\xeb\xbe\x0b\x8a\x8c\x97\x7f|m}\xae\xa9I\x95\xcc\xe7\x80\xa5yC4\x1f5\xa4P\xc5\xbf.\xf9V\xe8|\xbb\xc3\xcb\x98&\'JB\x99\x94\xc0\r$\x0b\xbe48u\xeb\xca\xa1\xfbb\xd8_R\x97\x8e\xaeI\xfc\xc2\xb2\xd2#@\xec\x16\xf1\xd7eCQ\x1cO\x13\xca\xb5\xd3\x1a\xb1\xf1_D\x80\x06\xa5\xbe\xbev\xbd\xd6\xbb\x9a\xc9x\x9cf:\xcb>\xa2\xe1\xcad\xde]aw\xa0\xdc\xb2\xb3{+\x85\x8d\x8b\xc5\rT\xcc\xd9X\xd5\x9b\r<\x99m\xb8b6s\xbfp\x0eo~\xe9&\xb2{\xbe\xee\x93\xd2N1\\\x94\x968IWO7\xcb\xb6e\x80\xf7\x9air\xb2~\x17\x1cF\x0f\x82T]RBX\xdex\x13\x85\xfa\xcd-\xce\xdc\xe4\xe5^\x99u\xb5\x01\xd0-\xc3C\xcd\xc4y6\xb7\x9d|L1\xe74\xf7\x8cH\xe9\xa9\xfav\n\xec;\xf2\xa2w\xfb\x13_b\r)z!\xa3\xc8\xa8\xc2\xd2\x10\x00\x11\x11\r\xb2&\xfb\x04&\x84">x6l[\x06n>\xa0\xbe\x9c`\xa7\x9e\xe0\xfb\x85\x91\xc4,\xcf\xac\xe11@a\xed3@\xfd}\x8e\xfaTp\xcb7\xe7\xbf\xd4\xe0~b\xd9\xe0<\xba\x81\xd4"e\xfc\x939|j#0H\x86\xf8\x0b\x03\xd2\xe8\xf5\xe55\xdc\xc8\x06\\\xb7)\xcc\x9b\'\xf12'

message_pad = pad(b'f', 16)
key = b'\x8fj\x94\x98-\x1fd\xd5\x89\xbe\xa9*Tu\x90\xb7'

myaes = AES.new(key, AES.MODE_ECB)

iv = bytes([a^b for a, b in zip(myaes.decrypt(encrypted[:16]), message_pad)])
print(iv)
c = b'\x9fT@\xbc\x82\x8esQ\x1e\xd8\x1d\xdb\x9b\xb4\xf8rU\xc8\xa0\xcb\xaf H\xa9.\x04\x1e\xd2\x92\x1f\x0fBja-\x965x\xa8@\xc9x\xf9\xaf\x87\xd1\xa5}\xfc\x1b\xe0#\xc3m\xc9\x8973\x1c\x1f\x13\x8f\xb2a\xae\xa9]\xb9\xc2\xe8\x83A\x80\x13g\xc9a\x1c<\x8a\x9c&\xd9\xbd\x06\xef\xba9\xb0\x03\x9f\x022\xc9\x13\x9a\xffXPG\xc6o\xc0\xeaV7)XG9L\x84N7U\xe3Wn0G\x8e\xd3\x04(\n\x08\xb9\x17\xe6\xf1\xaa\xb7\x8a@$\x16\x13\x06A\x00\xc9Z\xdf\x7fQ\xc9\x08\xb4\xf3P\xfcpe\xe2\xeb\x96\x0e(-\xde\x17\xd1\x01\x1c_\x82\x8b\x9fw\xc8\x86\xfbw\xb5\xf7\xd0\xc8\x1784\xe3?\x00\x0b.)\xb7\xbc\x8e{\xe0\xae\x8d$\x0f\x19\'\xb6\xee@d\x00\xd9\x84\x8c\x0e\xa3,\xc6a\xa3\xba*1\xfd<\xfd\x18\xd6\x9e\x8c4\x8e#\xfd\xbd&0R\xeddE,\xed\xb6\x1e\x00\x11\xa6K\xd3\x1dT\x8c5\x8e\x00\xea\x10\xe9\'u"B#\xa1#\xd8\xe3\xf5j\xbc\x94M\xda\xe3\xcb*\xf0W1\xa0\x80\x1d\xfc\xbfo\x01?(da\r\xb6\x86\xd0\x90\x88Z\xa1`B\x89\x89\x89\xb3v\xa5\xf0\xe0\x0c\x8e\xcc+P\xfc\xfd#\x83\xe9\x93\x96\n\xf2\xa5\xfb\xc3\xc5\xaa\x9e\x89\x93\xb6\xf5\xea\x8c%NY\xc3\x0eR\xfas\xa1\x13\xf2/*\xce\x8b_:_r\xeb\xbe\x0b\x8a\x8c\x97\x7f|m}\xae\xa9I\x95\xcc\xe7\x80\xa5yC4\x1f5\xa4P\xc5\xbf.\xf9V\xe8|\xbb\xc3\xcb\x98&\'JB\x99\x94\xc0\r$\x0b\xbe48u\xeb\xca\xa1\xfbb\xd8_R\x97\x8e\xaeI\xfc\xc2\xb2\xd2#@\xec\x16\xf1\xd7eCQ\x1cO\x13\xca\xb5\xd3\x1a\xb1\xf1_D\x80\x06\xa5\xbe\xbev\xbd\xd6\xbb\x9a\xc9x\x9cf:\xcb>\xa2\xe1\xcad\xde]aw\xa0\xdc\xb2\xb3{+\x85\x8d\x8b\xc5\rT\xcc\xd9X\xd5\x9b\r<\x99m\xb8b6s\xbfp\x0eo~\xe9&\xb2{\xbe\xee\x93\xd2N1\\\x94\x968IWO7\xcb\xb6e\x80\xf7\x9air\xb2~\x17\x1cF\x0f\x82T]RBX\xdex\x13\x85\xfa\xcd-\xce\xdc\xe4\xe5^\x99u\xb5\x01\xd0-\xc3C\xcd\xc4y6\xb7\x9d|L1\xe74\xf7\x8cH\xe9\xa9\xfav\n\xec;\xf2\xa2w\xfb\x13_b\r)z!\xa3\xc8\xa8\xc2\xd2\x10\x00\x11\x11\r\xb2&\xfb\x04&\x84">x6l[\x06n>\xa0\xbe\x9c`\xa7\x9e\xe0\xfb\x85\x91\xc4,\xcf\xac\xe11@a\xed3@\xfd}\x8e\xfaTp\xcb7\xe7\xbf\xd4\xe0~b\xd9\xe0<\xba\x81\xd4"e\xfc\x939|j#0H\x86\xf8\x0b\x03\xd2\xe8\xf5\xe55\xdc\xc8\x06\\\xb7)\xcc\x9b\'\xf12'
key = b'\x8fj\x94\x98-\x1fd\xd5\x89\xbe\xa9*Tu\x90\xb7'
myaes = AES.new(key=key, iv=iv, mode=AES.MODE_CBC)

decrypted_bytes = myaes.decrypt(c)
# print(decrypted_bytes)
messages = [decrypted_bytes[i:i + 16] for i in range(0, len(decrypted_bytes), 16)]
flag = "".join([chr(message[0]) for message in messages])
print(flag)
# flag{6ef25d1e-bb76-8e53-dbc4-1e56585f9aa9}

Happy

task.py

#!/usr/bin/env python
# Simplify the problem by happy4321
import os, utils
from secret import flag
assert flag.startswith(b'flag{') and flag.endswith(b'}')

seed = int(os.urandom(16).hex(), 16)
gen = utils.Gen(seed)
msg = b'Happy4321: ' + flag
enc = bytes(m ^ next(gen) for m in msg).hex()
print(enc)
# cd1dd7c7a9cfe3c0067ff64694e64c38aa759c81d1c8f48cf6f7ee1df2d1e58584da52644ea56bd24dadca6bd5a6899a92b118f57de2529670264d48

utils.py

class Gen:
    def __init__(self, state):
        self.nbits = 128
        self.state = state & ((1 << self.nbits) - 1)
        self.mask = 109908700282042807039366676242995409413

    def func0(self, steps=1):
        for _ in range(steps):
            res = self.state & self.mask
            bit = sum([(res >> i) & 1 for i in range(self.nbits)]) & 1
            self.state = ((self.state << 1) ^ bit) & ((1 << self.nbits) - 1)
        return bit

    def __next__(self):
        out = 0
        for _ in range(8):
            bit = self.func0(2023)
            out = (out << 1) ^ bit
        return out

Analyse:

seed转换为1x128的矩阵

则变换矩阵为含mask的128x128矩阵,在GF(2)上有:

[staten][Omask0Imask1+]=[staten+1]\begin{bmatrix} state_n \\ \end{bmatrix} \begin{bmatrix} O & mask_0 \\ I & mask_{1+} \\ \end{bmatrix} = \begin{bmatrix} state_{n+1} \\ \end{bmatrix}

Exp:

(直接把class Gen复制进来跑出来的是乱码😕)

# sagemath 10.6
from Crypto.Util.number import *

enc = 'cd1dd7c7a9cfe3c0067ff64694e64c38aa759c81d1c8f48cf6f7ee1df2d1e58584da52644ea56bd24dadca6bd5a6899a92b118f57de2529670264d48'
mask = 109908700282042807039366676242995409413

flag_know = b'Happy4321: flag{'
enc_know = bytes.fromhex(enc)[:16]

leak = ''.join([bin(i)[2:].zfill(8) for i in [a^^b for a,b in zip(flag_know,enc_know)]])
mask = bin(mask)[2:].zfill(128)

def get_seed(leak,mask):
    change_m = matrix(GF(2),128,128)
    for i in range(127):
        change_m[i+1,i] = 1
    for i in range(128):
        change_m[i,-1] = mask[i]

    M = list()
    for i in range(16*8):
        M.append((change_m ^ (2023*(i+1))).T[-1].list())

    seed = ''.join(map(str,(matrix(GF(2),list(leak)) / matrix(GF(2),M).T).list()))
    return int(seed,2)

seed = get_seed(leak,mask)
print(f'seed = {seed}')

import utils
gen = utils.Gen(seed)
enc = bytes.fromhex(enc)

flag = bytes(e ^^ next(gen) for e in enc)
print(flag)
# Happy4321: flag{The_matrix_is_as_charming_as_the_starry_sky}