Agent: change the interface of Credentials

Refactor from dataclass to object with tuples. This enforces read only identities and secrets so users don't modify them
This commit is contained in:
vakarisz 2022-02-15 18:39:17 +02:00
parent 8868fb9b0c
commit ac376a0014
3 changed files with 59 additions and 29 deletions

View File

@ -1,10 +1,11 @@
from dataclasses import dataclass from typing import Iterable
from typing import List
from .credential_components.i_credential_component import ICredentialComponent from .credential_components.i_credential_component import ICredentialComponent
@dataclass
class Credentials: class Credentials:
identities: List[ICredentialComponent] def __init__(
secrets: List[ICredentialComponent] self, identities: Iterable[ICredentialComponent], secrets: Iterable[ICredentialComponent]
):
self.identities = tuple(identities)
self.secrets = tuple(secrets)

View File

@ -8,7 +8,6 @@ from infection_monkey.credential_collectors import (
Password, Password,
Username, Username,
) )
from . import pypykatz_handler from . import pypykatz_handler
from .windows_credentials import WindowsCredentials from .windows_credentials import WindowsCredentials
@ -22,24 +21,24 @@ class MimikatzCredentialCollector(ICredentialCollector):
def _to_credentials(win_creds: List[WindowsCredentials]) -> [Credentials]: def _to_credentials(win_creds: List[WindowsCredentials]) -> [Credentials]:
all_creds = [] all_creds = []
for win_cred in win_creds: for win_cred in win_creds:
creds_obj = Credentials(identities=[], secrets=[]) identities = []
secrets = []
if win_cred.username: if win_cred.username:
identity = Username(win_cred.username) identity = Username(win_cred.username)
creds_obj.identities.append(identity) identities.append(identity)
if win_cred.password: if win_cred.password:
password = Password(win_cred.password) password = Password(win_cred.password)
creds_obj.secrets.append(password) secrets.append(password)
if win_cred.lm_hash: if win_cred.lm_hash:
lm_hash = LMHash(lm_hash=win_cred.lm_hash) lm_hash = LMHash(lm_hash=win_cred.lm_hash)
creds_obj.secrets.append(lm_hash) secrets.append(lm_hash)
if win_cred.ntlm_hash: if win_cred.ntlm_hash:
lm_hash = NTHash(nt_hash=win_cred.ntlm_hash) lm_hash = NTHash(nt_hash=win_cred.ntlm_hash)
creds_obj.secrets.append(lm_hash) secrets.append(lm_hash)
if creds_obj.identities != [] or creds_obj.secrets != []:
all_creds.append(creds_obj)
if identities != [] or secrets != []:
all_creds.append(Credentials(identities, secrets))
return all_creds return all_creds

View File

@ -1,4 +1,4 @@
from infection_monkey.credential_collectors import Credentials, LMHash, NTHash, Password, Username from infection_monkey.credential_collectors import LMHash, NTHash, Password, Username
from infection_monkey.credential_collectors.mimikatz_collector.mimikatz_cred_collector import ( from infection_monkey.credential_collectors.mimikatz_collector.mimikatz_cred_collector import (
MimikatzCredentialCollector, MimikatzCredentialCollector,
) )
@ -28,27 +28,57 @@ def test_empty_results(monkeypatch):
def test_pypykatz_result_parsing(monkeypatch): def test_pypykatz_result_parsing(monkeypatch):
win_creds = [WindowsCredentials(username="user", password="secret", ntlm_hash="", lm_hash="")]
patch_pypykatz(win_creds, monkeypatch)
# Expected credentials
username = Username("user")
password = Password("secret")
collected = MimikatzCredentialCollector().collect_credentials()
assert len(list(collected)) == 1
assert list(collected)[0].identities[0].__dict__ == username.__dict__
assert list(collected)[0].secrets[0].__dict__ == password.__dict__
def test_pypykatz_result_parsing_duplicates(monkeypatch):
win_creds = [ win_creds = [
WindowsCredentials(username="user", password="secret", ntlm_hash="", lm_hash=""), WindowsCredentials(username="user", password="secret", ntlm_hash="", lm_hash=""),
WindowsCredentials(username="", password="", ntlm_hash="ntlm_hash", lm_hash="lm_hash"),
WindowsCredentials(username="user", password="secret", ntlm_hash="", lm_hash=""), WindowsCredentials(username="user", password="secret", ntlm_hash="", lm_hash=""),
]
patch_pypykatz(win_creds, monkeypatch)
collected = MimikatzCredentialCollector().collect_credentials()
assert len(list(collected)) == 2
def test_pypykatz_result_parsing_defaults(monkeypatch):
win_creds = [
WindowsCredentials(username="user2", password="secret2", lm_hash="lm_hash"), WindowsCredentials(username="user2", password="secret2", lm_hash="lm_hash"),
] ]
patch_pypykatz(win_creds, monkeypatch) patch_pypykatz(win_creds, monkeypatch)
# Expected credentials # Expected credentials
username = Username("user") username = Username("user2")
username2 = Username("user2") password = Password("secret2")
password = Password("secret") lm_hash = LMHash("lm_hash")
password2 = Password("secret2")
nt_hash = NTHash(nt_hash="ntlm_hash")
lm_hash = LMHash(lm_hash="lm_hash")
expected = [
Credentials(identities=[username], secrets=[password]),
Credentials(identities=[], secrets=[lm_hash, nt_hash]),
Credentials(identities=[username], secrets=[password]),
Credentials(identities=[username2], secrets=[password2, lm_hash]),
]
collected = MimikatzCredentialCollector().collect_credentials() collected = MimikatzCredentialCollector().collect_credentials()
assert expected == collected assert list(collected)[0].identities[0].__dict__ == username.__dict__
assert list(collected)[0].secrets[0].__dict__ == password.__dict__
assert list(collected)[0].secrets[1].__dict__ == lm_hash.__dict__
def test_pypykatz_result_parsing_no_identities(monkeypatch):
win_creds = [
WindowsCredentials(username="", password="", ntlm_hash="ntlm_hash", lm_hash="lm_hash"),
]
patch_pypykatz(win_creds, monkeypatch)
# Expected credentials
nt_hash = NTHash("ntlm_hash")
lm_hash = LMHash("lm_hash")
collected = MimikatzCredentialCollector().collect_credentials()
assert list(collected)[0].secrets[0].__dict__ == lm_hash.__dict__
assert list(collected)[0].secrets[1].__dict__ == nt_hash.__dict__