DownUnderCTF 2025 mini-me

国外的CTF -web题

比赛平台:DownUnderCTF

097d1dc5feceab4a.png

打开题目后下载附件

be5b0fd8be291948.png

里面包括这些文件

代码审计

templates分析

templates 里面包含 index.html和confidential.html

这两文件中有一段代码比较重要(共同的)

1
<script src="/static/js/main.min.js"></script>

app.py 分析

然后我们分析app.py

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
from flask import Flask, render_template, send_from_directory, request, redirect, make_response
from dotenv import load_dotenv

import os
load_dotenv()
API_SECRET_KEY = os.getenv("API_SECRET_KEY")
FLAG = os.getenv("FLAG")

app = Flask(__name__, static_folder="static", template_folder="templates")

@app.after_request
def add_header(response):
response.cache_control.no_store = True
response.cache_control.must_revalidate = True
return response

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

@app.route("/login", methods=["POST"])
def login():
return redirect("/confidential.html")

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


@app.route("/admin/flag", methods=["POST"])
def flag():
key = request.headers.get("X-API-Key")
if key == API_SECRET_KEY:
return FLAG
return "Unauthorized", 403

由上到下来分析吧

首先

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from flask import Flask, render_template, send_from_directory, request, redirect, make_response
from dotenv import load_dotenv

import os
load_dotenv()
API_SECRET_KEY = os.getenv("API_SECRET_KEY")
FLAG = os.getenv("FLAG")

app = Flask(__name__, static_folder="static", template_folder="templates")

@app.after_request
def add_header(response):
response.cache_control.no_store = True
response.cache_control.must_revalidate = True
return response

一些配置文件,初始化 api 密钥 和flag

接着我们分析路由

/路由

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

打开题目后载入到index.html页面

login和confidential.html路由

1
2
3
4
5
6
7
@app.route("/login", methods=["POST"])
def login():
return redirect("/confidential.html")

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

login 路由登录完成后载入confidential.html

confidential.html路由同理

/admin/flag路由

1
2
3
4
5
6
@app.route("/admin/flag", methods=["POST"])
def flag():
key = request.headers.get("X-API-Key")
if key == API_SECRET_KEY:
return FLAG
return "Unauthorized", 403

在/admin/flag路由中 我们给X-API-Key 传入 经过判断得到flag

分析完之后我们开始做题

打开题目

做题分析

登录部分

一个登录界面

2886570599ff18a9.png

访问static/js/main.min.js(前面有提到过的)

1
https://web-mini-me-ab6d19a7ea6e.2025.ductf.net/static/js/main.min.js

e1df66e32a96bbf6.png

注意这里

1
//test map file -> test-main.min.js.map, remove in prod 

.map 文件(源映射文件)是 JavaScript 开发中用于调试压缩/混淆代码的重要工具

我们访问看看

1
https://web-mini-me-ab6d19a7ea6e.2025.ductf.net/static/js/test-main.min.js.map

下载到文件

image-20250719115019659

解密部分

打开后我们我们丢给ai分析并让他给我们解密脚本(由于里面内容太乱这里只展示部分重要的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3
# decrypt_key.py

def decrypt():
# 原始数据
dhgyvu = [
"85", "87", "77", "67", "40", "82",
"82", "70", "78", "39", "95", "89",
"67", "73", "34", "68", "68", "92",
"84", "57", "70", "87", "95", "77", "75"
]
# 解密并拼接
return "".join(
chr(int(val) ^ (idx + 1))
for idx, val in enumerate(dhgyvu)
)

if __name__ == "__main__":
key = decrypt()
print("解密结果:", key)

a812d475f5e12403.png

我们把

1
TUNG-TUNG-TUNG-TUNG-SAHUR

作为

X-API-Key (HTTTP 头)传入 /admin/flag路由得到flag

cb0d341467b67262.png

1
flag:DUCTF{Cl13nt-S1d3-H4ck1nG-1s-FuN}