ATT&CK fields can be mapped together, ATT&CK configuration gets translated to monkey's configuration
This commit is contained in:
parent
cce76f37df
commit
b3f7b29640
|
@ -29,7 +29,7 @@ from cc.resources.telemetry import Telemetry
|
|||
from cc.resources.telemetry_feed import TelemetryFeed
|
||||
from cc.resources.pba_file_download import PBAFileDownload
|
||||
from cc.resources.pba_file_upload import FileUpload
|
||||
from cc.resources.attack import AttackConfiguration
|
||||
from cc.resources.attack_config import AttackConfiguration
|
||||
from cc.services.config import ConfigService
|
||||
|
||||
__author__ = 'Barak'
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import flask_restful
|
||||
import json
|
||||
from flask import jsonify, request
|
||||
|
||||
from cc.auth import jwt_required
|
||||
from cc.services.attack.attack import AttackService
|
||||
|
||||
|
||||
class AttackConfiguration(flask_restful.Resource):
|
||||
@jwt_required()
|
||||
def get(self):
|
||||
return jsonify(configuration=AttackService.get_config()['properties'])
|
||||
|
||||
@jwt_required()
|
||||
def post(self):
|
||||
config_json = json.loads(request.data)
|
||||
if 'reset_attack_matrix' in config_json:
|
||||
AttackService.reset_config()
|
||||
return jsonify(configuration=AttackService.get_config()['properties'])
|
||||
else:
|
||||
AttackService.update_config({'properties': json.loads(request.data)})
|
||||
return {}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import flask_restful
|
||||
import json
|
||||
from flask import jsonify, request
|
||||
|
||||
from cc.auth import jwt_required
|
||||
from cc.services.attack.attack_config import *
|
||||
|
||||
|
||||
class AttackConfiguration(flask_restful.Resource):
|
||||
@jwt_required()
|
||||
def get(self):
|
||||
return jsonify(configuration=get_config()['properties'])
|
||||
|
||||
@jwt_required()
|
||||
def post(self):
|
||||
"""
|
||||
Based on request content this endpoint either resets ATT&CK configuration or updates it.
|
||||
:return: Technique types dict with techniques on reset and nothing on update
|
||||
"""
|
||||
config_json = json.loads(request.data)
|
||||
if 'reset_attack_matrix' in config_json:
|
||||
reset_config()
|
||||
return jsonify(configuration=get_config()['properties'])
|
||||
else:
|
||||
update_config({'properties': json.loads(request.data)})
|
||||
apply_to_monkey_config()
|
||||
return {}
|
||||
|
|
@ -7,7 +7,7 @@ from flask import request, make_response, jsonify
|
|||
from cc.auth import jwt_required
|
||||
from cc.database import mongo
|
||||
from cc.services.config import ConfigService
|
||||
from cc.services.attack.attack import AttackService
|
||||
from cc.services.attack.attack_config import reset_config as reset_attack_config
|
||||
from cc.services.node import NodeService
|
||||
from cc.services.report import ReportService
|
||||
from cc.utils import local_ip_addresses
|
||||
|
@ -48,7 +48,7 @@ class Root(flask_restful.Resource):
|
|||
# We can't drop system collections.
|
||||
[mongo.db[x].drop() for x in mongo.db.collection_names() if not x.startswith('system.')]
|
||||
ConfigService.init_config()
|
||||
AttackService.reset_config()
|
||||
reset_attack_config()
|
||||
logger.info('DB was reset')
|
||||
return jsonify(status='OK')
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"server_config": "standard"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import logging
|
||||
from cc.database import mongo
|
||||
from attack_schema import SCHEMA
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AttackService:
|
||||
default_config = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_config():
|
||||
config = mongo.db.attack.find_one({'name': 'newconfig'}) or AttackService.get_default_config()
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def get_config_schema():
|
||||
return SCHEMA
|
||||
|
||||
@staticmethod
|
||||
def reset_config():
|
||||
config = AttackService.get_default_config()
|
||||
AttackService.update_config(config)
|
||||
|
||||
@staticmethod
|
||||
def update_config(config_json):
|
||||
mongo.db.attack.update({'name': 'newconfig'}, {"$set": config_json}, upsert=True)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def parse_users_matrix(data):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_default_config():
|
||||
if not AttackService.default_config:
|
||||
AttackService.update_config(SCHEMA)
|
||||
AttackService.default_config = SCHEMA
|
||||
return AttackService.default_config
|
|
@ -0,0 +1,86 @@
|
|||
import logging
|
||||
from cc.database import mongo
|
||||
from attack_schema import SCHEMA
|
||||
from cc.services.config import ConfigService
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_config():
|
||||
config = mongo.db.attack.find_one({'name': 'newconfig'}) or reset_config()
|
||||
return config
|
||||
|
||||
|
||||
def get_config_schema():
|
||||
return SCHEMA
|
||||
|
||||
|
||||
def reset_config():
|
||||
update_config(SCHEMA)
|
||||
|
||||
|
||||
def update_config(config_json):
|
||||
mongo.db.attack.update({'name': 'newconfig'}, {"$set": config_json}, upsert=True)
|
||||
return True
|
||||
|
||||
|
||||
def apply_to_monkey_config():
|
||||
"""
|
||||
Applies ATT&CK matrix in the database to the monkey configuration
|
||||
:return:
|
||||
"""
|
||||
attack_techniques = get_techniques()
|
||||
monkey_config = ConfigService.get_config(False, True, True)
|
||||
monkey_schema = ConfigService.get_config_schema()
|
||||
set_exploiters(attack_techniques, monkey_config, monkey_schema)
|
||||
ConfigService.update_config(monkey_config, True)
|
||||
|
||||
|
||||
def set_exploiters(attack_techniques, monkey_config, monkey_schema):
|
||||
"""
|
||||
Sets exploiters according to ATT&CK matrix
|
||||
:param attack_techniques: ATT&CK techniques dict. Format: {'T1110': True, ...}
|
||||
:param monkey_config: Monkey island's configuration
|
||||
:param monkey_schema: Monkey configuration schema
|
||||
"""
|
||||
for exploiter in monkey_schema['definitions']['exploiter_classes']['anyOf']:
|
||||
# Go trough each attack technique used by exploiter
|
||||
for attack_technique in exploiter['attack_techniques']:
|
||||
# If exploiter's attack technique is disabled, disable the exploiter
|
||||
if not attack_techniques[attack_technique]:
|
||||
remove_exploiter(exploiter['enum'][0], monkey_config)
|
||||
break
|
||||
# If exploiter's attack technique is enabled, enable the exploiter
|
||||
else:
|
||||
add_exploiter(exploiter['enum'][0], monkey_config)
|
||||
|
||||
|
||||
def remove_exploiter(exploiter, monkey_config):
|
||||
"""
|
||||
Removes exploiter from monkey's configuration
|
||||
:param exploiter: Exploiter class name found in SCHEMA->definitions->exploiter_classes -> anyOf -> enum
|
||||
:param monkey_config: Monkey's configuration
|
||||
"""
|
||||
if exploiter in monkey_config['exploits']['general']['exploiter_classes']:
|
||||
monkey_config['exploits']['general']['exploiter_classes'].remove(exploiter)
|
||||
|
||||
|
||||
def add_exploiter(exploiter, monkey_config):
|
||||
"""
|
||||
Adds exploiter to monkey's configuration
|
||||
:param exploiter: Exploiter class name found in SCHEMA->definitions->exploiter_classes -> anyOf -> enum
|
||||
:param monkey_config: Monkey's configuration
|
||||
"""
|
||||
if not exploiter in monkey_config['exploits']['general']['exploiter_classes']:
|
||||
monkey_config['exploits']['general']['exploiter_classes'].append(exploiter)
|
||||
|
||||
|
||||
def get_techniques():
|
||||
attack_config = get_config()
|
||||
techniques = {}
|
||||
for key, attack_type in attack_config['properties'].items():
|
||||
for key, technique in attack_type['properties'].items():
|
||||
techniques[key] = technique['value']
|
||||
return techniques
|
|
@ -2,6 +2,22 @@ SCHEMA = {
|
|||
"title": "ATT&CK configuration",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"initial_access": {
|
||||
"title": "Initial access",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"T1078": {
|
||||
"title": "T1078 Valid accounts",
|
||||
"type": "bool",
|
||||
"value": True,
|
||||
"necessary": False,
|
||||
"description": "Adversaries may steal the credentials of a specific user or service account using "
|
||||
"Credential Access techniques or capture credentials earlier in their "
|
||||
"reconnaissance process.",
|
||||
"mapped_to": ["T1003"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"lateral_movement": {
|
||||
"title": "Lateral movement",
|
||||
"type": "object",
|
||||
|
@ -36,6 +52,16 @@ SCHEMA = {
|
|||
"necessary": False,
|
||||
"description": "Adversaries may use brute force techniques to attempt access to accounts "
|
||||
"when passwords are unknown or when password hashes are obtained."
|
||||
},
|
||||
"T1003": {
|
||||
"title": "T1003 Credential dumping",
|
||||
"type": "bool",
|
||||
"value": True,
|
||||
"necessary": False,
|
||||
"description": "Credential dumping is the process of obtaining account login and password "
|
||||
"information, normally in the form of a hash or a clear text password, "
|
||||
"from the operating system and software.",
|
||||
"mapped_to": ["T1078"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -13,84 +13,96 @@ SCHEMA = {
|
|||
"enum": [
|
||||
"SmbExploiter"
|
||||
],
|
||||
"title": "SMB Exploiter"
|
||||
"title": "SMB Exploiter",
|
||||
"attack_techniques": ["T1110", "T1210", "T1021", "T1035", "T1075"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"WmiExploiter"
|
||||
],
|
||||
"title": "WMI Exploiter"
|
||||
"title": "WMI Exploiter",
|
||||
"attack_techniques": ["T1110"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"MSSQLExploiter"
|
||||
],
|
||||
"title": "MSSQL Exploiter"
|
||||
"title": "MSSQL Exploiter",
|
||||
"attack_techniques": ["T1110"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"RdpExploiter"
|
||||
],
|
||||
"title": "RDP Exploiter (UNSAFE)"
|
||||
"title": "RDP Exploiter (UNSAFE)",
|
||||
"attack_techniques": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Ms08_067_Exploiter"
|
||||
],
|
||||
"title": "MS08-067 Exploiter (UNSAFE)"
|
||||
"title": "MS08-067 Exploiter (UNSAFE)",
|
||||
"attack_techniques": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"SSHExploiter"
|
||||
],
|
||||
"title": "SSH Exploiter"
|
||||
"title": "SSH Exploiter",
|
||||
"attack_techniques": ["T1110"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ShellShockExploiter"
|
||||
],
|
||||
"title": "ShellShock Exploiter"
|
||||
"title": "ShellShock Exploiter",
|
||||
"attack_techniques": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"SambaCryExploiter"
|
||||
],
|
||||
"title": "SambaCry Exploiter"
|
||||
"title": "SambaCry Exploiter",
|
||||
"attack_techniques": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ElasticGroovyExploiter"
|
||||
],
|
||||
"title": "ElasticGroovy Exploiter"
|
||||
"title": "ElasticGroovy Exploiter",
|
||||
"attack_techniques": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Struts2Exploiter"
|
||||
],
|
||||
"title": "Struts2 Exploiter"
|
||||
"title": "Struts2 Exploiter",
|
||||
"attack_techniques": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"WebLogicExploiter"
|
||||
],
|
||||
"title": "Oracle Web Logic Exploiter"
|
||||
"title": "Oracle Web Logic Exploiter",
|
||||
"attack_techniques": []
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"HadoopExploiter"
|
||||
],
|
||||
"title": "Hadoop/Yarn Exploiter"
|
||||
"title": "Hadoop/Yarn Exploiter",
|
||||
"attack_techniques": []
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -55,7 +55,6 @@ class MatrixComponent extends AuthComponent {
|
|||
this.state.columns = this.getColumns(this.state.matrixTableData)
|
||||
};
|
||||
|
||||
|
||||
getColumns(matrixData) {
|
||||
return Object.keys(matrixData[0]).map((key)=>{
|
||||
return {
|
||||
|
@ -132,12 +131,20 @@ class MatrixComponent extends AuthComponent {
|
|||
});
|
||||
};
|
||||
|
||||
handleTechniqueChange = (technique, value) => {
|
||||
handleTechniqueChange = (technique, value, mapped=false) => {
|
||||
// Change value on configuration
|
||||
Object.entries(this.state.configData).forEach(techType => {
|
||||
if(techType[1].properties.hasOwnProperty(technique)){
|
||||
let tempMatrix = this.state.configData;
|
||||
tempMatrix[techType[0]].properties[technique].value = value;
|
||||
// Toggle all mapped techniques
|
||||
if (! mapped && tempMatrix[techType[0]].properties[technique].hasOwnProperty('mapped_to')){
|
||||
console.log("Triggered");
|
||||
tempMatrix[techType[0]].properties[technique].mapped_to.forEach(mappedTechnique => {
|
||||
console.log(mappedTechnique)
|
||||
this.handleTechniqueChange(mappedTechnique, value, true)
|
||||
})
|
||||
}
|
||||
this.updateStateFromConfig(tempMatrix);
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue