forked from p34709852/monkey
Agent: Skip empty password attempts in PowerShell if HTTP disabled
This commit is contained in:
parent
06899be264
commit
45658b5559
|
@ -39,7 +39,7 @@ class PowerShellExploiter(HostExploiter):
|
||||||
self._client = None
|
self._client = None
|
||||||
|
|
||||||
def _exploit_host(self):
|
def _exploit_host(self):
|
||||||
if not self._is_any_default_port_open():
|
if not self._any_powershell_port_is_open():
|
||||||
message = "PowerShell Remoting appears to be disabled on the remote host"
|
message = "PowerShell Remoting appears to be disabled on the remote host"
|
||||||
self.exploit_result.error_message = message
|
self.exploit_result.error_message = message
|
||||||
logger.debug(message)
|
logger.debug(message)
|
||||||
|
@ -77,13 +77,21 @@ class PowerShellExploiter(HostExploiter):
|
||||||
|
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
def _is_any_default_port_open(self) -> bool:
|
def _any_powershell_port_is_open(self) -> bool:
|
||||||
return "tcp-5985" in self.host.services or "tcp-5986" in self.host.services
|
return self._http_powershell_port_is_open() or self._https_powershell_port_is_open()
|
||||||
|
|
||||||
|
def _http_powershell_port_is_open(self) -> bool:
|
||||||
|
return "tcp-5985" in self.host.services
|
||||||
|
|
||||||
|
def _https_powershell_port_is_open(self) -> bool:
|
||||||
|
return "tcp-5986" in self.host.services
|
||||||
|
|
||||||
def _authenticate_via_brute_force(
|
def _authenticate_via_brute_force(
|
||||||
self, credentials: List[Credentials], auth_options: List[AuthOptions]
|
self, credentials: List[Credentials], auth_options: List[AuthOptions]
|
||||||
) -> Optional[IPowerShellClient]:
|
) -> Optional[IPowerShellClient]:
|
||||||
for (creds, opts) in interruptible_iter(zip(credentials, auth_options), self.interrupt):
|
creds_opts_pairs = filter(self.check_ssl_setting_is_valid, zip(credentials, auth_options))
|
||||||
|
for (creds, opts) in interruptible_iter(creds_opts_pairs, self.interrupt):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client = PowerShellClient(self.host.ip_addr, creds, opts)
|
client = PowerShellClient(self.host.ip_addr, creds, opts)
|
||||||
client.connect()
|
client.connect()
|
||||||
|
@ -105,6 +113,17 @@ class PowerShellExploiter(HostExploiter):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def check_ssl_setting_is_valid(self, creds_opts_pair):
|
||||||
|
opts = creds_opts_pair[1]
|
||||||
|
|
||||||
|
if opts.ssl and not self._https_powershell_port_is_open():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not opts.ssl and not self._http_powershell_port_is_open():
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def _report_login_attempt(self, result: bool, credentials: Credentials):
|
def _report_login_attempt(self, result: bool, credentials: Credentials):
|
||||||
if credentials.secret_type in [SecretType.PASSWORD, SecretType.CACHED]:
|
if credentials.secret_type in [SecretType.PASSWORD, SecretType.CACHED]:
|
||||||
self.report_login_attempt(result, credentials.username, password=credentials.secret)
|
self.report_login_attempt(result, credentials.username, password=credentials.secret)
|
||||||
|
|
|
@ -76,8 +76,6 @@ def test_powershell_http(monkeypatch, powershell_exploiter, powershell_arguments
|
||||||
|
|
||||||
|
|
||||||
def test_powershell_https(monkeypatch, powershell_exploiter, powershell_arguments, https_only_host):
|
def test_powershell_https(monkeypatch, powershell_exploiter, powershell_arguments, https_only_host):
|
||||||
powershell_arguments["host"] = https_only_host
|
|
||||||
|
|
||||||
mock_powershell_client = MagicMock()
|
mock_powershell_client = MagicMock()
|
||||||
mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login"))
|
mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login"))
|
||||||
mock_powershell_client_constructor = MagicMock(return_value=mock_powershell_client)
|
mock_powershell_client_constructor = MagicMock(return_value=mock_powershell_client)
|
||||||
|
@ -85,11 +83,15 @@ def test_powershell_https(monkeypatch, powershell_exploiter, powershell_argument
|
||||||
|
|
||||||
powershell_exploiter.exploit_host(**powershell_arguments)
|
powershell_exploiter.exploit_host(**powershell_arguments)
|
||||||
|
|
||||||
|
non_ssl_calls = 0
|
||||||
for call_args in mock_powershell_client_constructor.call_args_list:
|
for call_args in mock_powershell_client_constructor.call_args_list:
|
||||||
if call_args[0][1].secret != "":
|
if call_args[0][1].secret != "":
|
||||||
assert call_args[0][2].ssl
|
assert call_args[0][2].ssl
|
||||||
else:
|
else:
|
||||||
assert not call_args[0][2].ssl
|
assert not call_args[0][2].ssl
|
||||||
|
non_ssl_calls += 1
|
||||||
|
|
||||||
|
assert non_ssl_calls > 0
|
||||||
|
|
||||||
|
|
||||||
def test_no_valid_credentials(monkeypatch, powershell_exploiter, powershell_arguments):
|
def test_no_valid_credentials(monkeypatch, powershell_exploiter, powershell_arguments):
|
||||||
|
@ -185,3 +187,22 @@ def test_build_monkey_execution_command():
|
||||||
|
|
||||||
assert f"-d {depth}" in cmd
|
assert f"-d {depth}" in cmd
|
||||||
assert executable_path in cmd
|
assert executable_path in cmd
|
||||||
|
|
||||||
|
|
||||||
|
def test_skip_http_only_logins(
|
||||||
|
monkeypatch, powershell_exploiter, powershell_arguments, https_only_host
|
||||||
|
):
|
||||||
|
# Only HTTPS is enabled on the destination, so we should never try to connect with "" empty
|
||||||
|
# password, since connection with empty password requires SSL == False.
|
||||||
|
powershell_arguments["host"] = https_only_host
|
||||||
|
|
||||||
|
mock_powershell_client = MagicMock()
|
||||||
|
mock_powershell_client.connect = MagicMock(side_effect=Exception("Failed login"))
|
||||||
|
mock_powershell_client_constructor = MagicMock(return_value=mock_powershell_client)
|
||||||
|
monkeypatch.setattr(powershell, "PowerShellClient", mock_powershell_client_constructor)
|
||||||
|
|
||||||
|
powershell_exploiter.exploit_host(**powershell_arguments)
|
||||||
|
|
||||||
|
for call_args in mock_powershell_client_constructor.call_args_list:
|
||||||
|
assert call_args[0][1].secret != ""
|
||||||
|
assert call_args[0][2].ssl
|
||||||
|
|
Loading…
Reference in New Issue