CSACTF2025 Writeup
鉴定为纯失
CheckIn
HidenWorld
Deformed-Image-Restorer一把梭了。

ezPickle
根本不要出网啊这道题
看见它放hint https://requestrepo.com 然后变成 无回显的rce,https://requestrepo.com
然后又加了容器可以出网 然后又加了 可以利用app的某些方法辅助rce
我就想笑
1 | import pickle |
cookie用引号绕过
1 | POST http://10.202.160.112:32829/admin |
报错回显:
Response:
1 | 200 OK |
CSACTF{N0w_u_Kn0w_h0W_P1cK13_w0rks_8726a30d05df}
babySteg
搜索comments中字段JPEG Encoder Copyright 1998, James R. Weeks and BioElectroMech.知是matthewgao/F5-steganography: F5 steganography
文件尾base64解码为CSACTF{1T_SEeMs_L1kE_4_fL49}推测为密码(灵感时刻.jpg)
是故运行
1 | $ [Redacted]/jre-1.8/bin/java Extract ./babySteg1.jpg -p "CSACTF{1T_SEeMs_L1kE_4_fL49}" |
得到输出CSACTF{N0W_u_kNoW_f5_4Nd_7He_rE41_fL49}
签退
略。CSACTF{H0p3_u_h4v3_a_go0d_7im3}
babyRsa
最有deepseek的一集
Part 1
根据提供的值(d-p、pow(m, e, N) 和 N),我们可以通过求解 RSA 参数来恢复明文 m。脚本通过循环可能的乘数 r(从 1 到 e=65537),利用二次方程求解素数 p,并最终解密得到 flag。
以下是 Python 脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 import math
from Crypto.Util.number import long_to_bytes
e = 65537
# 从 output.txt 读取值
with open('output.txt', 'r') as f:
lines = f.readlines()
k = int(lines[0].strip())
c = int(lines[1].strip())
N = int(lines[2].strip())
# 循环遍历可能的 r 值
for r in range(1, e+1):
if r % 10000 == 0:
print(f"Trying r = {r}") # 进度指示
A = e + r
B = e * k - 1 - r * N - r
C = r * N
# 计算判别式
D = B*B - 4*A*C
if D < 0:
continue
# 检查 D 是否为完全平方数
root = math.isqrt(D)
if root * root != D:
continue
# 计算可能的 p
num = -B + root
if num % (2*A) != 0:
continue
p = num // (2*A)
# 检查 p 是否整除 N
if N % p != 0:
continue
print(f"Found p: {p}")
q = N // p
phi = (p-1) * (q-1)
d = pow(e, -1, phi)
m = pow(c, d, N)
flag = long_to_bytes(m)
print(flag)
break
else:
print("Not found")使用说明:
- 将提供的值(d-p、pow(m, e, N) 和 N)按顺序保存到
output.txt文件中,每行一个值。- 确保已安装
pycryptodome库(包含Crypto.Util.number),可以使用pip install pycryptodome安装。- 运行脚本,它将输出解密后的 flag。
此脚本通过数学关系求解 RSA 参数 p,并解密得到明文 m。循环次数最多为 65537 次,在现代计算机上可以快速完成。
flag{117699abef7d1e
Part 2
为了解出给定的RSA加密中的明文 $m$,我们需要分解模数 $n$。给定 $n$ 和 $c$ 以及密钥生成方式,其中 $q$ 是 $p$ 与 $(1<<900) - 1$ 异或后的下一个素数,我们可以利用这种关系通过求解二次方程模 $2^{900}$ 来找到 $p$ 和 $q$。以下是实现这一点的Python脚本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 import math
from Crypto.Util.number import long_to_bytes
def main(n, c):
e = 0x10001
base = 2**900
N_low = n % base
found = False
p_val = None
q_val = None
for k in range(1, 10000, 2):
solutions = [1]
for m in range(2, 901):
new_solutions = []
for b0 in solutions:
f_val = b0*b0 + b0*(1 - k) + N_low
if f_val % (2**(m-1)) != 0:
continue
c_val = f_val // (2**(m-1))
if c_val % 2 == 0:
new_solutions.append(b0)
new_solutions.append(b0 + 2**(m-1))
solutions = new_solutions
if not solutions:
break
if not solutions:
continue
for b in solutions:
d = base - 1 - b + k
C = b * d - n
D = (base - 1 + k)**2 - 4 * C
root = math.isqrt(D)
if root * root != D:
continue
A = (- (base - 1 + k) + root) // 2
if A % base != 0:
continue
p = A + b
if n % p == 0:
p_val = p
q_val = n // p
found = True
break
if found:
break
if not found:
print("Failed to factor n")
return
phi = (p_val - 1) * (q_val - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print(flag.decode())
if __name__ == '__main__':
n = int(input("Enter n: "))
c = int(input("Enter c: "))
main(n, c)使用说明:
- 将上述代码保存为脚本文件(例如
solve.py)。- 运行脚本并输入已知的 $n$ 和 $c$ 值。
- 脚本将计算私钥并解密出明文 $m$,输出flag。
注意:
- 脚本假设 $k$(即
next_prime的偏移量)是奇数且小于10000。这通常成立,因为素数的间隔在1024位数时通常较小。- 脚本使用
math.isqrt来计算整数平方根,需要Python 3.8及以上版本。- 如果分解失败,可以尝试增加 $k$ 的范围上限。
此脚本通过求解模 $2^{900}$ 的二次方程来找到 $p$ 的低900位,然后利用二次方程求出完整的 $p$,最终分解 $n$ 并解密 $c$。
e592d8cfae5fbb6fe7}
ezCrypto
又到了deepseek魅力时刻
为了解密秘密消息
secret,我们需要从给定的c,c1,c2,N中恢复出 RSA 的私钥参数p和q。通过利用c1和c2的线性关系,我们可以计算p和q,然后使用 RSA 解密得到secret。以下是完整的 Python 脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 from Crypto.Util.number import long_to_bytes
from math import gcd
# Given e1 and e2
e1 = 9993078339649918633394551494432099987489636970426459609511857467341547586587525392554182350765642296219526020856710856746033936605501022624688690300688439
e2 = 9862231551884468205315488646474297306588640159481717035401356860971981714476971478488573347081320483033055786493180165517487943548799848155409701594695241
# Replace these values with the actual output from encrypt()
c = # Insert actual value here
c1 = # Insert actual value here
c2 = # Insert actual value here
N = # Insert actual value here
# Compute the product e1 * e2
exp = e1 * e2
# Compute T1 = c1^e2 * 3^(e1*e2) mod N
T1 = (pow(c1, e2, N) * pow(3, exp, N)) % N
# Compute T2 = c2^e1 * 2^(e1*e2) mod N
T2 = (pow(c2, e1, N) * pow(2, exp, N)) % N
# Compute K = (T1 - T2) mod N
K = (T1 - T2) % N
# Find p by computing gcd(K, N)
p = gcd(K, N)
if p == 1 or p == N:
raise ValueError("Failed to find prime factor p")
q = N // p
# Compute phi(N)
phi = (p - 1) * (q - 1)
# Decrypt the message using RSA
e = 65537
d = pow(e, -1, phi)
m = pow(c, d, N)
secret = long_to_bytes(m)
print(secret)使用说明:
- 将脚本中的
c,c1,c2,N替换为encrypt函数的实际输出值。- 运行脚本,即可得到解密后的
secret。该方法通过计算
c1和c2的线性组合来找到p,然后推导出q,最终解密出消息。注意,脚本假设e1和e2是给定的,并且加密使用的指数e是 65537。
b'R28wZF9Kb0IhX1dlMUMwbUVfdDBfb1VSX2NzQUN0Rl8ybzI1IQ=='
Go0d_JoB!_We1C0mE_t0_oUR_csACtF_2o25!