diff --git a/monkey/monkey_island/cc/resources/attck.py b/monkey/monkey_island/cc/resources/attck.py index be0d09061..3b0d1605b 100644 --- a/monkey/monkey_island/cc/resources/attck.py +++ b/monkey/monkey_island/cc/resources/attck.py @@ -8,6 +8,5 @@ from cc.services.attck.attck import AttckService class AttckConfiguration(flask_restful.Resource): @jwt_required() def get(self): - return jsonify(schema=AttckService.get_config_schema(), - configuration=AttckService.get_config()) + return jsonify(configuration=AttckService.get_config()['properties']) diff --git a/monkey/monkey_island/cc/services/attck/attck_schema.py b/monkey/monkey_island/cc/services/attck/attck_schema.py index 67f2316ef..1d720aa9a 100644 --- a/monkey/monkey_island/cc/services/attck/attck_schema.py +++ b/monkey/monkey_island/cc/services/attck/attck_schema.py @@ -13,6 +13,13 @@ SCHEMA = { "description": "Exploitation of a software vulnerability occurs when an adversary " "takes advantage of a programming error in a program, service, or within the " "operating system software or kernel itself to execute adversary-controlled code." + }, + "T1075": { + "title": "T1075 Pass the hash", + "type": "bool", + "default": True, + "description": "Pass the hash (PtH) is a method of authenticating as a user without " + "having access to the user's cleartext password." } } }, diff --git a/monkey/monkey_island/cc/ui/src/components/attck/MatrixComponent.js b/monkey/monkey_island/cc/ui/src/components/attck/MatrixComponent.js new file mode 100644 index 000000000..ec689210b --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attck/MatrixComponent.js @@ -0,0 +1,79 @@ +import React from 'react'; +import Form from 'react-jsonschema-form'; +import {Col, Nav, NavItem} from 'react-bootstrap'; +import CheckBox from '../ui-components/checkBox' +import AuthComponent from '../AuthComponent'; +import 'filepond/dist/filepond.min.css'; +import ReactTable from "react-table"; + + +let renderTechnique = function (technique) { + console.log(technique); + if (technique == null){ + return (
) + } else { + return (
{technique.title}
) + } +}; + +// Finds which attack type has most techniques and returns that number +let findMaxTechniques = function (data){ + let maxLen = 0; + data.forEach(function(techType) { + if (Object.keys(techType.properties).length > maxLen){ + maxLen = Object.keys(techType.properties).length + } + }); + return maxLen +}; + +let parseTechniques = function (data, maxLen) { + let techniques = []; + // Create rows with attack techniques + for (let i = 0; i < maxLen; i++) { + let row = {}; + data.forEach(function(techType){ + let rowColumn = {}; + rowColumn.techName = techType.title; + if (i <= Object.keys(techType.properties).length) { + rowColumn.technique = Object.values(techType.properties)[i]; + } else { + rowColumn.technique = null + } + row[rowColumn.techName] = rowColumn + }); + techniques.push(row) + } + return techniques; +}; + +class MatrixComponent extends AuthComponent { + constructor(props) { + super(props); + this.maxTechniques = findMaxTechniques(Object.values(this.props.configuration)); + this.data = parseTechniques(Object.values(this.props.configuration), this.maxTechniques); + } + + getColumns() { + return Object.keys(this.data[0]).map((key)=>{ + return { + Header: key, + id: key, + accessor: x => renderTechnique(x[key].technique) + }; + }); + } + + render() { + console.log(this.data); + let columns = this.getColumns(); + return (); + } +} + +export default MatrixComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/AttckPage.js b/monkey/monkey_island/cc/ui/src/components/pages/AttckPage.js index 5d9e300c7..ca073a7ed 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/AttckPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/AttckPage.js @@ -1,8 +1,7 @@ import React from 'react'; -import Form from 'react-jsonschema-form'; -import {Col, Nav, NavItem} from 'react-bootstrap'; import AuthComponent from '../AuthComponent'; import 'filepond/dist/filepond.min.css'; +import MatrixComponent from '../attck/MatrixComponent' class AttckComponent extends AuthComponent { constructor(props) { @@ -12,7 +11,6 @@ class AttckComponent extends AuthComponent { this.sectionsOrder = ['ATT&CK matrix']; // set schema from server this.state = { - schema: {}, configuration: {}, lastAction: 'none', sections: [], @@ -29,16 +27,21 @@ class AttckComponent extends AuthComponent { sections.push({key: sectionKey, title: res.configuration.title}); } this.setState({ - schema: res.schema, configuration: res.configuration, sections: sections, selectedSection: 'ATT&CK matrix' - }) + }); }); } render() { - return ( Vakaris ); + let content; + if (Object.keys(this.state.configuration).length === 0) { + content = (

