Merge pull request #2063 from guardicore/1965-retrieve-credentials

1965 retrieve credentials
This commit is contained in:
Mike Salvatore 2022-07-07 08:44:53 -04:00 committed by GitHub
commit 540519e3c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 116 additions and 54 deletions

View File

@ -10,3 +10,4 @@ from .i_agent_configuration_repository import IAgentConfigurationRepository
from .file_agent_configuration_repository import FileAgentConfigurationRepository
from .i_simulation_repository import ISimulationRepository
from .file_simulation_repository import FileSimulationRepository
from .i_credentials_repository import ICredentialsRepository

View File

@ -1,15 +1,16 @@
from flask import jsonify
from monkey_island.cc.repository import ICredentialsRepository
from monkey_island.cc.resources.AbstractResource import AbstractResource
from monkey_island.cc.services.config import ConfigService
class PropagationCredentials(AbstractResource):
urls = ["/api/propagation-credentials"]
def __init__(self, credentials_repository: ICredentialsRepository):
self._credentials_repository = credentials_repository
def get(self):
config = ConfigService.get_flat_config(should_decrypt=True)
propagation_credentials = self._credentials_repository.get_all_credentials()
propagation_credentials = ConfigService.get_config_propagation_credentials_from_flat_config(
config
)
return {"propagation_credentials": propagation_credentials}
return jsonify(propagation_credentials)

View File

@ -1,7 +1,6 @@
import collections
import functools
import logging
from typing import Dict, List
from common.config_value_paths import (
LM_HASH_LIST_PATH,
@ -98,25 +97,6 @@ class ConfigService:
mongo_key = ".".join(config_key_as_arr)
mongo.db.config.update({}, {"$set": {mongo_key: value}})
@staticmethod
def get_flat_config(should_decrypt=True):
config_json = ConfigService.get_config(should_decrypt)
flat_config_json = {}
for i in config_json:
if i == "ransomware":
# Don't flatten the ransomware because ransomware payload expects a dictionary #1260
flat_config_json[i] = config_json[i]
continue
for j in config_json[i]:
for k in config_json[i][j]:
if isinstance(config_json[i][j][k], dict):
for key, value in config_json[i][j][k].items():
flat_config_json[key] = value
else:
flat_config_json[k] = config_json[i][j][k]
return flat_config_json
# Not added to interface because it's doable by get_config_field + set_config_field
@staticmethod
def add_item_to_config_set_if_dont_exist(item_path_array, item_value, should_encrypt):
@ -251,13 +231,3 @@ class ConfigService:
if is_decrypt
else get_datastore_encryptor().encrypt(config_arr)
)
@staticmethod
def get_config_propagation_credentials_from_flat_config(config) -> Dict[str, List[str]]:
return {
"exploit_user_list": config.get("exploit_user_list", []),
"exploit_password_list": config.get("exploit_password_list", []),
"exploit_lm_hash_list": config.get("exploit_lm_hash_list", []),
"exploit_ntlm_hash_list": config.get("exploit_ntlm_hash_list", []),
"exploit_ssh_keys": config.get("exploit_ssh_keys", []),
}

View File

@ -3,3 +3,8 @@ from .mock_file_repository import MockFileRepository, FILE_CONTENTS, FILE_NAME
from .open_error_file_repository import OpenErrorFileRepository
from .in_memory_agent_configuration_repository import InMemoryAgentConfigurationRepository
from .in_memory_simulation_configuration import InMemorySimulationRepository
from .stub_propagation_credentials_repository import StubPropagationCredentialsRepository
from .stub_propagation_credentials_repository import (
PROPAGATION_CREDENTIALS_1,
PROPAGATION_CREDENTIALS_2,
)

View File

