Agent: Add LM and NT hashes to PowerShell Credentials

Adds two list parameters to get_credentials() that contain LM and NT
hashes respectively. Adds a "secret_type" field to Credentials so that
the user of the Credentials object can distinguish between using cached
credentials (on windows), passwords, and NT or LM hashes.
This commit is contained in:
Mike Salvatore 2021-09-02 12:29:49 -04:00
parent 3a6f725cc4
commit a2e6b0bfbd
4 changed files with 132 additions and 26 deletions

View File

@ -13,7 +13,11 @@ from infection_monkey.exploit.powershell_utils.auth_options import (
AuthOptions, AuthOptions,
get_auth_options, get_auth_options,
) )
from infection_monkey.exploit.powershell_utils.credentials import Credentials, get_credentials from infection_monkey.exploit.powershell_utils.credentials import (
Credentials,
SecretType,
get_credentials,
)
from infection_monkey.exploit.powershell_utils.powershell_client import ( from infection_monkey.exploit.powershell_utils.powershell_client import (
AuthenticationError, AuthenticationError,
IPowerShellClient, IPowerShellClient,
@ -49,7 +53,11 @@ class PowerShellExploiter(HostExploiter):
return False return False
credentials = get_credentials( credentials = get_credentials(
self._config.exploit_user_list, self._config.exploit_password_list, is_windows_os() self._config.exploit_user_list,
self._config.exploit_password_list,
[],
[],
is_windows_os(),
) )
auth_options = get_auth_options(credentials, is_https) auth_options = get_auth_options(credentials, is_https)
@ -89,6 +97,7 @@ class PowerShellExploiter(HostExploiter):
credentials = Credentials( credentials = Credentials(
username="dummy_username", username="dummy_username",
secret="dummy_password", secret="dummy_password",
secret_type=SecretType.PASSWORD,
) )
auth_options = AuthOptions( auth_options = AuthOptions(

View File

@ -1,21 +1,36 @@
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum
from itertools import product from itertools import product
from typing import List, Union from typing import List, Union
class SecretType(Enum):
CACHED = 1
PASSWORD = 2
LM_HASH = 3
NT_HASH = 4
@dataclass @dataclass
class Credentials: class Credentials:
username: Union[str, None] username: Union[str, None]
secret: Union[str, None] secret: Union[str, None]
secret_type: SecretType
def get_credentials( def get_credentials(
usernames: List[str], passwords: List[str], is_windows: bool usernames: List[str],
passwords: List[str],
lm_hashes: List[str],
nt_hashes: List[str],
is_windows: bool,
) -> List[Credentials]: ) -> List[Credentials]:
credentials = [] credentials = []
credentials.extend(_get_empty_credentials(is_windows)) credentials.extend(_get_empty_credentials(is_windows))
credentials.extend(_get_username_only_credentials(usernames, is_windows)) credentials.extend(_get_username_only_credentials(usernames, is_windows))
credentials.extend(_get_username_password_credentials(usernames, passwords)) credentials.extend(_get_username_password_credentials(usernames, passwords))
credentials.extend(_get_username_lm_hash_credentials(usernames, lm_hashes))
credentials.extend(_get_username_nt_hash_credentials(usernames, nt_hashes))
return credentials return credentials
@ -24,7 +39,7 @@ def get_credentials(
# will be used to attempt to log into the victim. # will be used to attempt to log into the victim.
def _get_empty_credentials(is_windows: bool) -> List[Credentials]: def _get_empty_credentials(is_windows: bool) -> List[Credentials]:
if is_windows: if is_windows:
return [Credentials(username=None, secret=None)] return [Credentials(username=None, secret=None, secret_type=SecretType.CACHED)]
return [] return []
@ -32,10 +47,18 @@ def _get_empty_credentials(is_windows: bool) -> List[Credentials]:
# On Windows systems, when password == None, the current user's password will bu used to attempt to # On Windows systems, when password == None, the current user's password will bu used to attempt to
# log into the victim. # log into the victim.
def _get_username_only_credentials(usernames: List[str], is_windows: bool) -> List[Credentials]: def _get_username_only_credentials(usernames: List[str], is_windows: bool) -> List[Credentials]:
credentials = [Credentials(username=username, secret="") for username in usernames] credentials = [
Credentials(username=username, secret="", secret_type=SecretType.PASSWORD)
for username in usernames
]
if is_windows: if is_windows:
credentials.extend([Credentials(username=username, secret=None) for username in usernames]) credentials.extend(
[
Credentials(username=username, secret=None, secret_type=SecretType.CACHED)
for username in usernames
]
)
return credentials return credentials
@ -43,6 +66,27 @@ def _get_username_only_credentials(usernames: List[str], is_windows: bool) -> Li
def _get_username_password_credentials( def _get_username_password_credentials(
usernames: List[str], passwords: List[str] usernames: List[str], passwords: List[str]
) -> List[Credentials]: ) -> List[Credentials]:
username_password_pairs = product(usernames, passwords) return _get_username_secret_credentials(usernames, passwords, SecretType.PASSWORD)
return [Credentials(credentials[0], credentials[1]) for credentials in username_password_pairs]
def _get_username_lm_hash_credentials(
usernames: List[str], lm_hashes: List[str]
) -> List[Credentials]:
return _get_username_secret_credentials(usernames, lm_hashes, SecretType.LM_HASH)
def _get_username_nt_hash_credentials(
usernames: List[str], nt_hashes: List[str]
) -> List[Credentials]:
return _get_username_secret_credentials(usernames, nt_hashes, SecretType.NT_HASH)
def _get_username_secret_credentials(
usernames: List[str], secrets: List[str], secret_type: SecretType
) -> List[Credentials]:
username_secret_pairs = product(usernames, secrets)
return [
Credentials(credentials[0], credentials[1], secret_type)
for credentials in username_secret_pairs
]

View File

@ -6,12 +6,12 @@ from infection_monkey.exploit.powershell_utils.auth_options import (
ENCRYPTION_NEVER, ENCRYPTION_NEVER,
get_auth_options, get_auth_options,
) )
from infection_monkey.exploit.powershell_utils.credentials import Credentials from infection_monkey.exploit.powershell_utils.credentials import Credentials, SecretType
CREDENTIALS = [ CREDENTIALS = [
Credentials("user1", "password1"), Credentials("user1", "password1", SecretType.PASSWORD),
Credentials("user2", ""), Credentials("user2", "", SecretType.PASSWORD),
Credentials("user3", None), Credentials("user3", None, SecretType.CACHED),
] ]

View File

@ -1,44 +1,97 @@
from infection_monkey.exploit.powershell_utils.credentials import Credentials, get_credentials from infection_monkey.exploit.powershell_utils.credentials import (
Credentials,
SecretType,
get_credentials,
)
TEST_USERNAMES = ["user1", "user2"] TEST_USERNAMES = ["user1", "user2"]
TEST_PASSWORDS = ["p1", "p2"] TEST_PASSWORDS = ["p1", "p2"]
TEST_LM_HASHES = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"]
TEST_NT_HASHES = ["cccccccccccccccccccccccccccccccc", "dddddddddddddddddddddddddddddddd"]
def test_get_credentials__empty_windows_true(): def test_get_credentials__empty_windows_true():
credentials = get_credentials([], [], True) credentials = get_credentials([], [], [], [], True)
assert len(credentials) == 1 assert len(credentials) == 1
assert credentials[0] == Credentials(username=None, secret=None) assert credentials[0] == Credentials(username=None, secret=None, secret_type=SecretType.CACHED)
def test_get_credentials__empty_windows_false(): def test_get_credentials__empty_windows_false():
credentials = get_credentials([], [], False) credentials = get_credentials([], [], [], [], False)
assert len(credentials) == 0 assert len(credentials) == 0
def test_get_credentials__username_only_windows_true(): def test_get_credentials__username_only_windows_true():
credentials = get_credentials(TEST_USERNAMES, [], True) credentials = get_credentials(TEST_USERNAMES, [], [], [], True)
assert len(credentials) == 5 assert len(credentials) == 5
assert Credentials(username=TEST_USERNAMES[0], secret="") in credentials assert (
assert Credentials(username=TEST_USERNAMES[1], secret="") in credentials Credentials(username=TEST_USERNAMES[0], secret="", secret_type=SecretType.PASSWORD)
assert Credentials(username=TEST_USERNAMES[0], secret=None) in credentials in credentials
assert Credentials(username=TEST_USERNAMES[1], secret=None) in credentials )
assert (
Credentials(username=TEST_USERNAMES[1], secret="", secret_type=SecretType.PASSWORD)
in credentials
)
assert (
Credentials(username=TEST_USERNAMES[0], secret=None, secret_type=SecretType.CACHED)
in credentials
)
assert (
Credentials(username=TEST_USERNAMES[1], secret=None, secret_type=SecretType.CACHED)
in credentials
)
def test_get_credentials__username_only_windows_false(): def test_get_credentials__username_only_windows_false():
credentials = get_credentials(TEST_USERNAMES, [], False) credentials = get_credentials(TEST_USERNAMES, [], [], [], False)
assert len(credentials) == 2 assert len(credentials) == 2
assert Credentials(username=TEST_USERNAMES[0], secret="") in credentials assert (
assert Credentials(username=TEST_USERNAMES[1], secret="") in credentials Credentials(username=TEST_USERNAMES[0], secret="", secret_type=SecretType.PASSWORD)
in credentials
)
assert (
Credentials(username=TEST_USERNAMES[1], secret="", secret_type=SecretType.PASSWORD)
in credentials
)
def test_get_credentials__username_password_windows_true(): def test_get_credentials__username_password_windows_true():
credentials = get_credentials(TEST_USERNAMES, TEST_PASSWORDS, True) credentials = get_credentials(TEST_USERNAMES, TEST_PASSWORDS, [], [], True)
assert len(credentials) == 9 assert len(credentials) == 9
for user in TEST_USERNAMES: for user in TEST_USERNAMES:
for password in TEST_PASSWORDS: for password in TEST_PASSWORDS:
assert Credentials(username=user, secret=password) in credentials assert (
Credentials(username=user, secret=password, secret_type=SecretType.PASSWORD)
in credentials
)
def test_get_credentials__username_lm_hash_windows_false():
credentials = get_credentials(TEST_USERNAMES, TEST_PASSWORDS, TEST_LM_HASHES, [], False)
assert len(credentials) == 10
for user in TEST_USERNAMES:
for lm_hash in TEST_LM_HASHES:
assert (
Credentials(username=user, secret=lm_hash, secret_type=SecretType.LM_HASH)
in credentials
)
def test_get_credentials__username_nt_hash_windows_false():
credentials = get_credentials(
TEST_USERNAMES, TEST_PASSWORDS, TEST_LM_HASHES, TEST_NT_HASHES, False
)
assert len(credentials) == 14
for user in TEST_USERNAMES:
for nt_hash in TEST_NT_HASHES:
assert (
Credentials(username=user, secret=nt_hash, secret_type=SecretType.NT_HASH)
in credentials
)