Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouremetis committed Apr 11, 2023
1 parent bcc0c26 commit 8128c0c
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 1 deletion.
11 changes: 10 additions & 1 deletion app/api/v2/handlers/adversary_api.py
Expand Up @@ -118,6 +118,15 @@ async def delete_adversary(self, request: web.Request):
await self.delete_on_disk_object(request)
return web.HTTPNoContent()

@aiohttp_apispec.docs(tags=['adversaries'], summary='Gets fact analysis for an adversary.',
description='Gets fact analysis for an adversary.')
@aiohttp_apispec.request_schema(AdversarySchema(partial=True))
@aiohttp_apispec.response_schema(description='The response is the fact and requirement analysis for the adversary')
async def get_adversary_fact_analysis(self, request: web.Request):
data = await request.json()
analysis = await self._api_manager.fact_analysis(data)
return web.json_response(analysis)

async def create_on_disk_object(self, request: web.Request):
data = await request.json()
data.pop('id', None)
Expand All @@ -127,7 +136,7 @@ async def create_on_disk_object(self, request: web.Request):
self.obj_class)
return obj

async def _parse_common_data_from_request(self, request) -> (dict, dict, str, dict, dict):
async def _parse_common_data_from_request(self, request) -> tuple(dict, dict, str, dict, dict):
data = {}
raw_body = await request.read()
if raw_body:
Expand Down
4 changes: 4 additions & 0 deletions app/api/v2/managers/adversary_api_manager.py
Expand Up @@ -10,3 +10,7 @@ async def verify_adversary(self, adversary: Adversary):
adversary.verify(log=self.log, abilities=self._data_svc.ram['abilities'],
objectives=self._data_svc.ram['objectives'])
return adversary

async def fact_analysis(self, data: dict):
fact_reqs = await self._planning_svc.adversary_fact_requirements(**data)
# TODO: ability/ATT&CK suggestions for missing facts
11 changes: 11 additions & 0 deletions app/objects/c_ability.py
Expand Up @@ -118,6 +118,17 @@ def store(self, ram):
async def which_plugin(self):
return self.plugin

def get_executors(self):
"""Retrieve all executors defined for the ability"""
executors_ = dict()
for key, executor in self._executor_map.items():
name, platform = key
if platform not in executors_:
executors_[platform] = {}
if name not in executors_[platform]:
executors_[platform][name] = executor
return executors_

def find_executor(self, name, platform):
return self._executor_map.get(self._make_executor_map_key(name, platform))

Expand Down
41 changes: 41 additions & 0 deletions app/service/planning_svc.py
@@ -1,3 +1,5 @@
import re

from app.objects.secondclass.c_link import Link
from app.service.interfaces.i_planning_svc import PlanningServiceInterface
from app.utility.base_planning_svc import BasePlanningService
Expand Down Expand Up @@ -263,6 +265,45 @@ async def update_stopping_condition_met(self, planner, operation):
planner.stopping_condition_met = await self.check_stopping_conditions(planner.stopping_conditions,
operation)

async def adversary_fact_requirements(self, adversary_id=None, atomic_ordering=None):
""" """
fr = dict(errors=[])
facts_produced = []
required_facts = []
if atomic_ordering is None:
adversary = await self.get_service('data_svc') \
.locate('adversary', match=dict(adversary_id=adversary_id))
if not adversary:
fr['errors'].append(f'Adversary (ID: {adversary_id}) not found')
return fr
atomic_ordering = adversary.atomic_ordering

for ability_id in atomic_ordering:
ability = await self.get_service('data_svc') \
.locate('ability', match=dict(ability_id=ability_id))
if ability is None:
fr['errors'].append('Ability (ID: {ability_id}) not found')
continue

# record produced and required facts
executors = ability.get_exectuors()
for _platform, name_executor in executors.items():
for _name, executor in name_executor.items():
# record produced facts
for parser in executor.parsers:
for parserconfig in parser.parserconfigs:
for fact_type in ['source', 'target', 'edge']:
fact_ = getattr(parserconfig, fact_type, False)
if fact_:
facts_produced.append(fact_)
# record required facts
for fact_ in re.findall(BasePlanningService.re_variable, executor.test):
required_facts.append(fact_)

# Required facts gap
# HERE
return None

@staticmethod
async def sort_links(links):
"""Sort links by score and atomic ordering in adversary profile
Expand Down

0 comments on commit 8128c0c

Please sign in to comment.