博客 / 詳情

返回

記2025鵬城杯CTF線上賽部分題目

0.前言

這次鵬城杯真的是燃盡了,能不能進線下就看命了

1.cry

1.1 babyrsa

一道典型的RSA 密鑰恢復題目,具體來説,它是利用高精度浮點數泄露來還原私鑰參數的題目,題目給出了一個名為 leak 的變量,其計算公式為

這道題之所以會發生泄露,核心原因在於:題目給出的十進制小數精度遠大於還原分數所需的信息量

簡單來説,是因為給的小數點後的位數太多了,多到足以精確地反向推算出原本的分子和分母,舉個例子來説:

低精度假設原本分數是 1/3,但我只告訴你 0.3

你無法確定是 1/3,還是3/10,這就很安全,因為精度丟失了。

但是高精度:假設原本分數是 1/3,我告訴你 0.33333333...給了你足夠的位數,你會發現只有 1/3

這個簡單的分數能完美匹配這一長串數字,而不是 3333/10000這種複雜的數字

這道題,分母只需要約617 位就能表示,題目卻給了1024 位的信息

1024 > 617,這多出來的 400 多位精度,保證了我們可以毫無歧義地將這個小數轉回唯一的那個分數

exp.py

import decimal
from Crypto.Util.number import long_to_bytes
​
# --- 題目數據 ---
leak_str = "1.396995694831414203476063690838730308815841662737318558906107823553922718340982125801595368449608188770051881765292978548960520326036779130167518285237817101541807766017642530065080930654694948943506714268685400709580398894902693407016988670394423892586264077247263710263220932577837642377245651448838665854362532801659965471421937839336237670710012298796758992931116659292915200628873553198226185187089027680973673618973869464164460226697625936493428822424637497370197316811245879504779934098600596822159243994319583651080005054538419168988020562590543262648544970376255020489363894055887067948343768399654357738592577280906555896933717091837896978973488220368081406433117367524537063718421897982643644320078600517763936883820416362057895941185749296170109172249907094176821124345672294602380784325702476105763209165109703429326132417850746805701054961710623030742187505484821961670922386999933202645522248608323217011522889282323071281405301772218220381951540118124201599862330377374571641729649420917168701463539034702411"
d = 16306054997613721520756151430779642117683661431522665108784419231044104572118893098180652730976905729602478591047033305251624752030036736271198006715513694904231940253554804069707679445942892410812386221633728427239116007373836662495075237456279818311659331982404534490546781763464409713789636372508503902598331950861474527128323735250673137355260113147338636761737748874105625008482750923429512271416511835596944209137554445130949731646669691366003832655082535985891463876904334888009751956386994969339847254470145428608062575606120441725590059524749595027078238962391188809496875025237129899849787699468205026040721
c = 7908369000608075306226552240713890041649799894903074579356627811865842237315201153498579205223600526520994811661608630888045462921547166872107507948062717836952855804806976414887413729060431265217539895710936669089248515746191716161194996469977577048602427553584286064475300979649416171469313168995504717602670924606819204605601860560767900702512753735554900344201907921239415885901489708576066483012272256175573658509614344875077232108364134161997767814675830320630271209201503987787921279932886374846298269125068817280777403718279754392091441050281244934594776307137448975055247018414699621410668188864774860026941
​
# --- 求解腳本 ---
# 設置足夠的精度 (大於leak的位數)
decimal.getcontext().prec = 5000 
L = decimal.Decimal(leak_str)
​
# 嘗試常見的 e 值
e_list = [65537, 3, 5, 17, 257]
​
print("開始尋找 flag ...")
​
for e in e_list:
    # k 的範圍通常在 1 到 e 之間
    for k in range(1, e):
        # 檢查 k 是否能整除 e*d - 1
        if (e * d - 1) % k == 0:
            phi = (e * d - 1) // k
            
            # 使用一元二次方程求 q 的近似值: L*q^2 - (L+1)*q + (1-phi) = 0
            # 判別式 delta = (L+1)^2 - 4*L*(1-phi)
            #           = (L+1)^2 + 4*L*(phi-1)
            term1 = (L + 1) ** 2
            term2 = 4 * L * (decimal.Decimal(phi) - 1)
            delta = term1 + term2
            
            if delta < 0:
                continue
            
            # 求解正根 (q 是大素數,取正號)
            sqrt_delta = delta.sqrt()
            q_approx = (L + 1 + sqrt_delta) / (2 * L)
            
            # 轉為整數並搜索附近的整數
            q_int = int(q_approx)
            
            # 搜索範圍可以很小,因為 leak 精度極高
            for q_cand in range(q_int - 2, q_int + 3):
                if q_cand < 2: continue
                
                # 驗證: (q-1) 必須整除 phi
                if phi % (q_cand - 1) == 0:
                    p_cand = phi // (q_cand - 1) + 1
                    n = p_cand * q_cand
                    
                    try:
                        # 嘗試解密
                        m_int = pow(c, d, n)
                        m_bytes = long_to_bytes(m_int)
                        
                        # 檢查 flag 特徵
                        if b'ISCTF' in m_bytes or b'flag' in m_bytes:
                            print(f"\n[+] 成功找到 Flag (e={e}, k={k})")
                            print(f"[+] Flag: {m_bytes.decode()}")
                            exit()
                    except Exception:
                        pass
print("[-] 未找到 Flag,請檢查輸入數據或參數。")

1.2 peco

這是一道複合型密碼學題目,融合了多種數論和格密碼攻擊技術

主要類型可以歸納為:RSA 密鑰恢復 + 不定方程求解 + 格格歸約

基本思路就是

1.解不定方程→獲得 x,y

2.Hensel Lifting亨澤爾引理 + Coppersmith →分解 n→解密得到 m

3.構造 Lattice 使用 LL→求解 f0,f1→拼接得到 Flag

exp.py

import sys
​
# 手動實現 long_to_bytes
def long_to_bytes(val, endianness='big'):
    val = int(val)
    if val == 0: return b'\x00'
    width = (val.bit_length() + 7) // 8
    return val.to_bytes(width, byteorder=endianness)
​
# --- 題目數據 ---
n = 18443962106578943927922829208562388331564422618353954662348987125496135728205879853444693999188714508145409575298801277623433658530589571956301880815632542860363148763704636874275223979061507756787642735086825973011622866458454405794279633717255674221895468734500735123736684346340314680683830866884050311047424068122453972745273167956795195575475691048908906061023817574695902603984554911326264947716547564759877947888574515784489778380086664649338093680740990860192640619047071160362288611331225632270531304525264824445326394068892806774552310748255977040249822464839809344521107040968321810533993659358229305320413
c = 8176283809770578639445916571748890916863681496488338436815389781344271720445865752568007651231910205530735296305471880971422173915403956857863330698931559658909826642456860761540607878553228782799635976463090037022164739976302533892173751687781100980039065722082091714141141136171701360981540040678479802206949078162548124224838019262997441233919136963696523351831737708850863538007579105976954619102728135600542584651031405327214877358323388674864043740117718200022790892542634633918493245432384562983429810936975869853596007429259749282607844407676244954057886824475948603911174707176467261179324130051317766768127
gift1_A = 1293023064232431070902426583269468463
gift1_B = 105279230912868770223946474836383391725923
gift2 = 26161714402997656593966327522661504448812191236385246127313450633226841096347099194721417620572738092514050785292503472019045698167235604357096118735431692892202119807587271344465029467089266358735895706496467947787464475365718387614
e = 65537
​
# --- 全局變量存儲結果 ---
val_x = None
val_y = None
p_found = None
q_found = None
m_dec = None
​
print("=== 步驟 1: 求解佩爾方程 x, y ===")
# 你的日誌顯示這步已經成功了,我保留代碼以確保完整性
g = gcd(gift1_A, gift1_B)
A_prime = gift1_A // g
B_prime = gift1_B // g
D = A_prime * B_prime
K.<sqrtD> = QuadraticField(D)
​
try:
    unit = K.units()[0]
    # 轉換為整數單元
    curr = unit
    u, v = 0, 0
    # 嘗試幾次冪來消除分母 (通常 1 或 2 次即可)
    for _ in range(6):
        try:
            u = ZZ(curr[0])
            v = ZZ(curr[1])
            break
        except TypeError:
            curr = curr * unit
    else:
        print("[-] 無法找到整數解,跳過 x,y 求解 (如果之前已算出可手動填入)")
        
    if u**2 - D*v**2 == -1:
        u, v = u**2 + D*v**2, 2*u*v
        
    val_x = u
    val_y = A_prime * v
    print(f"[+] 找到 x: {str(val_x)[:30]}...")
    print(f"[+] 找到 y: {str(val_y)[:30]}...")
