Finished AdvancedMultiSelect component

This commit is contained in:
VakarisZ 2020-07-03 17:41:41 +03:00
parent 989020c5ba
commit 6a824efab3
9 changed files with 315 additions and 69 deletions

View File

@ -17,7 +17,10 @@ SCHEMA = {
"SmbExploiter"
],
"title": "SMB Exploiter",
"attack_techniques": ["T1110", "T1075", "T1035"]
"attack_techniques": ["T1110", "T1075", "T1035"],
"info": "Brute forces using credentials provided by user and"
" hashes gathered by mimikatz.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
@ -25,7 +28,10 @@ SCHEMA = {
"WmiExploiter"
],
"title": "WMI Exploiter",
"attack_techniques": ["T1110", "T1106"]
"attack_techniques": ["T1110", "T1106"],
"info": "Brute forces WMI (Windows Management Instrumentation) "
"using credentials provided by user and hashes gathered by mimikatz.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
@ -33,7 +39,10 @@ SCHEMA = {
"MSSQLExploiter"
],
"title": "MSSQL Exploiter",
"attack_techniques": ["T1110"]
"attack_techniques": ["T1110"],
"info": "Tries to brute force into MsSQL server and uses insecure "
"configuration to execute commands on server.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
@ -41,7 +50,9 @@ SCHEMA = {
"Ms08_067_Exploiter"
],
"title": "MS08-067 Exploiter (UNSAFE)",
"attack_techniques": []
"info": "Unsafe exploiter, that might cause system crash due to the use of buffer overflow. "
"Uses MS08-067 vulnerability.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
@ -49,56 +60,74 @@ SCHEMA = {
"SSHExploiter"
],
"title": "SSH Exploiter",
"attack_techniques": ["T1110", "T1145", "T1106"]
"attack_techniques": ["T1110", "T1145", "T1106"],
"info": "Brute forces using credentials provided by user and SSH keys gathered from systems.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
"enum": [
"ShellShockExploiter"
],
"title": "ShellShock Exploiter"
"title": "ShellShock Exploiter",
"info": "CVE-2014-6271, based on logic in NCC group's github.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
"enum": [
"SambaCryExploiter"
],
"title": "SambaCry Exploiter"
"title": "SambaCry Exploiter",
"info": "Bruteforces and searches for anonymous shares. Uses Impacket.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
"enum": [
"ElasticGroovyExploiter"
],
"title": "ElasticGroovy Exploiter"
"title": "ElasticGroovy Exploiter",
"info": "CVE-2015-1427. Logic is based on Metasploit module.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
"enum": [
"Struts2Exploiter"
],
"title": "Struts2 Exploiter"
"title": "Struts2 Exploiter",
"info": "Exploits struts2 java web framework. CVE-2017-5638. Logic based on this PoC.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
"enum": [
"WebLogicExploiter"
],
"title": "WebLogic Exploiter"
"title": "WebLogic Exploiter",
"info": "Exploits CVE-2017-10271 and CVE-2019-2725 vulnerabilities on WebLogic server.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
"enum": [
"HadoopExploiter"
],
"title": "Hadoop/Yarn Exploiter"
"title": "Hadoop/Yarn Exploiter",
"info": "Remote code execution on HADOOP server with YARN and default settings. "
"Logic based on https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
},
{
"type": "string",
"enum": [
"VSFTPDExploiter"
],
"title": "VSFTPD Exploiter"
"title": "VSFTPD Exploiter",
"info": "Exploits a malicious backdoor that was added to the VSFTPD download archive. "
"Logic based on Metasploit module.",
"link": "https://github.com/guardicore/monkey/wiki/Exploiters"
}
]
},

View File