Fetching configuration...

); + } else { + content = (); + } + return
{content}
; } } diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/checkBox.js b/monkey/monkey_island/cc/ui/src/components/ui-components/checkBox.js new file mode 100644 index 000000000..27eb78995 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/ui-components/checkBox.js @@ -0,0 +1,78 @@ +import '../../styles/CheckBox.scss' +import React from 'react'; +import MatrixComponent from "../attck/MatrixComponent"; + +class Checkbox extends React.PureComponent { + + constructor() { + super(); + + this.state = { + checked: false, + isAnimating: false, + }; + + this.toggleChecked = this.toggleChecked.bind(this); + this.ping = this.ping.bind(this); + this.composeStateClasses = this.composeStateClasses.bind(this); + } + + // + toggleChecked() { + if (this.state.isAnimating) return false; + this.setState({ + checked: !this.state.checked, + isAnimating: true, + }); + } + + // + ping() { + this.setState({ isAnimating: false }) + } + + // + composeStateClasses(core) { + let result = core; + + if (this.state.checked) { result += ' is-checked'; } + else { result += ' is-unchecked' } + + if (this.state.isAnimating) { result += ' do-ping'; } + return result; + } + + // + render() { + + const cl = this.composeStateClasses('ui-checkbox-btn'); + + return ( +
+ + + { + this.state.checked && + + + + + + } + { + !this.state.checked && + + + + + + } + +
+
+ ) + } +} +export default Checkbox; diff --git a/monkey/monkey_island/cc/ui/src/styles/CheckBox.scss b/monkey/monkey_island/cc/ui/src/styles/CheckBox.scss new file mode 100644 index 000000000..6dbf67e2c --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/styles/CheckBox.scss @@ -0,0 +1,103 @@ +// readable +$desired-line-height: 24px; +$desired-height: 36px; +$text-offset: 2px; + +// usable +$dlh: $desired-line-height; +$dh: $desired-height; +$to: $text-offset; + +// coooolors +$light-grey: #EAF4F4; +$medium-grey: #7B9EA8; +$dark-grey: #7B9EA8; +$green: #44CF6C; + +.ui-checkbox-btn { + position: relative; + display: inline-block; + + padding: (($dh - $dlh) / 2) ($dlh / 2); + border-radius: $dh / 2; // overcompensate + background-color: rgba(red, .6); + + input { display: none; } // turn off, but not forgotten + + .icon, + .text { + display: inline-block; + vertical-align: top; + color: inherit; + } + + .text { + font-size: 14px; + line-height: $dlh - $to; + padding-top: $to; + padding-left: 4px; + } + + // color states + &.is-unchecked { + border: 1px solid $medium-grey; + background-color: transparent; + color: $dark-grey; + fill: $dark-grey; + } + + &.is-checked { + border: 1px solid $green; + background-color: $green; + color: white; + fill: white; + } +} + +.icon { + position: relative; + display: inline-block; + width: $dlh - 4; + height: $dlh; + + svg { + position: absolute; + top: 0; right: 0; bottom: 0; left: 0; + margin: auto; + width: 16px; + height: auto; + fill: inherit; + } + + .is-checked & { + color: white; + fill: white; + } +} + +// ping animation magic +.ui-btn-ping { + position: absolute; + top: 50%; + left: 50%; + width: 50%; + transform: translate3d(-50%, -50%, 0); // center center by default + + // set the square + &:before { + content: ''; + transform: scale(0, 0); // center center by default + transition-property: background-color transform; + transition-timing-function: cubic-bezier(0.0, 0.0, 0.2, 1); + display: block; + padding-bottom: 100%; + border-radius: 50%; + background-color: rgba(white, .84);; + } + + .do-ping &:before { + transform: scale(2.5, 2.5); + transition-duration: .35s; + background-color: rgba(white, .08); + } +}