找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2161

积分

0

好友

303

主题
发表于 2025-12-24 18:41:20 | 查看: 30| 回复: 0

1. 密码学

1.1 BabyRSA:高精度浮点数泄露与密钥恢复

这是一道典型的RSA密钥恢复题目,其核心利用点在于高精度浮点数泄露来还原私钥参数。题目给出了一个计算得到的leak值,其公式为:

leak = (p-1)/q

该漏洞的成因在于,给出的十进制小数精度(1024位)远大于还原分数(p-1)/q所需的信息量(约617位)。这多出的400多位精度,保证了我们可以唯一地将这个小数还原为原始的分数,进而恢复出pq

解题脚本 (Python):

import decimal
from Crypto.Util.number import long_to_bytes

# --- 题目数据 ---
leak_str = "1.396995694831414203476063690838730308815841662737318558906107823553922718340982125801595368449608188770051881765292978548960520326036779130167518285237817101541807766017642530065080930654694948943506714268685400709580398894902693407016988670394423892586264077247263710263220932577837642377245651448838665854362532801659965471421937839336237670710012298796758992931116659292915200628873553198226185187089027680973673618973869464164460226697625936493428822424637497370197316811245879504779934098600596822159243994319583651080005054538419168988020562590543262648544970376255020489363894055887067948343768399654357738592577280906555896933717091837896978973488220368081406433117367524537063718421897982643644320078600517763936883820416362057895941185749296170109172249907094176821124345672294602380784325702476105763209165109703429326132417850746805701054961710623030742187505484821961670922386999933202645522248608323217011522889282323071281405301772218220381951540118124201599862330377374571641729649420917168701463539034702411"
d = 16306054997613721520756151430779642117683661431522665108784419231044104572118893098180652730976905729602478591047033305251624752030036736271198006715513694904231940253554804069707679445942892410812386221633728427239116007373836662495075237456279818311659331982404534490546781763464409713789636372508503902598331950861474527128323735250673137355260113147338636761737748874105625008482750923429512271416511835596944209137554445130949731646669691366003832655082535985891463876904334888009751956386994969339847254470145428608062575606120441725590059524749595027078238962391188809496875025237129899849787699468205026040721
c = 7908369000608075306226552240713890041649799894903074579356627811865842237315201153498579205223600526520994811661608630888045462921547166872107507948062717836952855804806976414887413729060431265217539895710936669089248515746191716161194996469977577048602427553584286064475300979649416171469313168995504717602670924606819204605601860560767900702512753735554900344201907921239415885901489708576066483012272256175573658509614344875077232108364134161997767814675830320630271209201503987787921279932886374846298269125068817280777403718279754392091441050281244934594776307137448975055247018414699621410668188864774860026941

# --- 求解脚本 ---
decimal.getcontext().prec = 5000
L = decimal.Decimal(leak_str)
e_list = [65537, 3, 5, 17, 257]

print("开始寻找 flag ...")
for e in e_list:
    for k in range(1, e):
        if (e * d - 1) % k == 0:
            phi = (e * d - 1) // k
            term1 = (L + 1) ** 2
            term2 = 4 * L * (decimal.Decimal(phi) - 1)
            delta = term1 + term2
            if delta < 0:
                continue
            sqrt_delta = delta.sqrt()
            q_approx = (L + 1 + sqrt_delta) / (2 * L)
            q_int = int(q_approx)
            for q_cand in range(q_int - 2, q_int + 3):
                if q_cand < 2: continue
                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)
                        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,请检查输入数据或参数。")

成功解密即可获得Flag。

1.2 Peco:复合型数论与格密码攻击

本题是一道复合型密码学题目,融合了RSA密钥恢复不定方程求解格密码攻击技术。这道题涉及从流量包分析到二进制逆向的完整安全/渗透链条。解题主要分为以下几步:

  1. 解不定方程:通过佩尔方程求解得到xy
  2. 分解RSA模数n:利用Hensel Lifting(亨泽尔引理)恢复p的低位,再结合Coppersmith攻击恢复完整的p,从而分解n
  3. RSA解密:获得中间消息m
  4. 构造格并求解:利用xym构造一个格(Lattice),通过LLL规约求解出最终的f0f1,拼接后得到Flag。

解题脚本 (SageMath/Python):

import sys

def long_to_bytes(val, endianness='big'):
    # ... (省略实现,同原exp)
    pass

# --- 题目数据 ---
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 ===")
# 求解过程 (代码较长,逻辑同原exp,此处省略)
# ... (假设已成功求解得到 val_x, val_y)

if val_x is not None:
    print("\n=== 步骤 2: Hensel Lifting 恢复 p 低位 ===")
    # Hensel Lifting 过程
    # ... (代码逻辑同原exp)

    print("\n=== 步骤 3: Coppersmith 恢复完整 p ===")
    # Coppersmith 攻击
    P_poly.<x_poly> = PolynomialRing(Zmod(n))
    for idx, p0 in enumerate(p_cands):
        f = p0 + x_poly * (1 << mod_limit_bits)
        f = f.monic()
        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:
            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]
        ])
        L = M.LLL()
        for row in L:
            f0_cand = abs(row[0])
            f1_cand = abs(row[1])
            r_cand = abs(row[2])
            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,请手动检查LLL结果向量。")
    else:
        print("[-] 未能分解 n")

2. 杂项(Misc)

2.1 Blue:多层图片隐写

题目给出一张纯色图片blue.png,视觉上无任何信息。

解题步骤:

  1. 提取像素值:发现每个像素蓝色通道(B)值的高4位可以组成一个ZIP文件的十六进制数据。
    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))
            s += hex(tmp[2]>>4)[2:]
    open('oo.zip','wb').write(bytes.fromhex(s))
  2. ZIP明文攻击:得到的oo.zipxor.png被加密,利用已知的PNG文件头进行明文攻击,获取密钥。
    bkcrack.exe -C oo.zip -c xor.png -x 0 89504e470d0a1a0a0000000d4948445200
    # 得到key: 68cc45ab 864060ce ac958caa
  3. 解密并提取:使用密钥解压出xor.png,发现其文件末尾附加了另一张图片Untitled1.png,将其分离。
  4. 图片异或:根据文件名提示,将xor.pngUntitled1.png进行像素级异或,得到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
    arr1 = np.array(img1)
    arr2 = np.array(img2)
    xor_arr = arr1 ^ arr2
    Image.fromarray(xor_arr).save("xor1.png")
  5. 盲水印提取:对xor1.png使用盲水印工具(如blindwatermark)提取,最终获得Flag。

2.2 Hidden:多重信息隐藏

题目给出一个treasure.bmp图片文件。

解题步骤:

  1. LSB隐写分析:使用zsteg工具检查最低有效位,发现存在隐藏数据。
    zsteg -a treasure.bmp
  2. Steghide隐写:尝试使用steghide提取,密码为PixelWhisper(可从上下文或常见密码字典尝试)。
    steghide extract -sf treasure.bmp
    # 输入密码: PixelWhisper
  3. 提取成功后得到flag.txt,打开即获得Flag:flag{a9a3c2872e428b6d859a0e63458a43f8}

2.3 The_Rogue_Beacon:CAN总线流量分析

题目提供一个车辆CAN总线流量包,要求找到车速信号的峰值。

解题步骤:

  1. 协议分析:使用Wireshark打开流量包,识别出CAN协议帧。在车载网络/系统中,车速信号通常有特定的ID。
  2. 筛选有效信号:观察发现ID 0x039的数据跳变无规律,为干扰信号;ID 0x244的数据呈现平滑的加速趋势,符合真实车速特征。

    注意:数据包中的CAN-ID为大端存储,0x244对应的Hex为00 00 02 44

  3. 过滤与定位:在Wireshark过滤器中输入 frame[0:4] contains 00:00:02:44,仅显示真实车速数据包。
  4. 寻找峰值:浏览过滤后的数据,对比相邻帧的数值。当发现某帧数据(如帧号12149,数据35e4)大于其前一帧(35d1)和后一帧(35d1)时,即可确定该帧为峰值点。
  5. 生成Flag:将峰值帧号12149进行SHA-256哈希计算,得到的哈希值即为Flag。
    flag{9db878fd06dd7587a91c0fb600e0e9f7c3ea310e75f36253ef57ac2d92dd8c29}

2.4 SMB:流量分析与简单逆向

题目提供一个网络流量包,其中包含通过SMB协议传输的文件。

解题步骤:

  1. 流量分析:使用Wireshark打开,在SMB协议流量中追踪文件传输流(TCP Follow Stream),发现一个名为letter.exe的可执行文件被传输,将其导出保存。
  2. 逆向分析:使用IDA Pro打开letter.exe,发现其为Rust语言编写。定位到主函数letter::main
  3. 关键数据定位:在代码中观察到内存分配和拷贝操作,地址0x1400A22A8处有19字节的数据被复制。
    v2 = __rustc::__rust_alloc(a1, a2, 1LL, 19LL);
    *(_OWORD *)v2 = xmmword_1400A22A8;
    *(_DWORD *)(v2 + 15) = 1060843565;
  4. 数据提取与解密:在Hex View中查看地址0x1400A22A8处的19字节原始数据。怀疑是简单加密(如XOR),尝试用单字节密钥0x42进行解密,成功得到Flag。

2.5 Zipcracker:无线电信号处理与明文攻击

题目提供三个文件:一个.grc文件(GNU Radio流程图)、一张图片和一个加密ZIP。

