diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index c313cea50..f43492713 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -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 AttckConfiguration +from cc.resources.attack import AttackConfiguration from cc.services.config import ConfigService __author__ = 'Barak' @@ -124,6 +124,6 @@ def init_app(mongo_url): '/api/fileUpload/?load=', '/api/fileUpload/?restore=') api.add_resource(RemoteRun, '/api/remote-monkey', '/api/remote-monkey/') - api.add_resource(AttckConfiguration, '/api/attack') + api.add_resource(AttackConfiguration, '/api/attack') return app diff --git a/monkey/monkey_island/cc/resources/attack.py b/monkey/monkey_island/cc/resources/attack.py index dd8be055e..25af9100c 100644 --- a/monkey/monkey_island/cc/resources/attack.py +++ b/monkey/monkey_island/cc/resources/attack.py @@ -6,13 +6,18 @@ from cc.auth import jwt_required from cc.services.attack.attack import AttackService -class AttckConfiguration(flask_restful.Resource): +class AttackConfiguration(flask_restful.Resource): @jwt_required() def get(self): return jsonify(configuration=AttackService.get_config()['properties']) @jwt_required() def post(self): - AttackService.update_config({'properties': json.loads(request.data)}) - return {} + 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 {} diff --git a/monkey/monkey_island/cc/ui/src/components/Main.js b/monkey/monkey_island/cc/ui/src/components/Main.js index 7fc9bbb80..291cfde58 100644 --- a/monkey/monkey_island/cc/ui/src/components/Main.js +++ b/monkey/monkey_island/cc/ui/src/components/Main.js @@ -162,7 +162,7 @@ class AppComponent extends AuthComponent {
    -
  • ATT&CK Configuration
  • +
  • ATT&CK Configuration
  • Configuration
  • Log
@@ -188,7 +188,7 @@ class AppComponent extends AuthComponent { {this.renderRoute('/start-over', )} {this.renderRoute('/report', )} {this.renderRoute('/license', )} - {this.renderRoute('/attck', )} + {this.renderRoute('/attack', )} diff --git a/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js b/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js index 309e2bbea..818a5b8e6 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/MatrixComponent.js @@ -46,15 +46,18 @@ let parseTechniques = function (data, maxLen) { class MatrixComponent extends AuthComponent { constructor(props) { super(props); - this.state = {lastAction: 'none', matrixData: this.props.configuration}; // Copy configuration and parse it for ATT&CK matrix table let configCopy = JSON.parse(JSON.stringify(this.props.configuration)); - this.maxTechniques = findMaxTechniques(Object.values(configCopy)); - this.data = parseTechniques(Object.values(configCopy), this.maxTechniques); - } + this.state = {lastAction: 'none', + configData: this.props.configuration, + maxTechniques: findMaxTechniques(Object.values(configCopy))}; + this.state.matrixTableData = parseTechniques(Object.values(configCopy), this.state.maxTechniques); + this.state.columns = this.getColumns(this.state.matrixTableData) + }; - getColumns() { - return Object.keys(this.data[0]).map((key)=>{ + + getColumns(matrixData) { + return Object.keys(matrixData[0]).map((key)=>{ return { Header: key, id: key, @@ -84,7 +87,7 @@ class MatrixComponent extends AuthComponent { { method: 'POST', headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(this.state.matrixData) + body: JSON.stringify(this.state.configData) }) .then(res => { if (!res.ok) @@ -102,26 +105,54 @@ class MatrixComponent extends AuthComponent { }); }; - handleTechniqueChange = (technique, value) => { - Object.entries(this.state.matrixData).forEach(techType => { - if(techType[1].properties.hasOwnProperty(technique)){ - let tempMatrix = this.state.matrixData; - tempMatrix[techType[0]].properties[technique].value = value; - this.setState({matrixData: tempMatrix}); - } + resetConfig = () => { + this.authFetch('/api/attack', + { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify('reset_attack_matrix') + }) + .then(res => res.json()) + .then(res => { + this.updateStateFromConfig(res.configuration, 'reset') + }); + }; + + updateStateFromConfig = (config, lastAction = '') => { + let configCopy = JSON.parse(JSON.stringify(config)); + let maxTechniques = findMaxTechniques(Object.values(configCopy)); + let matrixTableData = parseTechniques(Object.values(configCopy), maxTechniques); + let columns = this.getColumns(matrixTableData); + this.setState({ + lastAction: lastAction, + configData: config, + maxTechniques: maxTechniques, + matrixTableData: matrixTableData, + columns: columns }); }; + handleTechniqueChange = (technique, value) => { + // 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; + this.updateStateFromConfig(tempMatrix); + } + }); + + }; + render() { - let columns = this.getColumns(); return (
+ defaultPageSize={this.state.maxTechniques} />
{ this.state.lastAction === 'reset' ?
@@ -146,6 +177,9 @@ class MatrixComponent extends AuthComponent { +
);