blob: 77df89603f4270a8dff91845622211eb86d2bd97 [file]
from unittest import mock
import pytest
from app.objects.c_adversary import Adversary
from app.objects.c_source import Source
from app.objects.secondclass.c_link import Link
from app.objects.secondclass.c_fact import Fact
from app.objects.secondclass.c_fact import OriginType
from app.objects.secondclass.c_relationship import Relationship
from app.service.interfaces.i_event_svc import EventServiceInterface
from app.utility.base_service import BaseService
@pytest.fixture
def fake_event_svc(event_loop):
class FakeEventService(BaseService, EventServiceInterface):
def __init__(self):
self.fired = {}
def reset(self):
self.fired = {}
async def observe_event(self, callback, exchange=None, queue=None):
pass
async def fire_event(self, exchange=None, queue=None, timestamp=True, **callback_kwargs):
self.fired[exchange, queue] = callback_kwargs
service = FakeEventService()
service.add_service('event_svc', service)
yield service
service.remove_service('event_svc')
class TestLink:
def test_link_eq(self, ability, executor):
test_executor = executor(name='psh', platform='windows')
test_ability = ability(ability_id='123', executors=[test_executor])
fact = Fact(trait='remote.host.fqdn', value='dc')
test_link = Link(command='sc.exe \\dc create sandsvc binpath= "s4ndc4t.exe -originLinkID 111111"',
paw='123456', ability=test_ability, id=111111, executor=test_executor)
test_link.used = [fact]
test_link2 = Link(command='sc.exe \\dc create sandsvc binpath= "s4ndc4t.exe -originLinkID 222222"',
paw='123456', ability=test_ability, id=222222, executor=test_executor)
test_link2.used = [fact]
assert test_link == test_link2
def test_link_neq(self, ability, executor):
test_executor = executor(name='psh', platform='windows')
test_ability = ability(ability_id='123', executors=[test_executor])
fact_a = Fact(trait='host.user.name', value='a')
fact_b = Fact(trait='host.user.name', value='b')
test_link_a = Link(command='net user a', paw='123456', ability=test_ability, id=111111, executor=test_executor)
test_link_a.used = [fact_a]
test_link_b = Link(command='net user b', paw='123456', ability=test_ability, id=222222, executor=test_executor)
test_link_b.used = [fact_b]
assert test_link_a != test_link_b
@mock.patch.object(Link, '_emit_status_change_event')
def test_no_status_change_event_on_instantiation(self, mock_emit_status_change_method, ability, executor):
executor = executor('psh', 'windows')
ability = ability(executor=executor)
Link(command='net user a', paw='123456', ability=ability, executor=executor)
mock_emit_status_change_method.assert_not_called()
@mock.patch.object(Link, '_emit_status_change_event')
def test_status_change_event_fired_on_status_change(self, mock_emit_status_change_method, ability, executor):
executor = executor('psh', 'windows')
ability = ability(executor=executor)
link = Link(command='net user a', paw='123456', ability=ability, executor=executor, status=-3)
link.status = -5
mock_emit_status_change_method.assert_called_with(from_status=-3, to_status=-5)
def test_emit_status_change_event(self, event_loop, fake_event_svc, ability, executor):
executor = executor('psh', 'windows')
ability = ability(executor=executor)
link = Link(command='net user a', paw='123456', ability=ability, executor=executor, status=-3)
fake_event_svc.reset()
event_loop.run_until_complete(
link._emit_status_change_event(
from_status=-3,
to_status=-5
)
)
expected_key = (Link.EVENT_EXCHANGE, Link.EVENT_QUEUE_STATUS_CHANGED)
assert expected_key in fake_event_svc.fired
event_kwargs = fake_event_svc.fired[expected_key]
assert event_kwargs['link'] == link.id
assert event_kwargs['from_status'] == -3
assert event_kwargs['to_status'] == -5
def test_link_agent_reported_time_not_present_when_none_roundtrip(self, ability, executor):
test_executor = executor(name='psh', platform='windows')
test_ability = ability(ability_id='123')
test_link = Link(command='sc.exe \\dc create sandsvc binpath= "s4ndc4t.exe -originLinkID 111111"',
paw='123456', ability=test_ability, executor=test_executor, id=111111)
serialized_link = test_link.display
loaded_link = Link.load(serialized_link)
assert 'agent_reported_time' not in serialized_link
assert loaded_link.agent_reported_time is None
def test_link_agent_reported_time_present_when_set_roundtrip(self, ability, executor):
agent_reported_time = '2021-02-23T11:50:16Z'
test_executor = executor(name='psh', platform='windows')
test_ability = ability(ability_id='123')
test_link = Link(command='sc.exe \\dc create sandsvc binpath= "s4ndc4t.exe -originLinkID 111111"',
paw='123456', ability=test_ability, executor=test_executor, id=111111,
agent_reported_time=BaseService.get_timestamp_from_string(agent_reported_time))
serialized_link = test_link.display
loaded_link = Link.load(serialized_link)
assert serialized_link['agent_reported_time'] == agent_reported_time
assert loaded_link.agent_reported_time == BaseService.get_timestamp_from_string(agent_reported_time)
def test_link_knowledge_svc_synchronization(self, event_loop, executor, ability, knowledge_svc, fire_event_mock):
test_executor = executor(name='psh', platform='windows')
test_ability = ability(ability_id='123', executors=[test_executor])
fact = Fact(trait='remote.host.fqdn', value='dc')
fact2 = Fact(trait='domain.user.name', value='Bob')
relationship = Relationship(source=fact, edge='has_admin', target=fact2)
test_link = Link(command='echo "this was a triumph"',
paw='123456', ability=test_ability, id=111111, executor=test_executor)
event_loop.run_until_complete(test_link.create_relationships([relationship], None))
checkable = [(x.trait, x.value) for x in test_link.facts]
assert (fact.trait, fact.value) in checkable
assert (fact2.trait, fact2.value) in checkable
knowledge_base_f = event_loop.run_until_complete(knowledge_svc.get_facts(dict(source=test_link.id)))
assert len(knowledge_base_f) == 2
assert test_link.id in knowledge_base_f[0].links
knowledge_base_r = event_loop.run_until_complete(knowledge_svc.get_relationships(dict(edge='has_admin')))
assert len(knowledge_base_r) == 1
def test_create_relationship_source_fact(self, event_loop, ability, executor, operation, data_svc, knowledge_svc, fire_event_mock):
test_executor = executor(name='psh', platform='windows')
test_ability = ability(ability_id='123', executors=[test_executor])
fact1 = Fact(trait='remote.host.fqdn', value='dc')
fact2 = Fact(trait='domain.user.name', value='Bob')
relationship = Relationship(source=fact1, edge='has_admin', target=fact2)
link1 = Link(command='echo "Bob"', paw='123456', ability=test_ability, id='111111', executor=test_executor)
operation = operation(name='test-op', agents=[],
adversary=Adversary(name='sample', adversary_id='XYZ', atomic_ordering=[],
description='test'),
source=Source(id='test-source', facts=[fact1]))
event_loop.run_until_complete(data_svc.store(operation.source))
event_loop.run_until_complete(operation._init_source())
event_loop.run_until_complete(link1.create_relationships([relationship], operation))
link2 = Link(command='echo "Bob"', paw='789100', ability=test_ability, id='222222', executor=test_executor)
event_loop.run_until_complete(link2.create_relationships([relationship], operation))
fact_store_operation_source = event_loop.run_until_complete(knowledge_svc.get_facts(dict(source=operation.source.id)))
fact_store_operation = event_loop.run_until_complete(knowledge_svc.get_facts(dict(source=operation.id)))
assert len(fact_store_operation_source) == 1
assert len(fact_store_operation) == 1
assert len(fact_store_operation_source[0].collected_by) == 2
def test_save_discover_seeded_fact_not_in_command(self, event_loop, ability, executor, operation, knowledge_svc, data_svc, fire_event_mock):
test_executor = executor(name='psh', platform='windows')
test_ability = ability(ability_id='123', executors=[test_executor])
fact1 = Fact(trait='remote.host.fqdn', value='dc')
fact2 = Fact(trait='domain.user.name', value='Bob')
relationship = Relationship(source=fact1, edge='has_user', target=fact2)
link = Link(command='net user', paw='123456', ability=test_ability, id='111111', executor=test_executor)
operation = operation(name='test-op', agents=[],
adversary=Adversary(name='sample', adversary_id='XYZ', atomic_ordering=[],
description='test'),
source=Source(id='test-source', facts=[fact1, fact2]))
event_loop.run_until_complete(data_svc.store(operation.source))
event_loop.run_until_complete(operation._init_source())
event_loop.run_until_complete(link.save_fact(operation, fact2, 1, relationship))
assert fact2.origin_type == OriginType.SEEDED
assert '123456' in fact2.collected_by