​
except Exception as e:
    print(f"[-] Pell 求解出錯: {e}")
​
if val_x is not None:
    print("\n=== 步驟 2: Hensel Lifting 恢復 p 低位 ===")
    p_cands = [1]
    mod_limit_bits = 777
    
    for k in range(1, mod_limit_bits):
        next_mod = 1 << (k + 1)
        new_cands = []
        for val in p_cands:
            for bit in [0, 1]:
                cand = val | (bit << k)
                try:
                    # 驗證 p^7 + (n/p)^13 == gift2
                    inv_p = inverse_mod(cand, next_mod)
                    q_val = (n * inv_p) % next_mod
                    lhs = (pow(cand, 7, next_mod) + pow(q_val, 13, next_mod)) % next_mod
                    if lhs == (gift2 % next_mod):
                        new_cands.append(cand)
                except: pass
        p_cands = new_cands
        if not p_cands:
            print(f"[-] Lifting 在第 {k} 位中斷")
            break
            
    print(f"[+] Lifting 完成,候選數量: {len(p_cands)}")
    
    print("\n=== 步驟 3: Coppersmith 恢復完整 p ===")
    P_poly.<x_poly> = PolynomialRing(Zmod(n))
    
    # 遍歷所有候選 p0
    for idx, p0 in enumerate(p_cands):
        print(f"[*] 正在嘗試候選 {idx+1}/{len(p_cands)} ...")
        
        # 構造多項式 f(x) = p0 + x * 2^777
        f = p0 + x_poly * (1 << mod_limit_bits)
        f = f.monic()
        
        # 【關鍵優化】
        # 未知位數 = 1024 - 777 = 247 bits
        # 設置 X 為 2^250 (略大於247),beta 為 0.4
        # 只要 X < N^(beta^2) 即可。N^0.16 ≈ 320 bits > 250 bits,條件滿足且計算快。
        try:
            roots = f.small_roots(X=2**250, beta=0.4)
            if roots:
                p_high = int(roots[0])
                p_check = p0 + p_high * (1 << mod_limit_bits)
                if n % p_check == 0:
                    p_found = p_check
                    q_found = n // p_check
                    print(f"[+] 成功分解 n !")
                    break
        except Exception as e:
            print(f"[-] Coppersmith 錯誤: {e}")
            continue
​
    if p_found:
        print("\n=== 步驟 4: RSA 解密 m ===")
        phi = (p_found - 1) * (q_found - 1)
        d_rsa = inverse_mod(e, phi)
        m_dec = pow(c, d_rsa, n)
        print(f"[+] m = {m_dec}")
        
        print("\n=== 步驟 5: LLL 求解 Flag ===")
        # 構造格矩陣
        M = Matrix(ZZ, [
            [1, 0, val_x],
            [0, 1, val_y],
            [0, 0, m_dec]
        ])
        
        print("[*] 正在執行 LLL ...")
        L = M.LLL()
        
        print("[*] 搜索結果向量 ...")
        for row in L:
            f0_cand = abs(row[0])
            f1_cand = abs(row[1])
            r_cand = abs(row[2])
            
            # 題目約束 r < 2^99,這裏放寬一點檢查
            if r_cand < 2**110:
                s0 = long_to_bytes(int(f0_cand))
                s1 = long_to_bytes(int(f1_cand))
                
                # 檢查所有可能的拼接組合
                cands = [s0 + s1, s1 + s0]
                for flag_bytes in cands:
                    if b"flag{" in flag_bytes or b"ISCTF" in flag_bytes:
                        print(f"\n[SUCCESS] Flag: {flag_bytes.decode(errors='ignore')}")
                        sys.exit(0)
        
        print("[-] 未能自動識別 Flag,請手動檢查以下向量:")
        for row in L[:3]:
            print(row)
    else:
        print("[-] 未能分解 n")

2.misc

2.1 blue

給了一張圖片,但是啥都看不清

提取blue部分的像素值看看結果:

from PIL import Image
​
img = Image.open('blue.png')
width, height = img.size
​
s = []
for i in range(width):
    for j in range(1):
        tmp = img.getpixel((i,j))
        s.append(tmp[2])
​
print(bytes(s).hex())

發現取出每個字節的高8位,可以組成zip(開頭504b0304),處理

from PIL import Image
from tqdm import *
​
img = Image.open('blue.png')
width, height = img.size
​
s = ''
for i in trange(height):
    for j in range(width):
        tmp = img.getpixel((j,i))
        #print(hex(tmp[2]>>4)[2:])
        s += hex(tmp[2]>>4)[2:]
​
open('oo.zip','wb').write(bytes.fromhex(s))

得到zip,加密,裏面有xor.png 試試看用明文攻擊

bkcrack.exe -C oo.zip -c xor.png -x 0 89504e470d0a1a0a0000000d4948445200

得到key 68cc45ab 864060ce ac958caa

.\bkcrack.exe -C oo.zip -c xor.png -k 68cc45ab 864060ce ac958caa -d xor.png

得到 xor.png,末尾有另一個png,提取出來,根據名字xor,將兩幅圖異或得到xor1.png:

from PIL import Image
import numpy as np
​
# 打開圖片
img1 = Image.open("xor.png")
img2 = Image.open("Untitled1.png")
​
# 確保模式和尺寸一致
assert img1.size == img2.size
assert img1.mode == img2.mode
​
# 轉為 numpy 數組
arr1 = np.array(img1)
arr2 = np.array(img2)
​
# 像素逐位 XOR
xor_arr = arr1 ^ arr2
​
# 轉回 Image 並保存
xor_img = Image.fromarray(xor_arr)
xor_img.save("xor1.png")

得到的xor1.png與xor.png類似,盲水印解,解完就可以得到flag了

2.2 Hidden

給了一個.bmp格式的圖片,zsteg查看lsb:

zsteg -a treasure.bmp

再嘗試steghide隱寫,密碼PixelWhisper:

steghide extract -sf treasure.bmp

去看看flag.txt

flag{a9a3c2872e428b6d859a0e63458a43f8}

2.3 the_rogue_beacon

一個流量包,用wirehark打開

題目説要找到其峯值,這麼多流量幀看得我眼睛疼

【----幫助網安學習,以下所有學習資料免費領!加vx:YJ-2021-1,備註 “博客園” 獲取!】

 ① 網安學習成長路徑思維導圖
 ② 60+網安經典常用工具包
 ③ 100+SRC漏洞分析報告
 ④ 150+網安攻防實戰技術電子書
 ⑤ 最權威CISSP 認證考試指南+題庫
 ⑥ 超1800頁CTF實戰技巧手冊
 ⑦ 最新網安大廠面試題合集(含答案)
 ⑧ APP客户端安全檢測指南(安卓+IOS)

觀察數據包,發現主要存在兩個疑似傳輸數值的 ID:

· ID 0x039:數據跳變劇烈,無規律,判斷為干擾信號

· ID 0x244:數值呈現平滑的加速趨勢,符合物理運動規律,鎖定為真實車速信號

由於題目文件中的 CAN-ID 採用大端存儲,直接解析 ID 0x244 對應的 Hex 為 00 00 02 44。

在過濾器欄輸入以下指令,僅顯示真實車速數據,輸入 frame[0:4] contains 00:00:02:44 ,只顯示真實車速數據包

搜索到12149幀,此時的數據是35e4

上一行的數據是35d1,比35e4小

下一行的數據也是35d1,比35e4小,説明12149號幀就是峯值

而題目要求是sha-256加密,那直接拿12149去哈希就是flag了

flag{9db878fd06dd7587a91c0fb600e0e9f7c3ea310e75f36253ef57ac2d92dd8c29}

2.4 SMB

這道題其實是流量分析和逆向的結合

使用 Wireshark 打開提供的流量包文件,觀察流量包中的協議分佈

在流量包中發現大量 SMB 協議流量,SMB 是 Windows 系統中用於文件共享的協議,流量中可能包含傳輸的文件

發現一個名為 letter.exe 的可執行文件將該文件保存到本地

然後就是逆向的部分了,ida啓動

這居然還是rust語言的

真正的主函數是這個letter::main,不是main

v2 = __rustc::__rust_alloc(a1, a2, 1LL, 19LL); //這裏應該是分配內存
​
 //從地址 0x1400A22A8 複製 19 字節數據
​
*(_OWORD *)v2 = xmmword_1400A22A8;
​
*(_DWORD *)(v2 + 15) = 1060843565;

在 IDA 中定位到地址 0x1400A22A8使用 Hex View 查看該地址的數據

剛好是19個字符串,懷疑這裏就是flag,數據中包含可打印字符和不可打印字符,懷疑使用了簡單的加密算法

編寫 Python 腳本嘗試常見的 XOR 密鑰,當 XOR 密鑰為 0x42 時,成功解密出 flag

2.5 zipcracker

給了三個東西

do u know it是一個grc文件,將 I/Q 的實部、虛部分別寫入文件

something in it.jpg末尾有個zip,提取出來,可以得到 flag1.txt和 flag2.txt,分別是 I/Q 的實部、虛部

重構複數 IQ,然後NBFM解調,再低通+降採樣到音頻速率,保存為wav文件:

import numpy as np
from scipy.signal import decimate
from scipy.io.wavfile import write
​
I = np.fromfile("Untitled1/flag1.txt", dtype=np.float32)
Q = np.fromfile("Untitled1/flag2.txt", dtype=np.float32)
iq = I + 1j * Q
​
phase = np.unwrap(np.angle(iq))
fm = np.diff(phase)
​
audio = decimate(fm, 4)
print(audio)
​
write("out.wav", 48000, audio / np.max(np.abs(audio)))

獲得一段音頻,一聽就知道是摩斯密碼

提取一下 .---- .---- ....- ..... .---- ....- ...-- ..... ----- ..--- ...-- ....- .---- .---- ....- ..... .---- ....-

翻譯過來就是114514350234114514

解壓flag.zip,其中flag.txt是頭尾已知的部分明文,flag.zip是包含flag.txt的加密壓縮包

明文攻擊

bkcrack.exe -C flag.zip -c flag.txt -x 0 666c61677b593075 -x 25 2121217d

得到三個key 33b19021 93c4a78d 9ceed931

拿ARCHPR去跑,就可以得到flag

3.re

3.1 more_more_flower

Windows 32-bit PE 可執行文件Console 程序

給的flagSHA256.txt:給了一個 flag 的 SHA256,用來最後校驗結果

flagSHA256.txt 內容類似:

flag SHA256 Encrypted:3dbe89f66cb189f9cac1fb5ec23fac941df69119792aad4b6d61d63b98ddb527

IDA裏面跟flag有關的就是這個函數