@ -0,0 +1,63 @@
from typing import Sequence
from monkey_island.cc.repository import ICredentialsRepository
from monkey_island.cc.services.telemetry.processing.credentials import Credentials
fake_username = "m0nk3y_user"
fake_special_username = "m0nk3y.user"
fake_nt_hash = "c1c58f96cdf212b50837bc11a00be47c"
fake_lm_hash = "299BD128C1101FD6"
fake_password_1 = "trytostealthis"
fake_password_2 = "password"
fake_password_3 = "12345678"
PROPAGATION_CREDENTIALS_1 = {
"identities": [{"username": fake_username, "credential_type": "USERNAME"}],
"secrets": [
{"nt_hash": fake_nt_hash, "credential_type": "NT_HASH"},
{"lm_hash": fake_lm_hash, "credential_type": "LM_HASH"},
{"password": fake_password_1, "credential_type": "PASSWORD"},
],
}
PROPAGATION_CREDENTIALS_2 = {
"identities": [
{"username": fake_username, "credential_type": "USERNAME"},
{"username": fake_special_username, "credential_type": "USERNAME"},
],
"secrets": [
{"password": fake_password_1, "credential_type": "PASSWORD"},
{"password": fake_password_2, "credential_type": "PASSWORD"},
{"password": fake_password_3, "credential_type": "PASSWORD"},
],
}
# TODO: Use Credentials from common.credentials when serialization is implemented
class StubPropagationCredentialsRepository(ICredentialsRepository):
def get_configured_credentials(self) -> Sequence[Credentials]:
pass
def get_stolen_credentials(self) -> Sequence[Credentials]:
pass
def get_all_credentials(self) -> Sequence[Credentials]:
return [
Credentials.from_mapping(PROPAGATION_CREDENTIALS_1, monkey_guid="some_guid"),
Credentials.from_mapping(PROPAGATION_CREDENTIALS_2, monkey_guid="second_guid"),
]
def save_configured_credentials(self, credentials: Credentials):
pass
def save_stolen_credentials(self, credentials: Credentials):
pass
def remove_configured_credentials(self):
pass
def remove_stolen_credentials(self):
pass
def remove_all_credentials(self):
pass

View File

@ -0,0 +1,39 @@
import json
import pytest
from tests.common import StubDIContainer
from tests.monkey_island import (
PROPAGATION_CREDENTIALS_1,
PROPAGATION_CREDENTIALS_2,
StubPropagationCredentialsRepository,
)
from tests.unit_tests.monkey_island.conftest import get_url_for_resource
from monkey_island.cc.repository import ICredentialsRepository
from monkey_island.cc.resources.propagation_credentials import PropagationCredentials
@pytest.fixture
def flask_client(build_flask_client):
container = StubDIContainer()
container.register(ICredentialsRepository, StubPropagationCredentialsRepository)
with build_flask_client(container) as flask_client:
yield flask_client
def test_propagation_credentials_endpoint_get(flask_client):
propagation_credentials_url = get_url_for_resource(PropagationCredentials)
resp = flask_client.get(propagation_credentials_url)
assert resp.status_code == 200
actual_propagation_credentials = json.loads(resp.data)
assert len(actual_propagation_credentials) == 2
# TODO: delete the removal of monkey_guid key when the serialization of credentials
del actual_propagation_credentials[0]["monkey_guid"]
assert actual_propagation_credentials[0] == PROPAGATION_CREDENTIALS_1
del actual_propagation_credentials[1]["monkey_guid"]
assert actual_propagation_credentials[1] == PROPAGATION_CREDENTIALS_2

View File

@ -1,17 +0,0 @@
from monkey_island.cc.services.config import ConfigService
# If tests fail because config path is changed, sync with
# monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js
def test_get_config_propagation_credentials_from_flat_config(flat_monkey_config):
expected_creds = {
"exploit_lm_hash_list": ["lm_hash_1", "lm_hash_2"],
"exploit_ntlm_hash_list": ["nt_hash_1", "nt_hash_2", "nt_hash_3"],
"exploit_password_list": ["test", "iloveyou", "12345"],
"exploit_ssh_keys": [{"private_key": "my_private_key", "public_key": "my_public_key"}],
"exploit_user_list": ["Administrator", "root", "user", "ubuntu"],
}
creds = ConfigService.get_config_propagation_credentials_from_flat_config(flat_monkey_config)
assert creds == expected_creds