forked from p15670423/monkey
Agent: Add telemetry type for sending stolen credentials
This commit is contained in:
parent
49f1675b38
commit
040b37697b
|
@ -9,3 +9,4 @@ class TelemCategoryEnum:
|
||||||
ATTACK = "attack"
|
ATTACK = "attack"
|
||||||
FILE_ENCRYPTION = "file_encryption"
|
FILE_ENCRYPTION = "file_encryption"
|
||||||
AWS_INFO = "aws_info"
|
AWS_INFO = "aws_info"
|
||||||
|
CREDENTIALS = "credentials"
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import enum
|
||||||
|
import json
|
||||||
|
from typing import Dict, Iterable
|
||||||
|
|
||||||
|
from common.common_consts.telem_categories import TelemCategoryEnum
|
||||||
|
from infection_monkey.i_puppet.credential_collection import Credentials, ICredentialComponent
|
||||||
|
from infection_monkey.telemetry.base_telem import BaseTelem
|
||||||
|
|
||||||
|
|
||||||
|
class CredentialsTelem(BaseTelem):
|
||||||
|
telem_category = TelemCategoryEnum.CREDENTIALS
|
||||||
|
|
||||||
|
def __init__(self, credentials: Iterable[Credentials]):
|
||||||
|
"""
|
||||||
|
Used to send information about stolen or discovered credentials to the Island.
|
||||||
|
:param credentials: An iterable containing credentials to be sent to the Island.
|
||||||
|
"""
|
||||||
|
self._credentials = credentials
|
||||||
|
|
||||||
|
def get_data(self) -> Dict:
|
||||||
|
# TODO: At a later time we can consider factoring this into a Serializer class or similar.
|
||||||
|
return json.loads(json.dumps(self._credentials, default=_serialize))
|
||||||
|
|
||||||
|
|
||||||
|
def _serialize(obj):
|
||||||
|
if isinstance(obj, enum.Enum):
|
||||||
|
return obj.name
|
||||||
|
|
||||||
|
if isinstance(obj, ICredentialComponent):
|
||||||
|
# This is a workaround for ICredentialComponents that are implemented as dataclasses. If the
|
||||||
|
# credential_type attribute is populated with `field(init=False, ...)`, then credential_type
|
||||||
|
# is not added to the object's __dict__ attribute. The biggest risk of this workaround is
|
||||||
|
# that we might change the name of the credential_type field in ICredentialComponents, but
|
||||||
|
# automated refactoring tools would not detect that this string needs to change. This is
|
||||||
|
# mittigated by the call to getattr() below, which will raise an AttributeException if the
|
||||||
|
# attribute name changes and a unit test will fail under these conditions.
|
||||||
|
credential_type = getattr(obj, "credential_type")
|
||||||
|
return dict(obj.__dict__, **{"credential_type": credential_type})
|
||||||
|
|
||||||
|
return getattr(obj, "__dict__", str(obj))
|
|
@ -0,0 +1,37 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
from infection_monkey.credential_collectors import Password, SSHKeypair, Username
|
||||||
|
from infection_monkey.i_puppet import Credentials
|
||||||
|
from infection_monkey.telemetry.credentials_telem import CredentialsTelem
|
||||||
|
|
||||||
|
|
||||||
|
def test_credential_telem_send(spy_send_telemetry):
|
||||||
|
username = "m0nkey"
|
||||||
|
password = "mmm"
|
||||||
|
public_key = "pub_key"
|
||||||
|
private_key = "priv_key"
|
||||||
|
|
||||||
|
expected_data = [
|
||||||
|
{
|
||||||
|
"identities": [{"username": username, "credential_type": "USERNAME"}],
|
||||||
|
"secrets": [
|
||||||
|
{"password": password, "credential_type": "PASSWORD"},
|
||||||
|
{
|
||||||
|
"private_key": "pub_key",
|
||||||
|
"public_key": "priv_key",
|
||||||
|
"credential_type": "SSH_KEYPAIR",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
credentials = Credentials(
|
||||||
|
[Username(username)], [Password(password), SSHKeypair(public_key, private_key)]
|
||||||
|
)
|
||||||
|
|
||||||
|
telem = CredentialsTelem([credentials])
|
||||||
|
telem.send()
|
||||||
|
|
||||||
|
expected_data = json.dumps(expected_data, cls=telem.json_encoder)
|
||||||
|
assert spy_send_telemetry.data == expected_data
|
||||||
|
assert spy_send_telemetry.telem_category == "credentials"
|
Loading…
Reference in New Issue