sub_401000這個函數很長,大概就是 全局變量每輪從 .data 裏取 opcode 還有dispatch jump table,opcode -> handler 地址

還有全局寄存器R0C、R10、R14、R18、R28…

最後還在在 .data 裏開了一段空間 + SP 指針,就是用來驗證flag

輸入長度固定為 0x18(24)字節,處理時按 dword對齊讀取,因此總共會跑6 個 block

每次取 4 字節時,先按高字節在前拼成 32-bit 值:

v = (b0<<24) + (b1<<16) + (b2<<8) + b3

完成該 block 的運算後,結果不會按原順序寫回,而是把 dword 拆成 小端序的 4 個字節壓入 VM 棧

並沒有單獨的 loop 變量,而是把計數放在 棧底第 0 字節 啓動階段先 PUSH 0x06,每處理完一組就對 STACK[0] 做 -1,再用 JNZ STACK[0] 來決定要不要繼續下一組

每個 4 字節 block 內部會進入一個固定輪數的 ARX 更新流程,風格接近 TEA 那類“sum 逐輪疊加 delta”的寫法

sum 初始清零(VM 裏對應 R18

- 輪數硬編碼為 0x1e(即 30

每輪的順序是先累加:

sum += delta

隨後再更新數據本體 v

v += ((v<<5) ^ sum ^ (v>>4))

delta 不是直接出現的立即數,而是由字節碼“拼裝”出來:每輪都會 push 四個字節 56 11 25 23,再 POP 成 dword,因此得到常量:

delta = 0x23251156

6 組數據全部處理完後,VM 棧裏會累計得到 24 個變換後的輸出字節;隨後 bytecode 進入固定 24 次的校驗循環,每次都從棧頂 POP 1 字節並與 .data 段中的常量數組 DATA[i] 通過 SUB+JNZ 逐一比對,一旦不相等就直接走失敗分支 RET 0。由於校驗是“從棧頂往下彈”,實際比較順序與生成順序相反,因此整體等價於檢查 DATA == reverse(out)。從 .data 中提取的 24 字節常量為 21 7a 01 1c 33 d3 3e f7 03 78 25 5e 2f b8 8b 3b 93 84 ae 5b de a5 d6 e9,將其反序後再按每 4 字節以小端拼回 6 個 32-bit 密文塊,分別是 0xDEA5D6E9, 0x9384AE5B, 0x2FB88B3B, 0x0378255E, 0x33D33EF7, 0x217A011C,於是問題就轉化為:在已知這 6 個 32-bit 輸出的情況下,求對應的 6 個由 4 個可打印字符組成的 32-bit 輸入

用python會跑得很慢,所以直接改為用C++好了

#pragma GCC optimize("O3,unroll-loops")
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <cstdint>
#include <array>
​
// 配置常量
const uint32_t CFG_DELTA = 0x23251156;
const int CFG_ROUNDS = 30;
​
// 待解密的密文塊 (從 .data 提取)
const std::vector<uint32_t> TARGETS = {
    0xDEA5D6E9, 0x9384AE5B, 0x2FB88B3B, 
    0x0378255E, 0x33D33EF7, 0x217A011C
};
​
// 預計算 acc 表,避免重複計算
uint32_t ACC_TABLE[CFG_ROUNDS];
​
void precompute_acc() {
    uint32_t acc = 0;
    uint32_t delta = CFG_DELTA;
    for(int i = 0; i < CFG_ROUNDS; i++) {
        acc += delta;
        ACC_TABLE[i] = acc;
    }
}
​
// 核心加密函數 (內聯以提速)
inline uint32_t encrypt_core(uint32_t v) {
    for (int i = 0; i < CFG_ROUNDS; i++) {
        // v = v + ((v << 5) ^ acc ^ (v >> 4))
        v += ((v << 5) ^ ACC_TABLE[i] ^ (v >> 4));
    }
    return v;
}
​
// 輔助:將整數轉為字符串(自動處理字節序)
std::string u32_to_str(uint32_t val, bool little_endian) {
    std::string s(4, ' ');
    if (little_endian) {
        s[0] = (val >> 0) & 0xFF;
        s[1] = (val >> 8) & 0xFF;
        s[2] = (val >> 16) & 0xFF;
        s[3] = (val >> 24) & 0xFF;
    } else {
        s[0] = (val >> 24) & 0xFF;
        s[1] = (val >> 16) & 0xFF;
        s[2] = (val >> 8) & 0xFF;
        s[3] = (val >> 0) & 0xFF;
    }
    return s;
}
​
int main() {
    std::cout << "[*] Initializing tables..." << std::endl;
    precompute_acc();
​
    // 1. 快速驗證:檢查 "flag" 是否匹配第一個塊
    // "flag" -> 0x67616C66 (Little Endian) 或 0x666C6167 (Big Endian)
    uint32_t test_le = 0x67616C66; 
    uint32_t test_be = 0x666C6167;
    std::cout << "[?] Check logic: 'flag' encrypts to:" << std::endl;
    std::cout << "    LE input -> " << std::hex << encrypt_core(test_le) << std::endl;
    std::cout << "    BE input -> " << std::hex << encrypt_core(test_be) << std::endl;
    std::cout << "    Target 0 -> " << std::hex << TARGETS[0] << std::endl;
    std::cout << "------------------------------------------------" << std::endl;
​
    std::cout << "[*] Starting brute force (Space: ~81M)..." << std::endl;
    
    // 存儲結果:key 是 target 索引, value 是解出的字符串
    std::string results[6];
    int found_count = 0;
​
    // 4層循環窮舉 (c0 c1 c2 c3)
    // 假設輸入是 "ABCD",我們構建兩個整數:
    // LE_VAL = 0x44434241 (x86常用)
    // BE_VAL = 0x41424344 (網絡序/Z3腳本常用)
    
    // 優化:並行計算 (如果編譯器支持 OpenMP)
    #pragma omp parallel for collapse(2)
    for (int c0 = 32; c0 <= 126; c0++) {
        for (int c1 = 32; c1 <= 126; c1++) {
            for (int c2 = 32; c2 <= 126; c2++) {
                for (int c3 = 32; c3 <= 126; c3++) {
                    
                    // 構建兩種字節序的整數
                    uint32_t val_be = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
                    uint32_t val_le = (c3 << 24) | (c2 << 16) | (c1 << 8) | c0;
​
                    // 計算加密
                    uint32_t enc_be = encrypt_core(val_be);
                    uint32_t enc_le = encrypt_core(val_le);
​
                    // 檢查是否命中目標
                    for (int i = 0; i < 6; i++) {
                        if (enc_le == TARGETS[i]) {
                            // 命中 LE 模式
                            char buf[5] = {(char)c0, (char)c1, (char)c2, (char)c3, 0};
                            #pragma omp critical
                            {
                                std::cout << "[+] Found Chunk [" << i << "] (LE Mode): " << buf << std::endl;
                                results[i] = buf;
                                found_count++;
                            }
                        }
                        else if (enc_be == TARGETS[i]) {
                            // 命中 BE 模式
                            char buf[5] = {(char)c0, (char)c1, (char)c2, (char)c3, 0};
                            #pragma omp critical
                            {
                                std::cout << "[+] Found Chunk [" << i << "] (BE Mode): " << buf << std::endl;
                                results[i] = buf;
                                found_count++;
                            }
                        }
                    }
                }
            }
        }
    }
​
    std::cout << "[*] Done." << std::endl;
    std::cout << "Final Flag: ";
    for(int i=0; i<6; i++) std::cout << (results[i].empty() ? "????" : results[i]);
    std::cout << std::endl;
​
    return 0;
}

運行完就是flag{Fl0weRTeAVM15E3} 

更多網安技能的在線實操練習,請點擊這裏>>

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.