Merge pull request #1723 from guardicore/1605-brute-force-utils
1605 brute force utils
This commit is contained in:
commit
5fe2f80aa4
|
@ -0,0 +1,40 @@
|
||||||
|
from itertools import chain, product
|
||||||
|
from typing import Any, Iterable, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
def generate_identity_secret_pairs(
|
||||||
|
identities: Iterable, secrets: Iterable
|
||||||
|
) -> Iterable[Tuple[Any, Any]]:
|
||||||
|
"""
|
||||||
|
Generates all possible combinations of identities and secrets (e.g. usernames and passwords).
|
||||||
|
:param identities: An iterable containing identity components of a credential pair
|
||||||
|
:param secrets: An iterable containing secret components of a credential pair
|
||||||
|
:return: An iterable of all combinations of identity/secret pairs. If either identities or
|
||||||
|
secrets is empty, an empty iterator is returned.
|
||||||
|
"""
|
||||||
|
return product(identities, secrets)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_username_password_or_ntlm_hash_combinations(
|
||||||
|
usernames: Iterable[str],
|
||||||
|
passwords: Iterable[str],
|
||||||
|
lm_hashes: Iterable[str],
|
||||||
|
nt_hashes: Iterable[str],
|
||||||
|
) -> Iterable[Tuple[str, str, str, str]]:
|
||||||
|
"""
|
||||||
|
Generates all possible combinations of the following: username/password, username/lm_hash,
|
||||||
|
username/nt_hash.
|
||||||
|
:param usernames: An iterable containing usernames
|
||||||
|
:param passwords: An iterable containing passwords
|
||||||
|
:param lm_hashes: An iterable containing lm_hashes
|
||||||
|
:param nt_hashes: An iterable containing nt_hashes
|
||||||
|
:return: An iterable containing tuples of all possible credentials combinations. Note that each
|
||||||
|
tuple will contain a username and at most one secret component (i.e. password, lm_hash,
|
||||||
|
nt_hash). If usernames is empty, an empty iterator is returned. If all secret component
|
||||||
|
iterators are empty, an empty iterator is returned.
|
||||||
|
"""
|
||||||
|
return chain(
|
||||||
|
product(usernames, passwords, [""], [""]),
|
||||||
|
product(usernames, [""], lm_hashes, [""]),
|
||||||
|
product(usernames, [""], [""], nt_hashes),
|
||||||
|
)
|
|
@ -0,0 +1,94 @@
|
||||||
|
from itertools import chain, compress
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from infection_monkey.utils.brute_force import (
|
||||||
|
generate_identity_secret_pairs,
|
||||||
|
generate_username_password_or_ntlm_hash_combinations,
|
||||||
|
)
|
||||||
|
|
||||||
|
USERNAMES = ["shaggy", "scooby"]
|
||||||
|
PASSWORDS = ["1234", "iloveyou", "the_cake_is_a_lie"]
|
||||||
|
EXPECTED_USERNAME_PASSWORD_PAIRS = {
|
||||||
|
(USERNAMES[0], PASSWORDS[0]),
|
||||||
|
(USERNAMES[0], PASSWORDS[1]),
|
||||||
|
(USERNAMES[0], PASSWORDS[2]),
|
||||||
|
(USERNAMES[1], PASSWORDS[0]),
|
||||||
|
(USERNAMES[1], PASSWORDS[1]),
|
||||||
|
(USERNAMES[1], PASSWORDS[2]),
|
||||||
|
}
|
||||||
|
|
||||||
|
LM_HASHES = ["DEADBEEF", "FACADE"]
|
||||||
|
EXPECTED_USERNAME_LM_PAIRS = {
|
||||||
|
(USERNAMES[0], LM_HASHES[0]),
|
||||||
|
(USERNAMES[0], LM_HASHES[1]),
|
||||||
|
(USERNAMES[1], LM_HASHES[0]),
|
||||||
|
(USERNAMES[1], LM_HASHES[1]),
|
||||||
|
}
|
||||||
|
|
||||||
|
NT_HASHES = ["FADED", "ADDED"]
|
||||||
|
EXPECTED_USERNAME_NT_PAIRS = {
|
||||||
|
(USERNAMES[0], NT_HASHES[0]),
|
||||||
|
(USERNAMES[0], NT_HASHES[1]),
|
||||||
|
(USERNAMES[1], NT_HASHES[0]),
|
||||||
|
(USERNAMES[1], NT_HASHES[1]),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_username_password_pairs():
|
||||||
|
generated_pairs = generate_identity_secret_pairs(USERNAMES, PASSWORDS)
|
||||||
|
assert set(generated_pairs) == EXPECTED_USERNAME_PASSWORD_PAIRS
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("usernames, passwords", [(USERNAMES, []), ([], PASSWORDS), ([], [])])
|
||||||
|
def test_generate_username_password_pairs__empty_inputs(usernames, passwords):
|
||||||
|
generated_pairs = generate_identity_secret_pairs(usernames, passwords)
|
||||||
|
assert len(set(generated_pairs)) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def generate_expected_username_password_hash_combinations(
|
||||||
|
passwords: bool, lm_hashes: bool, nt_hashes: bool
|
||||||
|
):
|
||||||
|
possible_combinations = (
|
||||||
|
{(p[0], p[1], "", "") for p in EXPECTED_USERNAME_PASSWORD_PAIRS},
|
||||||
|
{(p[0], "", p[1], "") for p in EXPECTED_USERNAME_LM_PAIRS},
|
||||||
|
{(p[0], "", "", p[1]) for p in EXPECTED_USERNAME_NT_PAIRS},
|
||||||
|
)
|
||||||
|
|
||||||
|
return set(
|
||||||
|
chain.from_iterable(compress(possible_combinations, (passwords, lm_hashes, nt_hashes)))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_username_password_or_ntlm_hash_pairs__empty_usernames():
|
||||||
|
generated_pairs = generate_username_password_or_ntlm_hash_combinations(
|
||||||
|
[], PASSWORDS, LM_HASHES, NT_HASHES
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(set(generated_pairs)) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"passwords,lm_hashes,nt_hashes",
|
||||||
|
[
|
||||||
|
(PASSWORDS, LM_HASHES, NT_HASHES),
|
||||||
|
([], LM_HASHES, NT_HASHES),
|
||||||
|
(PASSWORDS, [], NT_HASHES),
|
||||||
|
(PASSWORDS, LM_HASHES, []),
|
||||||
|
(PASSWORDS, [], []),
|
||||||
|
([], LM_HASHES, []),
|
||||||
|
([], [], NT_HASHES),
|
||||||
|
([], [], []),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_generate_username_password_or_ntlm_hash_pairs__with_usernames(
|
||||||
|
passwords, lm_hashes, nt_hashes
|
||||||
|
):
|
||||||
|
expected_credential_combinations = generate_expected_username_password_hash_combinations(
|
||||||
|
bool(passwords), bool(lm_hashes), bool(nt_hashes)
|
||||||
|
)
|
||||||
|
generated_pairs = generate_username_password_or_ntlm_hash_combinations(
|
||||||
|
USERNAMES, passwords, lm_hashes, nt_hashes
|
||||||
|
)
|
||||||
|
|
||||||
|
assert set(generated_pairs) == expected_credential_combinations
|
Loading…
Reference in New Issue