解题步骤:

  1. 理解.grc文件:该文件描述了一个NBFM(窄带调频)解调流程,将I/Q(同相/正交)信号的实部、虚部分别写入文件。
  2. 提取I/Q数据:从图片文件something in it.jpg末尾分离出一个ZIP,解压得到flag1.txtflag2.txt,即为I和Q数据。
  3. 信号解调:读取I/Q数据,重构复数信号,计算相位并差分得到FM信号,最后进行低通滤波和降采样,输出为WAV音频文件。
    import numpy as np
    from scipy.signal import decimate
    from scipy.io.wavfile import write
    I = np.fromfile("flag1.txt", dtype=np.float32)
    Q = np.fromfile("flag2.txt", dtype=np.float32)
    iq = I + 1j * Q
    phase = np.unwrap(np.angle(iq))
    fm = np.diff(phase)
    audio = decimate(fm, 4)
    write("out.wav", 48000, audio / np.max(np.abs(audio)))
  4. 摩斯密码解码:收听生成的out.wav,为摩斯电码。解码后得到数字串:114514350234114514
  5. ZIP明文攻击:另一个flag.zip中包含加密的flag.txt。已知Flag格式为flag{...!!!},因此可以构造部分明文(头flag{Y和尾!!!})对ZIP进行明文攻击。
    bkcrack.exe -C flag.zip -c flag.txt -x 0 666c61677b593075 -x 25 2121217d
  6. 破解密码:获得密钥后,使用工具(如ARCHPR)或bkcrack-k参数直接解密ZIP,或利用密钥生成一个已知密码的新ZIP包,最终解压获得完整Flag。

3. 逆向工程

3.1 More_More_Flower:自定义VM逆向

本题为一个32位Windows控制台程序,实现了一个自定义的虚拟机(VM)来验证输入的Flag。

分析过程:

  1. 程序行为:输入长度为24字节(0x18),程序通过自定义的字节码解释器进行处理,最后与.data段中的常量数组比对。
  2. VM结构分析
    • 存在全局寄存器(如R0C, R10, R14, R18, R28)。
    • .data段读取opcode,通过分发跳转表(dispatch jump table)执行对应的handler。
    • .data段开辟栈空间,有SP指针。
  3. 算法识别:逆向VM字节码handler后,识别出其核心是一个类似TEA的ARX(加法-循环移位-异或)加密算法,每组4字节(共6组)独立加密。
    • sum初始为0,每轮增加一个固定delta0x23251156)。
    • 轮数为30轮(0x1e)。
    • 每轮更新公式:v += ((v << 5) ^ sum ^ (v >> 4))
  4. 验证逻辑:6组数据加密后,将每组的32位结果按小端序拆分为4字节压入VM栈。最后从栈顶依次弹出24字节,与.data中的常量数组进行比对。常量数组为: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个目标密文块:
      0xDEA5D6E9, 0x9384AE5B, 0x2FB88B3B, 0x0378255E, 0x33D33EF7, 0x217A011C
  5. 暴力破解:问题转化为,对于每个32位密文,寻找一个由4个可打印字符(ASCII 32-126)组成的明文,经过上述30轮加密后恰好等于目标密文。由于每组仅需遍历约95^4 ≈ 81M种可能,可以暴力破解。需考虑输入字节序(大端或小端)。

破解脚本 (C++):

#pragma GCC optimize("O3,unroll-loops")
#include<iostream>
#include<cstdint>
const uint32_t CFG_DELTA = 0x23251156;
const int CFG_ROUNDS = 30;
const uint32_t TARGETS[6] = {0xDEA5D6E9, 0x9384AE5B, 0x2FB88B3B, 0x0378255E, 0x33D33EF7, 0x217A011C};
uint32_t ACC_TABLE[CFG_ROUNDS];

void precompute_acc() {
    uint32_t acc = 0;
    for(int i = 0; i < CFG_ROUNDS; i++) {
        acc += CFG_DELTA;
        ACC_TABLE[i] = acc;
    }
}
inline uint32_t encrypt_core(uint32_t v) {
    for (int i = 0; i < CFG_ROUNDS; i++) {
        v += ((v << 5) ^ ACC_TABLE[i] ^ (v >> 4));
    }
    return v;
}

int main() {
    precompute_acc();
    std::string results[6] = {""};
    #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] || enc_be == TARGETS[i]) {
                            char buf[5] = {(char)c0, (char)c1, (char)c2, (char)c3, 0};
                            #pragma omp critical
                            {
                                results[i] = buf;
                            }
                        }
                    }
                }
            }
        }
    }
    std::cout << "Flag: ";
    for(int i=0; i<6; i++) std::cout << results[i];
    std::cout << std::endl;
    return 0;
}

运行脚本后得到Flag:flag{Fl0weRTeAVM15E3}




上一篇:快手P0级事故分析:直播业务安全漏洞与风控系统加固思考
下一篇:Linux内存问题诊断:如何识别系统“勉强维持”的早期信号与性能瓶颈
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 20:15 , Processed in 0.257196 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

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