forked from p34709852/monkey
Finished AdvancedMultiSelect component
This commit is contained in:
parent
989020c5ba
commit
6a824efab3
|
@ -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"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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.'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue