Merge pull request #2301 from guardicore/2180-credentials-event-encoding
2180 credentials event encoding
This commit is contained in:
commit
ae073de766
|
@ -3,5 +3,6 @@ from .nt_hash import NTHash
|
||||||
from .password import Password
|
from .password import Password
|
||||||
from .ssh_keypair import SSHKeypair
|
from .ssh_keypair import SSHKeypair
|
||||||
from .username import Username
|
from .username import Username
|
||||||
|
from .encoding import get_plaintext, SecretEncodingConfig
|
||||||
|
|
||||||
from .credentials import Credentials
|
from .credentials import Credentials
|
||||||
|
|
|
@ -2,22 +2,14 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from pydantic import SecretBytes, SecretStr
|
|
||||||
|
|
||||||
from ..base_models import InfectionMonkeyBaseModel, InfectionMonkeyModelConfig
|
from ..base_models import InfectionMonkeyBaseModel, InfectionMonkeyModelConfig
|
||||||
from . import LMHash, NTHash, Password, SSHKeypair, Username
|
from . import LMHash, NTHash, Password, SSHKeypair, Username
|
||||||
|
from .encoding import SecretEncodingConfig
|
||||||
|
|
||||||
Secret = Union[Password, LMHash, NTHash, SSHKeypair]
|
Secret = Union[Password, LMHash, NTHash, SSHKeypair]
|
||||||
Identity = Username
|
Identity = Username
|
||||||
|
|
||||||
|
|
||||||
def get_plaintext(secret: Union[SecretStr, SecretBytes, None, str]) -> Optional[str]:
|
|
||||||
if isinstance(secret, (SecretStr, SecretBytes)):
|
|
||||||
return secret.get_secret_value()
|
|
||||||
else:
|
|
||||||
return secret
|
|
||||||
|
|
||||||
|
|
||||||
class Credentials(InfectionMonkeyBaseModel):
|
class Credentials(InfectionMonkeyBaseModel):
|
||||||
"""Represents a credential pair (an identity and a secret)"""
|
"""Represents a credential pair (an identity and a secret)"""
|
||||||
|
|
||||||
|
@ -27,9 +19,5 @@ class Credentials(InfectionMonkeyBaseModel):
|
||||||
secret: Optional[Secret]
|
secret: Optional[Secret]
|
||||||
"""Secret part of credentials, like a password or a hash"""
|
"""Secret part of credentials, like a password or a hash"""
|
||||||
|
|
||||||
class Config(InfectionMonkeyModelConfig):
|
class Config(SecretEncodingConfig, InfectionMonkeyModelConfig):
|
||||||
json_encoders = {
|
pass
|
||||||
# This makes secrets dumpable to json, but not loggable
|
|
||||||
SecretStr: get_plaintext,
|
|
||||||
SecretBytes: get_plaintext,
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
|
from pydantic import SecretBytes, SecretStr
|
||||||
|
|
||||||
|
|
||||||
|
def get_plaintext(secret: Union[SecretStr, SecretBytes, None, str]) -> Optional[str]:
|
||||||
|
if isinstance(secret, (SecretStr, SecretBytes)):
|
||||||
|
return secret.get_secret_value()
|
||||||
|
else:
|
||||||
|
return secret
|
||||||
|
|
||||||
|
|
||||||
|
class SecretEncodingConfig:
|
||||||
|
json_encoders = {
|
||||||
|
# This makes secrets dumpable to json, but not loggable
|
||||||
|
SecretStr: get_plaintext,
|
||||||
|
SecretBytes: get_plaintext,
|
||||||
|
}
|
|
@ -2,8 +2,10 @@ from typing import Sequence
|
||||||
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
|
from common.base_models import InfectionMonkeyModelConfig
|
||||||
from common.credentials import Credentials
|
from common.credentials import Credentials
|
||||||
|
|
||||||
|
from ..credentials.encoding import SecretEncodingConfig
|
||||||
from . import AbstractAgentEvent
|
from . import AbstractAgentEvent
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,3 +18,6 @@ class CredentialsStolenEvent(AbstractAgentEvent):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stolen_credentials: Sequence[Credentials] = Field(default_factory=list)
|
stolen_credentials: Sequence[Credentials] = Field(default_factory=list)
|
||||||
|
|
||||||
|
class Config(SecretEncodingConfig, InfectionMonkeyModelConfig):
|
||||||
|
pass
|
||||||
|
|
|
@ -6,7 +6,7 @@ from typing import Sequence, Tuple
|
||||||
import pymssql
|
import pymssql
|
||||||
|
|
||||||
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
|
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
|
||||||
from common.credentials.credentials import get_plaintext
|
from common.credentials import get_plaintext
|
||||||
from common.utils.exceptions import FailedExploitationError
|
from common.utils.exceptions import FailedExploitationError
|
||||||
from infection_monkey.exploit.HostExploiter import HostExploiter
|
from infection_monkey.exploit.HostExploiter import HostExploiter
|
||||||
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
|
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
|
||||||
|
|
|
@ -11,7 +11,7 @@ from pypsrp.powershell import PowerShell, RunspacePool
|
||||||
from typing_extensions import Protocol
|
from typing_extensions import Protocol
|
||||||
from urllib3 import connectionpool
|
from urllib3 import connectionpool
|
||||||
|
|
||||||
from common.credentials.credentials import get_plaintext
|
from common.credentials import get_plaintext
|
||||||
from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions
|
from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions
|
||||||
from infection_monkey.exploit.powershell_utils.credentials import Credentials, SecretType
|
from infection_monkey.exploit.powershell_utils.credentials import Credentials, SecretType
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from impacket.dcerpc.v5 import scmr, transport
|
||||||
from impacket.dcerpc.v5.scmr import DCERPCSessionError
|
from impacket.dcerpc.v5.scmr import DCERPCSessionError
|
||||||
|
|
||||||
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
|
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
|
||||||
from common.credentials.credentials import get_plaintext
|
from common.credentials import get_plaintext
|
||||||
from common.utils.attack_utils import ScanStatus, UsageEnum
|
from common.utils.attack_utils import ScanStatus, UsageEnum
|
||||||
from infection_monkey.exploit.HostExploiter import HostExploiter
|
from infection_monkey.exploit.HostExploiter import HostExploiter
|
||||||
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
|
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
|
||||||
|
|
|
@ -6,7 +6,7 @@ import paramiko
|
||||||
|
|
||||||
from common import OperatingSystem
|
from common import OperatingSystem
|
||||||
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
|
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
|
||||||
from common.credentials.credentials import get_plaintext
|
from common.credentials import get_plaintext
|
||||||
from common.utils import Timer
|
from common.utils import Timer
|
||||||
from common.utils.attack_utils import ScanStatus
|
from common.utils.attack_utils import ScanStatus
|
||||||
from common.utils.exceptions import FailedExploitationError
|
from common.utils.exceptions import FailedExploitationError
|
||||||
|
|
|
@ -10,7 +10,7 @@ from impacket.smb3structs import SMB2_DIALECT_002, SMB2_DIALECT_21
|
||||||
from impacket.smbconnection import SMB_DIALECT, SMBConnection
|
from impacket.smbconnection import SMB_DIALECT, SMBConnection
|
||||||
from pydantic import SecretStr
|
from pydantic import SecretStr
|
||||||
|
|
||||||
from common.credentials.credentials import get_plaintext
|
from common.credentials import get_plaintext
|
||||||
from common.utils.attack_utils import ScanStatus
|
from common.utils.attack_utils import ScanStatus
|
||||||
from infection_monkey.network.tools import get_interface_to_target
|
from infection_monkey.network.tools import get_interface_to_target
|
||||||
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
|
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
|
||||||
|
|
|
@ -5,7 +5,7 @@ import traceback
|
||||||
|
|
||||||
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
from impacket.dcerpc.v5.rpcrt import DCERPCException
|
||||||
|
|
||||||
from common.credentials.credentials import get_plaintext
|
from common.credentials import get_plaintext
|
||||||
from infection_monkey.exploit.HostExploiter import HostExploiter
|
from infection_monkey.exploit.HostExploiter import HostExploiter
|
||||||
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
|
from infection_monkey.exploit.tools.helpers import get_agent_dst_path
|
||||||
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
||||||
|
|
|
@ -16,8 +16,7 @@ from tests.data_for_tests.propagation_credentials import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from common.base_models import InfectionMonkeyBaseModel
|
from common.base_models import InfectionMonkeyBaseModel
|
||||||
from common.credentials import Credentials
|
from common.credentials import Credentials, get_plaintext
|
||||||
from common.credentials.credentials import get_plaintext
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
from tests.data_for_tests.propagation_credentials import (
|
||||||
|
CREDENTIALS,
|
||||||
|
PLAINTEXT_LM_HASH,
|
||||||
|
PLAINTEXT_NT_HASH,
|
||||||
|
PLAINTEXT_PASSWORD,
|
||||||
|
PLAINTEXT_PRIVATE_KEY,
|
||||||
|
)
|
||||||
|
from tests.unit_tests.monkey_island.cc.models.test_agent import AGENT_ID
|
||||||
|
|
||||||
|
from common.events import CredentialsStolenEvent
|
||||||
|
|
||||||
|
TEST_EVENT = CredentialsStolenEvent(stolen_credentials=CREDENTIALS, source=AGENT_ID)
|
||||||
|
|
||||||
|
|
||||||
|
def test_credentials_stolen_event_serialization_json():
|
||||||
|
serialized_event = TEST_EVENT.json()
|
||||||
|
assert PLAINTEXT_PASSWORD in serialized_event
|
||||||
|
assert PLAINTEXT_LM_HASH in serialized_event
|
||||||
|
assert PLAINTEXT_NT_HASH in serialized_event
|
||||||
|
assert PLAINTEXT_PRIVATE_KEY in serialized_event
|
||||||
|
|
||||||
|
|
||||||
|
def test_credential_stolen_event_deserialization_json():
|
||||||
|
serialized_event = TEST_EVENT.json()
|
||||||
|
deserialized_event = CredentialsStolenEvent.parse_raw(serialized_event)
|
||||||
|
assert deserialized_event == TEST_EVENT
|
Loading…
Reference in New Issue