@ -1,4 +1,4 @@
import ArrayFieldTemplate from "../ui-components/AdvancedMultipleSelect";
import AdvancedMultiSelect from "../ui-components/AdvancedMultiSelect";
import PbaInput from "./PbaInput";
import {API_PBA_LINUX, API_PBA_WINDOWS} from '../pages/ConfigurePage';
@ -6,11 +6,6 @@ export default function UiSchema(props) {
const UiSchema = {
basic: {
'ui:order': ['general', 'credentials'],
credentials: {
exploit_password_list: {
"ui:ArrayFieldTemplate": ArrayFieldTemplate
}
}
},
basic_network: {},
monkey: {
@ -54,7 +49,13 @@ export default function UiSchema(props) {
exploits: {
general: {
exploiter_classes: {
"ui:ArrayFieldTemplate": ArrayFieldTemplate
'ui:widget': AdvancedMultiSelect,
'ui:options': {
defaultPaneParams: {
title: 'Exploiters',
content: 'Click on exploiter to get more information about it.'
}
}
}
}
},

View File

@ -0,0 +1,111 @@
import React, {useState} from 'react';
import {Card, Button, Form} from 'react-bootstrap';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faSquare, faCheckSquare} from '@fortawesome/free-solid-svg-icons';
import {cloneDeep} from 'lodash';
import {getComponentHeight} from './utils/HeightCalculator';
import {resolveObjectPath} from './utils/ObjectPathResolver';
import InfoPane from './InfoPane';
function getSelectValuesAfterClick(valueArray, clickedValue) {
if (valueArray.includes(clickedValue)) {
return valueArray.filter((e) => {
return e !== clickedValue;
});
} else {
valueArray.push(clickedValue);
return valueArray;
}
}
function onMasterCheckboxClick(checkboxValue, defaultArray, onChangeFnc) {
if (checkboxValue) {
onChangeFnc([]);
} else {
onChangeFnc(defaultArray);
}
}
// Definitions passed to components only contains value and label,
// custom fields like "info" or "links" must be pulled from registry object using this function
function getFullDefinitionsFromRegistry(refString, registry) {
let refArray = refString.replace('#', '').split('/');
let definitionObject = resolveObjectPath(refArray, registry);
return definitionObject.anyOf;
}
function getFullDefinitionByKey(refString, registry, itemKey) {
let fullArray = getFullDefinitionsFromRegistry(refString, registry);
return fullArray.filter(e => (e.enum[0] === itemKey))[0];
}
function setPaneInfo(refString, registry, itemKey, setPaneInfoFnc) {
let definitionObj = getFullDefinitionByKey(refString, registry, itemKey);
setPaneInfoFnc({title: definitionObj.title, content: definitionObj.info, link: definitionObj.link});
}
function AdvancedMultiSelect(props) {
const [masterCheckbox, setMasterCheckbox] = useState(true);
const {
schema,
id,
options,
value,
required,
disabled,
readonly,
multiple,
autofocus,
onChange,
registry
} = props;
const {enumOptions, defaultPaneParams} = options;
const [infoPaneParams, setInfoPaneParams] = useState(defaultPaneParams);
const selectValue = cloneDeep(value);
return (
<div className={'advanced-multi-select'}>
<Card.Header>
<Button key={`${props.schema.title}-button`} value={value}
variant={'link'} disabled={disabled}
onClick={() => {
onMasterCheckboxClick(masterCheckbox, schema.default, onChange);
setMasterCheckbox(!masterCheckbox);
}}
>
<FontAwesomeIcon icon={masterCheckbox ? faCheckSquare : faSquare}/>
</Button>
<span className={'header-title'}>{props.schema.title}</span>
</Card.Header>
<Form.Group
style={{height: `${getComponentHeight(enumOptions.length)}px`}}
id={id}
multiple={multiple}
className='choice-block form-control'
required={required}
disabled={disabled || readonly}
autoFocus={autofocus}>
{enumOptions.map(({value, label}, i) => {
return (
<Form.Group
key={i}
onClick={() => setPaneInfo(schema.items.$ref, registry, value, setInfoPaneParams)}>
<Button value={value} variant={'link'} disabled={disabled}
onClick={() => onChange(getSelectValuesAfterClick(selectValue, value))}>
<FontAwesomeIcon icon={selectValue.includes(value) ? faCheckSquare : faSquare}/>
</Button>
<span className={'option-text'}>
{label}
</span>
</Form.Group>
);
})}
</Form.Group>
<InfoPane title={infoPaneParams.title} body={infoPaneParams.content} link={infoPaneParams.link}/>
</div>
);
}
export default AdvancedMultiSelect;

View File

@ -1,50 +0,0 @@
import React from "react";
import Button from 'react-bootstrap/Button';
function ArrayFieldTemplate(props) {
return (
<div className={props.className}>
{props.items &&
props.items.map(element => (
<div key={element.key} className={element.className}>
<div>{element.children}</div>
{element.hasMoveDown && (
<button
onClick={element.onReorderClick(
element.index,
element.index + 1
)}>
Down
</button>
)}
{element.hasMoveUp && (
<button
onClick={element.onReorderClick(
element.index,
element.index - 1
)}>
Up
</button>
)}
<button onClick={element.onDropIndexClick(element.index)}>
Delete
</button>
<hr />
</div>
))}
{props.canAdd && (
<div className="row">
<p className="col-xs-3 col-xs-offset-9 array-item-add text-right">
<button onClick={props.onAddClick} type="button">
Custom +
</button>
</p>
</div>
)}
</div>
);
}
export default ArrayFieldTemplate;

View File

@ -0,0 +1,52 @@
import {Card, Button} from 'react-bootstrap';
import React from 'react';
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faQuestionCircle} from "@fortawesome/free-solid-svg-icons";
function InfoPane(props) {
return (
<Card className={'info-pane'}>
{getTitle(props)}
{getSubtitle(props)}
{getBody(props)}
</Card>);
}
function getTitle(props) {
if (typeof (props.title) == 'string') {
return (
<Card.Title className={'pane-title'}>
{props.title}
{getLinkButton(props)}
</Card.Title>)
}
}
function getLinkButton(props) {
if (typeof (props.link) == 'string') {
return (
<Button variant={'link'} className={'pane-link'} href={props.link} target={'_blank'}>
<FontAwesomeIcon icon={faQuestionCircle}/>
</Button>)
}
}
function getSubtitle(props) {
if (typeof (props.subtitle) == 'string') {
return (
<Card.Subtitle className={'pane-subtitle'}>
{props.subtitle}
</Card.Subtitle>)
}
}
function getBody(props) {
return (
<Card.Body className={'pane-body'}>
{props.body}
</Card.Body>
)
}
export default InfoPane

View File

@ -0,0 +1,16 @@
const defaultMinHeight = 50
const defaultMaxHeight = 300
const defaultSubcomponentHeight = 15
export function getComponentHeight(subcomponentCount,
subcomponentHeight = defaultSubcomponentHeight,
minHeight = defaultMinHeight,
maxHeight = defaultMaxHeight) {
let height = subcomponentHeight * subcomponentCount;
if (height > maxHeight)
height = maxHeight
else if (height < minHeight)
height = minHeight
return height
}

View File

@ -0,0 +1,11 @@
// Resolves object's path if it's specified in a dot notation.
// (e.g. params: "firstLevel.secondLevel.property", myObject)
export function resolveObjectPath(pathArray, obj) {
return pathArray.reduce(function(prev, curr) {
if(curr === '')
return prev;
else
return prev ? prev[curr] : null;
}, obj || self)
}

View File

@ -0,0 +1,47 @@
.advanced-multi-select .choice-block.form-control {
overflow: scroll;
overflow-x: hidden;
padding: 0;
margin-left: 0;
}
.advanced-multi-select svg {
font-size: 1.15em;
}
.advanced-multi-select .card-header {
border: 1px solid $gray-300;
border-bottom: none;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
padding-left: 0;
padding-bottom: 5px;
}
.advanced-multi-select .card-header button {
padding-top: 0;
}
.advanced-multi-select .card-header .header-title {
font-size: 1.2em;
}
.advanced-multi-select .choice-block .form-group {
margin: 0;
padding: 3px 0 0 0;
height: 30px;
}
.advanced-multi-select .choice-block .form-group:hover {
background-color: $gray-300;
cursor: pointer;
}
.advanced-multi-select .choice-block .form-group button {
margin: 0 5px 3px 10px;
padding: 0;
}
.advanced-multi-select .option-text {
margin-left: 10px;
}

View File

@ -0,0 +1,29 @@
.info-pane, .card {
margin-top: 5px;
}
.info-pane svg {
font-size: 1.1em;
}
.info-pane .pane-title {
margin: 10px 15px 3px 15px;
color: $monkey-alt;
}
.info-pane .pane-link {
position: absolute;
right: 0;
top: 0;
}
.info-pane .pane-subtitle {
margin: 0 15px;
color: $gray-600;
}
.info-pane .pane-body {
margin: 10px 15px;
padding: 0;
}