forked from p34709852/monkey
Merge pull request #2051 from guardicore/2003-define-new-json-schema
2003 define new json schema
This commit is contained in:
commit
8873ef891b
|
@ -1,23 +1,25 @@
|
|||
const CONFIGURATION_TABS = {
|
||||
BASIC: 'basic',
|
||||
BASIC_NETWORK: 'basic_network',
|
||||
RANSOMWARE: 'ransomware',
|
||||
MONKEY: 'monkey',
|
||||
INTERNAL: 'internal'
|
||||
PROPAGATION: 'propagation',
|
||||
PAYLOADS: 'payloads',
|
||||
PBA: 'post_breach_actions',
|
||||
CUSTOM_PBA: 'custom_pbas',
|
||||
CREDENTIALS_COLLECTORS: 'credential_collectors',
|
||||
ADVANCED: 'advanced'
|
||||
};
|
||||
|
||||
const advancedModeConfigTabs = [
|
||||
CONFIGURATION_TABS.BASIC,
|
||||
CONFIGURATION_TABS.BASIC_NETWORK,
|
||||
CONFIGURATION_TABS.RANSOMWARE,
|
||||
CONFIGURATION_TABS.MONKEY,
|
||||
CONFIGURATION_TABS.INTERNAL
|
||||
CONFIGURATION_TABS.PROPAGATION,
|
||||
CONFIGURATION_TABS.PAYLOADS,
|
||||
CONFIGURATION_TABS.PBA,
|
||||
CONFIGURATION_TABS.CUSTOM_PBA,
|
||||
CONFIGURATION_TABS.CREDENTIALS_COLLECTORS,
|
||||
CONFIGURATION_TABS.ADVANCED
|
||||
];
|
||||
|
||||
const ransomwareModeConfigTabs = [
|
||||
CONFIGURATION_TABS.BASIC,
|
||||
CONFIGURATION_TABS.BASIC_NETWORK,
|
||||
CONFIGURATION_TABS.RANSOMWARE
|
||||
CONFIGURATION_TABS.PROPAGATION,
|
||||
CONFIGURATION_TABS.PAYLOADS,
|
||||
CONFIGURATION_TABS.ADVANCED
|
||||
];
|
||||
|
||||
const CONFIGURATION_TABS_PER_MODE = {
|
||||
|
|
|
@ -12,7 +12,7 @@ function applyUiSchemaManipulators(selectedSection,
|
|||
function ransomwareDirManipulator(selectedSection,
|
||||
formData,
|
||||
uiSchema) {
|
||||
if (selectedSection === 'ransomware'){
|
||||
if (selectedSection === 'payloads'){
|
||||
uiSchema.encryption.directories =
|
||||
{'ui:disabled': !formData['encryption']['enabled']};
|
||||
}
|
||||
|
|
|
@ -1,139 +1,140 @@
|
|||
import AdvancedMultiSelect from '../ui-components/AdvancedMultiSelect';
|
||||
import InfoBox from './InfoBox';
|
||||
import TextBox from './TextBox.js';
|
||||
import PbaInput from './PbaInput';
|
||||
import {API_PBA_LINUX, API_PBA_WINDOWS} from '../pages/ConfigurePage';
|
||||
import InfoBox from './InfoBox';
|
||||
import TextBox from './TextBox';
|
||||
import SensitiveTextInput from '../ui-components/SensitiveTextInput';
|
||||
|
||||
export default function UiSchema(props) {
|
||||
const UiSchema = {
|
||||
basic: {
|
||||
'ui:order': ['exploiters', 'credentials'],
|
||||
exploiters: {
|
||||
exploiter_classes: {
|
||||
propagation: {
|
||||
exploitation: {
|
||||
brute_force: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect
|
||||
}
|
||||
},
|
||||
credentials: {
|
||||
exploit_user_list: {
|
||||
items: {
|
||||
'ui:widget': AdvancedMultiSelect,
|
||||
brute_force_classes: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
},
|
||||
exploit_password_list: {
|
||||
items: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': SensitiveTextInput
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
basic_network: {
|
||||
'ui:order': ['scope', 'network_analysis'],
|
||||
scope: {
|
||||
info_box: {
|
||||
'ui:field': InfoBox
|
||||
},
|
||||
blocked_ips: {
|
||||
items: {
|
||||
vulnerability: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect,
|
||||
vulnerability_classes: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
},
|
||||
subnet_scan_list: {
|
||||
format: 'ip-list',
|
||||
items: {
|
||||
classNames: 'config-template-no-header'
|
||||
options: {
|
||||
http_ports: {
|
||||
items: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
network_analysis: {
|
||||
inaccessible_subnets: {
|
||||
items: {
|
||||
network_scan: {
|
||||
targets: {
|
||||
info_box: {
|
||||
'ui:field': InfoBox
|
||||
},
|
||||
blocked_ips: {
|
||||
items: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
},
|
||||
inaccessible_subnets: {
|
||||
items: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
},
|
||||
subnets: {
|
||||
items: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
}
|
||||
},
|
||||
tcp: {
|
||||
ports: {
|
||||
items: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
}
|
||||
},
|
||||
fingerprinters:{
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect,
|
||||
fingerprinter_classes: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
monkey: {
|
||||
post_breach: {
|
||||
post_breach_actions: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect
|
||||
},
|
||||
custom_PBA_linux_cmd: {
|
||||
'ui:widget': 'textarea',
|
||||
'ui:emptyValue': ''
|
||||
},
|
||||
PBA_linux_file: {
|
||||
'ui:widget': PbaInput,
|
||||
'ui:options': {
|
||||
filename: props.PBA_linux_filename,
|
||||
apiEndpoint: API_PBA_LINUX,
|
||||
setPbaFilename: props.setPbaFilenameLinux
|
||||
}
|
||||
},
|
||||
custom_PBA_windows_cmd: {
|
||||
'ui:widget': 'textarea',
|
||||
'ui:emptyValue': ''
|
||||
},
|
||||
PBA_windows_file: {
|
||||
'ui:widget': PbaInput,
|
||||
'ui:options': {
|
||||
filename: props.PBA_windows_filename,
|
||||
apiEndpoint: API_PBA_WINDOWS,
|
||||
setPbaFilename: props.setPbaFilenameWindows
|
||||
}
|
||||
},
|
||||
PBA_linux_filename: {
|
||||
classNames: 'linux-pba-file-info',
|
||||
'ui:emptyValue': ''
|
||||
},
|
||||
PBA_windows_filename: {
|
||||
classNames: 'windows-pba-file-info',
|
||||
'ui:emptyValue': ''
|
||||
}
|
||||
},
|
||||
credential_collectors: {
|
||||
credential_collectors: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect
|
||||
}
|
||||
}
|
||||
},
|
||||
ransomware: {
|
||||
payloads: {
|
||||
classNames: 'config-template-no-header',
|
||||
encryption: {
|
||||
info_box: {
|
||||
info_box : {
|
||||
'ui:field': InfoBox
|
||||
},
|
||||
directories: {
|
||||
// Directory inputs are dynamically hidden
|
||||
// Directory inputs are dynamically hidden
|
||||
},
|
||||
text_box: {
|
||||
'ui:field': TextBox
|
||||
},
|
||||
enabled: {'ui:widget': 'hidden'}
|
||||
enabled: {
|
||||
'ui:widget': 'hidden'
|
||||
}
|
||||
},
|
||||
other_behaviors : {'ui:widget': 'hidden'}
|
||||
other_behaviors : {
|
||||
'ui:widget': 'hidden'
|
||||
}
|
||||
},
|
||||
internal: {
|
||||
classes: {
|
||||
finger_classes: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect
|
||||
custom_pbas: {
|
||||
classNames: 'config-template-no-header',
|
||||
linux_command: {
|
||||
'ui:widget': 'textarea',
|
||||
'ui:emptyValue': ''
|
||||
},
|
||||
linux_file: {
|
||||
'ui:widget': PbaInput,
|
||||
'ui:options': {
|
||||
filename: props.linux_filename,
|
||||
apiEndpoint: API_PBA_LINUX,
|
||||
setPbaFilename: props.setPbaFilenameLinux
|
||||
}
|
||||
},
|
||||
exploits: {
|
||||
exploit_lm_hash_list:{
|
||||
items: {
|
||||
'ui:widget': SensitiveTextInput
|
||||
}
|
||||
},
|
||||
exploit_ntlm_hash_list: {
|
||||
items: {
|
||||
'ui:widget': SensitiveTextInput
|
||||
}
|
||||
windows_command: {
|
||||
'ui:widget': 'textarea',
|
||||
'ui:emptyValue': ''
|
||||
},
|
||||
windows_file: {
|
||||
'ui:widget': PbaInput,
|
||||
'ui:options': {
|
||||
filename: props.windows_filename,
|
||||
apiEndpoint: API_PBA_WINDOWS,
|
||||
setPbaFilename: props.setPbaFilenameWindows
|
||||
}
|
||||
},
|
||||
linux_filename: {
|
||||
classNames: 'linux-pba-file-info',
|
||||
'ui:emptyValue': ''
|
||||
},
|
||||
windows_filename: {
|
||||
classNames: 'windows-pba-file-info',
|
||||
'ui:emptyValue': ''
|
||||
}
|
||||
},
|
||||
post_breach_actions: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect,
|
||||
post_breach_actions: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
},
|
||||
credential_collectors: {
|
||||
classNames: 'config-template-no-header',
|
||||
'ui:widget': AdvancedMultiSelect,
|
||||
credential_collectors_classes: {
|
||||
classNames: 'config-template-no-header'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,7 +8,6 @@ import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck';
|
|||
import {faExclamationCircle} from '@fortawesome/free-solid-svg-icons/faExclamationCircle';
|
||||
import {formValidationFormats} from '../configuration-components/ValidationFormats';
|
||||
import transformErrors from '../configuration-components/ValidationErrorMessages';
|
||||
import InternalConfig from '../configuration-components/InternalConfig';
|
||||
import UnsafeConfigOptionsConfirmationModal
|
||||
from '../configuration-components/UnsafeConfigOptionsConfirmationModal.js';
|
||||
import UnsafeOptionsWarningModal from '../configuration-components/UnsafeOptionsWarningModal.js';
|
||||
|
@ -18,6 +17,7 @@ import ConfigImportModal from '../configuration-components/ImportConfigModal';
|
|||
import applyUiSchemaManipulators from '../configuration-components/UISchemaManipulators.tsx';
|
||||
import HtmlFieldDescription from '../configuration-components/HtmlFieldDescription.js';
|
||||
import CONFIGURATION_TABS_PER_MODE from '../configuration-components/ConfigurationTabs.js';
|
||||
import {SCHEMA} from '../../services/configuration/config_schema.js';
|
||||
|
||||
const CONFIG_URL = '/api/configuration/island';
|
||||
export const API_PBA_LINUX = '/api/file-upload/PBAlinux';
|
||||
|
@ -68,24 +68,28 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
let urls = [CONFIG_URL];
|
||||
let urls = ['/api/agent-configuration'];
|
||||
// ??? Why fetch config here and not in `render()`?
|
||||
Promise.all(urls.map(url => this.authFetch(url).then(res => res.json())))
|
||||
.then(data => {
|
||||
let sections = [];
|
||||
let monkeyConfig = data[0];
|
||||
this.setInitialConfig(monkeyConfig.configuration);
|
||||
// TODO: Fix when we add plugins
|
||||
monkeyConfig['payloads'] = monkeyConfig['payloads'][0]['options'];
|
||||
|
||||
this.setInitialConfig(monkeyConfig);
|
||||
for (let sectionKey of this.getSectionsOrder()) {
|
||||
sections.push({
|
||||
key: sectionKey,
|
||||
title: monkeyConfig.schema.properties[sectionKey].title
|
||||
title: SCHEMA.properties[sectionKey].title
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
schema: monkeyConfig.schema,
|
||||
configuration: monkeyConfig.configuration,
|
||||
schema: SCHEMA,
|
||||
configuration: monkeyConfig,
|
||||
sections: sections,
|
||||
currentFormData: monkeyConfig.configuration[this.state.selectedSection]
|
||||
currentFormData: monkeyConfig[this.state.selectedSection]
|
||||
})
|
||||
});
|
||||
};
|
||||
|
@ -266,9 +270,11 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
|
||||
this.updateConfigSection();
|
||||
this.currentSection = key;
|
||||
let selectedSectionData = this.state.configuration[key];
|
||||
|
||||
this.setState({
|
||||
selectedSection: key,
|
||||
currentFormData: this.state.configuration[key]
|
||||
currentFormData: selectedSectionData
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -337,11 +343,11 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
let formProperties = {};
|
||||
formProperties['schema'] = displayedSchema
|
||||
formProperties['uiSchema'] = UiSchema({
|
||||
PBA_linux_filename: this.state.configuration.monkey.post_breach.PBA_linux_filename,
|
||||
PBA_windows_filename: this.state.configuration.monkey.post_breach.PBA_windows_filename,
|
||||
selectedSection: this.state.selectedSection,
|
||||
linux_filename: this.state.configuration.custom_pbas.linux_filename,
|
||||
windows_filename: this.state.configuration.custom_pbas.windows_filename,
|
||||
setPbaFilenameWindows: this.setPbaFilenameWindows,
|
||||
setPbaFilenameLinux: this.setPbaFilenameLinux,
|
||||
selectedSection: this.state.selectedSection
|
||||
setPbaFilenameLinux: this.setPbaFilenameLinux
|
||||
})
|
||||
formProperties['fields'] = {DescriptionField: HtmlFieldDescription};
|
||||
formProperties['formData'] = this.state.currentFormData;
|
||||
|
@ -355,22 +361,18 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
formProperties['formData'],
|
||||
formProperties['uiSchema']);
|
||||
|
||||
if (this.state.selectedSection === 'internal') {
|
||||
return (<InternalConfig {...formProperties}/>)
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<Form {...formProperties}>
|
||||
<button type='submit' className={'hidden'}>Submit</button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Form {...formProperties} key={displayedSchema.title}>
|
||||
<button type='submit' className={'hidden'}>Submit</button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
setPbaFilenameWindows = (filename) => {
|
||||
let config = this.state.configuration
|
||||
config.monkey.post_breach.PBA_windows_filename = filename
|
||||
config.custom_pbas.windows_filename = filename
|
||||
this.setState({
|
||||
configuration: config
|
||||
})
|
||||
|
@ -378,7 +380,7 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
|
||||
setPbaFilenameLinux = (filename) => {
|
||||
let config = this.state.configuration
|
||||
config.monkey.post_breach.PBA_linux_filename = filename
|
||||
config.custom_pbas.linux_filename = filename
|
||||
this.setState({
|
||||
configuration: config
|
||||
})
|
||||
|
@ -391,7 +393,7 @@ class ConfigurePageComponent extends AuthComponent {
|
|||
style={{'marginBottom': '2em'}}
|
||||
className={'config-nav'}>
|
||||
{this.state.sections.map(section => {
|
||||
let classProp = section.key.startsWith('basic') ? 'tab-primary' : '';
|
||||
let classProp = section.key.startsWith('propagation') ? 'tab-primary' : '';
|
||||
return (
|
||||
<Nav.Item key={section.key}>
|
||||
<Nav.Link className={classProp} eventKey={section.key}>{section.title}</Nav.Link>
|
||||
|
|
|
@ -6,7 +6,7 @@ import {cloneDeep} from 'lodash';
|
|||
import {getDefaultPaneParams, InfoPane, WarningType} from './InfoPane';
|
||||
import {MasterCheckbox, MasterCheckboxState} from './MasterCheckbox';
|
||||
import ChildCheckboxContainer from './ChildCheckbox';
|
||||
import {getFullDefinitionByKey} from './JsonSchemaHelpers';
|
||||
import {getFullDefinitionByKey, getObjectFromRegistryByRef} from './JsonSchemaHelpers';
|
||||
|
||||
function AdvancedMultiSelectHeader(props) {
|
||||
const {
|
||||
|
@ -17,12 +17,13 @@ function AdvancedMultiSelectHeader(props) {
|
|||
onResetClick
|
||||
} = props;
|
||||
|
||||
|
||||
return (
|
||||
<Card.Header className="d-flex justify-content-between">
|
||||
<MasterCheckbox title={title} onClick={onCheckboxClick} checkboxState={checkboxState}/>
|
||||
<Button className={'reset-safe-defaults'} type={'reset'} variant={'warning'}
|
||||
hidden={hideReset} onClick={onResetClick}>
|
||||
Reset to safe defaults
|
||||
hidden={hideReset} onClick={onResetClick}>
|
||||
Reset to safe options
|
||||
</Button>
|
||||
</Card.Header>
|
||||
);
|
||||
|
@ -32,22 +33,47 @@ class AdvancedMultiSelect extends React.Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.defaultValues = props.schema.default;
|
||||
this.infoPaneRefString = props.schema.items.$ref;
|
||||
this.registry = props.registry;
|
||||
this.enumOptions = props.options.enumOptions.sort(this.compareOptions);
|
||||
let selectedPluginNames = this.props.value.map(v => v.name);
|
||||
let allPluginNames = this.props.options.enumOptions.map(v => v.value);
|
||||
|
||||
this.state = {
|
||||
masterCheckboxState: this.getMasterCheckboxState(props.value),
|
||||
hideReset: this.getHideResetState(props.value),
|
||||
infoPaneParams: getDefaultPaneParams(
|
||||
this.infoPaneRefString,
|
||||
this.registry,
|
||||
this.isUnsafeOptionSelected(props.value)
|
||||
)
|
||||
this.props.schema.items.$ref,
|
||||
this.props.registry,
|
||||
this.isUnsafeOptionSelected(selectedPluginNames)
|
||||
),
|
||||
allPluginNames: allPluginNames,
|
||||
masterCheckboxState: this.getMasterCheckboxState(selectedPluginNames),
|
||||
pluginDefinitions: getObjectFromRegistryByRef(this.props.schema.items.$ref,
|
||||
this.props.registry).pluginDefs,
|
||||
selectedPluginNames: selectedPluginNames
|
||||
};
|
||||
}
|
||||
|
||||
getOptionList = () => {
|
||||
return this.props.options.enumOptions.sort(this.compareOptions);
|
||||
}
|
||||
|
||||
onChange = (strValues) => {
|
||||
let newValues = [];
|
||||
for (let j = 0; j < strValues.length; j++) {
|
||||
let found = false;
|
||||
for (let i = 0; i < this.state.allPluginNames.length; i++) {
|
||||
if (strValues[j] === this.state.allPluginNames[i]['name']) {
|
||||
newValues.push(JSON.parse(JSON.stringify(this.props.value[i])))
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
newValues.push(this.state.pluginDefinitions[strValues[j]]);
|
||||
}
|
||||
}
|
||||
newValues = JSON.parse(JSON.stringify(newValues));
|
||||
this.props.onChange(newValues)
|
||||
this.setState({selectedPluginNames: newValues.map(v => v.name)});
|
||||
}
|
||||
|
||||
// Sort options alphabetically. "Unsafe" options float to the top so that they
|
||||
// do not get selected and hidden at the bottom of the list.
|
||||
compareOptions = (a, b) => {
|
||||
|
@ -62,28 +88,23 @@ class AdvancedMultiSelect extends React.Component {
|
|||
}
|
||||
|
||||
onMasterCheckboxClick = () => {
|
||||
if (this.state.masterCheckboxState === MasterCheckboxState.ALL) {
|
||||
let checkboxState = this.getMasterCheckboxState(this.state.selectedPluginNames);
|
||||
if (checkboxState === MasterCheckboxState.ALL) {
|
||||
var newValues = [];
|
||||
} else {
|
||||
newValues = this.enumOptions.map(({value}) => value);
|
||||
newValues = this.getOptionList().map(({value}) => value);
|
||||
}
|
||||
|
||||
this.props.onChange(newValues);
|
||||
this.setMasterCheckboxState(newValues);
|
||||
this.setHideResetState(newValues);
|
||||
this.setPaneInfoToDefault(this.isUnsafeOptionSelected(newValues));
|
||||
this.onChange(newValues);
|
||||
}
|
||||
|
||||
onChildCheckboxClick = (value) => {
|
||||
let selectValues = this.getSelectValuesAfterClick(value);
|
||||
this.props.onChange(selectValues);
|
||||
|
||||
this.setMasterCheckboxState(selectValues);
|
||||
this.setHideResetState(selectValues);
|
||||
this.onChange(selectValues);
|
||||
}
|
||||
|
||||
getSelectValuesAfterClick(clickedValue) {
|
||||
const valueArray = cloneDeep(this.props.value);
|
||||
const valueArray = cloneDeep(this.state.selectedPluginNames);
|
||||
|
||||
if (valueArray.includes(clickedValue)) {
|
||||
return valueArray.filter(e => e !== clickedValue);
|
||||
|
@ -95,8 +116,7 @@ class AdvancedMultiSelect extends React.Component {
|
|||
|
||||
setMasterCheckboxState(selectValues) {
|
||||
let newState = this.getMasterCheckboxState(selectValues);
|
||||
|
||||
if (newState != this.state.masterCheckboxState) {
|
||||
if (newState !== this.state.masterCheckboxState) {
|
||||
this.setState({masterCheckboxState: newState});
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +126,7 @@ class AdvancedMultiSelect extends React.Component {
|
|||
return MasterCheckboxState.NONE;
|
||||
}
|
||||
|
||||
if (selectValues.length !== this.enumOptions.length) {
|
||||
if (selectValues.length !== this.getOptionList().length) {
|
||||
return MasterCheckboxState.MIXED;
|
||||
}
|
||||
|
||||
|
@ -114,16 +134,7 @@ class AdvancedMultiSelect extends React.Component {
|
|||
}
|
||||
|
||||
onResetClick = () => {
|
||||
this.props.onChange(this.defaultValues);
|
||||
this.setHideResetState(this.defaultValues);
|
||||
this.setMasterCheckboxState(this.defaultValues);
|
||||
this.setPaneInfoToDefault(this.isUnsafeOptionSelected(this.defaultValues));
|
||||
}
|
||||
|
||||
setHideResetState(selectValues) {
|
||||
this.setState(() => ({
|
||||
hideReset: this.getHideResetState(selectValues)
|
||||
}));
|
||||
this.setPaneInfoToSafe();
|
||||
}
|
||||
|
||||
getHideResetState(selectValues) {
|
||||
|
@ -135,11 +146,14 @@ class AdvancedMultiSelect extends React.Component {
|
|||
}
|
||||
|
||||
isSafe = (itemKey) => {
|
||||
return getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey).safe;
|
||||
let fullDef = getFullDefinitionByKey(this.props.schema.items.$ref,
|
||||
this.props.registry, itemKey);
|
||||
return fullDef.safe;
|
||||
}
|
||||
|
||||
setPaneInfo = (itemKey) => {
|
||||
let definitionObj = getFullDefinitionByKey(this.infoPaneRefString, this.registry, itemKey);
|
||||
setPaneInfo = (itemKey) => {
|
||||
let definitionObj = getFullDefinitionByKey(this.props.schema.items.$ref,
|
||||
this.props.registry, itemKey);
|
||||
this.setState(
|
||||
{
|
||||
infoPaneParams: {
|
||||
|
@ -152,14 +166,10 @@ class AdvancedMultiSelect extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
setPaneInfoToDefault(isUnsafeOptionSelected) {
|
||||
this.setState(() => ({
|
||||
infoPaneParams: getDefaultPaneParams(
|
||||
this.props.schema.items.$ref,
|
||||
this.props.registry,
|
||||
isUnsafeOptionSelected
|
||||
)
|
||||
}));
|
||||
setPaneInfoToSafe() {
|
||||
let safePluginNames = this.state.allPluginNames.filter(pluginName => this.isSafe(pluginName));
|
||||
this.setState({selectedPluginNames: safePluginNames});
|
||||
this.onChange(safePluginNames);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -168,33 +178,33 @@ class AdvancedMultiSelect extends React.Component {
|
|||
id,
|
||||
multiple,
|
||||
required,
|
||||
schema,
|
||||
value
|
||||
schema
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={'advanced-multi-select'}>
|
||||
<AdvancedMultiSelectHeader title={schema.title}
|
||||
onCheckboxClick={this.onMasterCheckboxClick}
|
||||
checkboxState={this.state.masterCheckboxState}
|
||||
hideReset={this.state.hideReset} onResetClick={this.onResetClick}/>
|
||||
onCheckboxClick={this.onMasterCheckboxClick}
|
||||
checkboxState={this.getMasterCheckboxState(
|
||||
this.state.selectedPluginNames)}
|
||||
hideReset={this.getHideResetState(
|
||||
this.state.selectedPluginNames)}
|
||||
onResetClick={this.onResetClick}/>
|
||||
|
||||
<ChildCheckboxContainer id={id} multiple={multiple} required={required}
|
||||
autoFocus={autofocus} isSafe={this.isSafe}
|
||||
onPaneClick={this.setPaneInfo} onCheckboxClick={this.onChildCheckboxClick}
|
||||
selectedValues={value} enumOptions={this.enumOptions}/>
|
||||
autoFocus={autofocus} isSafe={this.isSafe}
|
||||
onPaneClick={this.setPaneInfo}
|
||||
onCheckboxClick={this.onChildCheckboxClick}
|
||||
selectedValues={this.state.selectedPluginNames}
|
||||
enumOptions={this.getOptionList()}/>
|
||||
|
||||
<InfoPane title={this.state.infoPaneParams.title}
|
||||
body={this.state.infoPaneParams.content}
|
||||
link={this.state.infoPaneParams.link}
|
||||
warningType={this.state.infoPaneParams.warningType}/>
|
||||
body={this.state.infoPaneParams.content}
|
||||
link={this.state.infoPaneParams.link}
|
||||
warningType={this.state.infoPaneParams.warningType}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidUpdate(_prevProps) {
|
||||
this.setMasterCheckboxState(this.props.value);
|
||||
}
|
||||
}
|
||||
|
||||
export default AdvancedMultiSelect;
|
||||
|
|
|
@ -1,24 +1,29 @@
|
|||
function getPluginDescriptors(schema, config) {
|
||||
return ([
|
||||
{
|
||||
name: 'Exploiters',
|
||||
allPlugins: schema.definitions.exploiter_classes.anyOf,
|
||||
selectedPlugins: config.basic.exploiters.exploiter_classes
|
||||
name: 'Brute force exploiters',
|
||||
allPlugins: schema.definitions.brute_force_classes.anyOf,
|
||||
selectedPlugins: config.propagation.exploitation.brute_force
|
||||
},
|
||||
{
|
||||
name: 'Vulnerability exploiters',
|
||||
allPlugins: schema.definitions.vulnerability_classes.anyOf,
|
||||
selectedPlugins: config.propagation.exploitation.vulnerability
|
||||
},
|
||||
{
|
||||
name: 'Fingerprinters',
|
||||
allPlugins: schema.definitions.finger_classes.anyOf,
|
||||
selectedPlugins: config.internal.classes.finger_classes
|
||||
allPlugins: schema.definitions.fingerprinter_classes.anyOf,
|
||||
selectedPlugins: config.propagation.network_scan.fingerprinters
|
||||
},
|
||||
{
|
||||
name: 'PostBreachActions',
|
||||
allPlugins: schema.definitions.post_breach_actions.anyOf,
|
||||
selectedPlugins: config.monkey.post_breach.post_breach_actions
|
||||
selectedPlugins: config.post_breach_actions
|
||||
},
|
||||
{
|
||||
name: 'CredentialCollectors',
|
||||
allPlugins: schema.definitions.credential_collectors.anyOf,
|
||||
selectedPlugins: config.monkey.credential_collectors.credential_collectors
|
||||
allPlugins: schema.definitions.credential_collectors_classes.anyOf,
|
||||
selectedPlugins: config.credential_collectors
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
@ -40,7 +45,7 @@ function isUnsafePluginSelected(pluginDescriptor) {
|
|||
pluginDescriptor.allPlugins.forEach(i => pluginSafety[i.enum[0]] = i.safe);
|
||||
|
||||
for (let selected of pluginDescriptor.selectedPlugins) {
|
||||
if (!pluginSafety[selected]) {
|
||||
if (!pluginSafety[selected.name]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import {customPBAConfigurationSchema} from './definitions/custom_pbas.js';
|
||||
import {ransomwareSchema} from './definitions/ransomware.js';
|
||||
import {propagationConfigurationSchema} from './definitions/propagation.js';
|
||||
import {bruteForceExploiters, vulnerabilityExploiters} from './definitions/exploiter_classes.js';
|
||||
import {credentialCollectors} from './definitions/credential_collectors.js';
|
||||
import {postBreachActions} from './definitions/post_breach_actions.js';
|
||||
import {fingerprinterClasses} from './definitions/fingerprinter_classes.js'
|
||||
|
||||
export const SCHEMA = {
|
||||
'title': 'Monkey',
|
||||
'type': 'object',
|
||||
'definitions': {
|
||||
'brute_force_classes': bruteForceExploiters,
|
||||
'vulnerability_classes': vulnerabilityExploiters,
|
||||
'credential_collectors_classes': credentialCollectors,
|
||||
'post_breach_actions': postBreachActions,
|
||||
'fingerprinter_classes': fingerprinterClasses
|
||||
},
|
||||
'properties': {
|
||||
'propagation': propagationConfigurationSchema,
|
||||
'post_breach_actions': {
|
||||
'title': 'Post-breach actions',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'$ref': '#/definitions/post_breach_actions'
|
||||
}
|
||||
},
|
||||
'custom_pbas': customPBAConfigurationSchema,
|
||||
'payloads': ransomwareSchema,
|
||||
'credential_collectors': {
|
||||
'title': 'Credential collectors',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'$ref': '#/definitions/credential_collectors_classes'
|
||||
},
|
||||
'default': [
|
||||
'MimikatzCollector',
|
||||
'SSHCollector'
|
||||
]
|
||||
},
|
||||
'advanced': {
|
||||
'title': 'Advanced',
|
||||
'type': 'object',
|
||||
'properties':{
|
||||
'keep_tunnel_open_time': {
|
||||
'title': 'Keep tunnel open time',
|
||||
'format': 'float',
|
||||
'type': 'number',
|
||||
'default': 30,
|
||||
'description': 'Time to keep tunnel open before going down after last exploit (in seconds)'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'options': {'collapsed': true}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
export const credentialCollectors = {
|
||||
'title': 'Credential Collectors',
|
||||
'description': 'Click on a credential collector to find out what it collects.',
|
||||
'type': 'string',
|
||||
'pluginDefs': {
|
||||
'MimikatzCollector':{'name': 'MimikatzCollector', 'options': {}},
|
||||
'SSHCollector':{'name': 'SSHCollector', 'options': {}}
|
||||
},
|
||||
'anyOf': [
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['MimikatzCollector'],
|
||||
'title': 'Mimikatz Credentials Collector',
|
||||
'safe': true,
|
||||
'info': 'Collects credentials from Windows credential manager.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['SSHCollector'],
|
||||
'title': 'SSH Credentials Collector',
|
||||
'safe': true,
|
||||
'info': 'Searches users\' home directories and collects SSH keypairs.'
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
export const customPBAConfigurationSchema = {
|
||||
'title': 'Custom PBA',
|
||||
'properties': {
|
||||
'linux_command': {
|
||||
'title': 'Linux post-breach command',
|
||||
'type': 'string',
|
||||
'default': '',
|
||||
'description': 'Command to be executed after breaching. ' +
|
||||
'Use this field to run custom commands or execute the uploaded ' +
|
||||
'file on exploited machines.\nExample: ' +
|
||||
'"chmod +x ./my_script.sh; ./my_script.sh ; rm ./my_script.sh"'
|
||||
},
|
||||
'linux_file': {
|
||||
'title': 'Linux post-breach file',
|
||||
'type': 'string',
|
||||
'format': 'data-url',
|
||||
'description': 'File to be uploaded after breaching. ' +
|
||||
'Use the "Linux post-breach command" field to ' +
|
||||
'change permissions, run, or delete the file. ' +
|
||||
'Reference your file by filename.'
|
||||
},
|
||||
'linux_filename': {
|
||||
'title': 'Linux PBA filename',
|
||||
'type': 'string',
|
||||
'default': ''
|
||||
},
|
||||
'windows_command': {
|
||||
'title': 'Windows post-breach command',
|
||||
'type': 'string',
|
||||
'default': '',
|
||||
'description': 'Command to be executed after breaching. ' +
|
||||
'Use this field to run custom commands or execute the uploaded ' +
|
||||
'file on exploited machine.\nExample: ' +
|
||||
'"my_script.bat & del my_script.bat"'
|
||||
},
|
||||
'windows_file':{
|
||||
'title': 'Windows post-breach file',
|
||||
'type': 'string',
|
||||
'format': 'data-url',
|
||||
'description': 'File to be uploaded after breaching. ' +
|
||||
'Use the "Windows post-breach command" field to ' +
|
||||
'change permissions, run or delete the file. ' +
|
||||
'Reference your file by filename.'
|
||||
},
|
||||
'windows_filename': {
|
||||
'title': 'Windows PBA filename',
|
||||
'type': 'string',
|
||||
'default': ''
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import {exploitationOptionsConfigurationSchema} from './exploitation_options.js';
|
||||
|
||||
export const exploitationConfigurationSchema = {
|
||||
'title': 'Exploiters',
|
||||
'type': 'object',
|
||||
'description': 'Choose which exploiters the Monkey will attempt.',
|
||||
'properties': {
|
||||
'brute_force': {
|
||||
'title': 'Brute force exploiters',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'$ref': '#/definitions/brute_force_classes'
|
||||
}
|
||||
},
|
||||
'vulnerability': {
|
||||
'title': 'Vulnerability Exploiters',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'$ref': '#/definitions/vulnerability_classes'
|
||||
}
|
||||
},
|
||||
'options': exploitationOptionsConfigurationSchema
|
||||
}
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
export const exploitationOptionsConfigurationSchema = {
|
||||
'title': 'Exploiters Options',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'http_ports': {
|
||||
'title': 'HTTP Ports',
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'integer'
|
||||
},
|
||||
'default': [80, 8080, 443, 8008, 7001, 9200, 8983, 9600],
|
||||
'description': 'List of ports the monkey will check if are being used for HTTP'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
export const bruteForceExploiters = {
|
||||
'title': 'Brute force exploiters',
|
||||
'description': 'Click on exploiter to get more information about it.'
|
||||
+ '\u26A0'
|
||||
+ ' Note that using unsafe exploits may cause crashes of the exploited ' +
|
||||
'machine/service.',
|
||||
'type': 'string',
|
||||
'pluginDefs': {
|
||||
'SmbExploiter': {'name': 'SmbExploiter', 'options': {}},
|
||||
'PowerShellExploiter': {'name': 'PowerShellExploiter', 'options': {}},
|
||||
'WmiExploiter': {'name': 'WmiExploiter', 'options': {}},
|
||||
'MSSQLExploiter': {'name': 'MSSQLExploiter', 'options': {}},
|
||||
'SSHExploiter': {'name': 'SSHExploiter', 'options': {}}
|
||||
},
|
||||
'anyOf': [
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['SmbExploiter'],
|
||||
'title': 'SMB Exploiter',
|
||||
'safe': true,
|
||||
'info': 'Brute forces using credentials provided by user and' +
|
||||
' hashes gathered by mimikatz.',
|
||||
'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' +
|
||||
'/exploiters/smbexec/'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['PowerShellExploiter'],
|
||||
'title': 'PowerShell Remoting Exploiter',
|
||||
'info': 'Exploits PowerShell remote execution setups. PowerShell Remoting uses Windows ' +
|
||||
'Remote Management (WinRM) to allow users to run PowerShell commands on remote ' +
|
||||
'computers.',
|
||||
'safe': true,
|
||||
'link': 'https://www.guardicore.com/infectionmonkey' +
|
||||
'/docs/reference/exploiters/powershell'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['WmiExploiter'],
|
||||
'title': 'WMI Exploiter',
|
||||
'safe': true,
|
||||
'info': 'Brute forces WMI (Windows Management Instrumentation) ' +
|
||||
'using credentials provided by user and hashes gathered by ' +
|
||||
'mimikatz.',
|
||||
'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' +
|
||||
'/exploiters/wmiexec/'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['MSSQLExploiter'],
|
||||
'title': 'MSSQL Exploiter',
|
||||
'safe': true,
|
||||
'info': 'Tries to brute force into MsSQL server and uses insecure ' +
|
||||
'configuration to execute commands on server.',
|
||||
'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' +
|
||||
'/exploiters/mssql/'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['SSHExploiter'],
|
||||
'title': 'SSH Exploiter',
|
||||
'safe': true,
|
||||
'info': 'Brute forces using credentials provided by user and SSH keys ' +
|
||||
'gathered from systems.',
|
||||
'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' +
|
||||
'/exploiters/sshexec/'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const vulnerabilityExploiters = {
|
||||
'title': 'Vulnerability exploiters',
|
||||
'description': 'Click on exploiter to get more information about it.' +
|
||||
'\u26A0 Note that using unsafe exploits may cause craches of the exploited ' +
|
||||
'machine/service.',
|
||||
'type': 'string',
|
||||
'pluginDefs': {
|
||||
'ZerologonExploiter': {'name': 'ZerologonExploiter', 'options':{}},
|
||||
'Log4ShellExploiter': {'name': 'Log4ShellExploiter', 'options': {}},
|
||||
'HadoopExploiter': {'name': 'HadoopExploiter', 'options': {}}
|
||||
},
|
||||
'anyOf': [
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['ZerologonExploiter'],
|
||||
'title': 'Zerologon Exploiter',
|
||||
'safe': false,
|
||||
'info': 'Exploits a privilege escalation vulnerability (CVE-2020-1472) in a Windows ' +
|
||||
'server domain controller (DC) by using the Netlogon Remote Protocol (MS-NRPC). ' +
|
||||
'This exploiter changes the password of a Windows server DC account, steals ' +
|
||||
'credentials, and then attempts to restore the original DC password. The victim DC ' +
|
||||
'will be unable to communicate with other DCs until the original ' +
|
||||
'password has been restored. If Infection Monkey fails to restore the ' +
|
||||
'password automatically, you\'ll have to do it manually. For more ' +
|
||||
'information, see the documentation.',
|
||||
'link': 'https://www.guardicore.com/infectionmonkey' +
|
||||
'/docs/reference/exploiters/zerologon/'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['Log4ShellExploiter'],
|
||||
'title': 'Log4Shell Exploiter',
|
||||
'safe': true,
|
||||
'info': 'Exploits a software vulnerability (CVE-2021-44228) in Apache Log4j, a Java ' +
|
||||
'logging framework. Exploitation is attempted on the following services — ' +
|
||||
'Apache Solr, Apache Tomcat, Logstash.',
|
||||
'link': 'https://www.guardicore.com/infectionmonkey/docs/reference' +
|
||||
'/exploiters/log4shell/'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['HadoopExploiter'],
|
||||
'title': 'Hadoop/Yarn Exploiter',
|
||||
'safe': true,
|
||||
'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://www.guardicore.com/infectionmonkey/docs/reference/exploiters/hadoop/'
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
export const fingerprinterClasses = {
|
||||
'title': 'Fingerprinters',
|
||||
'description': 'Fingerprint modules collect info about external services ' +
|
||||
'Infection Monkey scans.',
|
||||
'type': 'string',
|
||||
'pluginDefs': {
|
||||
'smb' : {'name':'smb', 'options':''},
|
||||
'ssh' : {'name':'ssh', 'options':''},
|
||||
'http' : {'name':'http', 'options':''},
|
||||
'mssql' : {'name':'mssql', 'options':''},
|
||||
'elastic' : {'name':'elastic', 'options':''}
|
||||
},
|
||||
'anyOf': [
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['smb'],
|
||||
'title': 'SMB Fingerprinter',
|
||||
'safe': true,
|
||||
'info': 'Figures out if SMB is running and what\'s the version of it.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['ssh'],
|
||||
'title': 'SSH Fingerprinter',
|
||||
'safe': true,
|
||||
'info': 'Figures out if SSH is running.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['http'],
|
||||
'title': 'HTTP Fingerprinter',
|
||||
'safe': true,
|
||||
'info': 'Checks if host has HTTP/HTTPS ports open.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['mssql'],
|
||||
'title': 'MSSQL Fingerprinter',
|
||||
'safe': true,
|
||||
'info': 'Checks if Microsoft SQL service is running and tries to gather ' +
|
||||
'information about it.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['elastic'],
|
||||
'title': 'Elastic Fingerprinter',
|
||||
'safe': true,
|
||||
'info': 'Checks if ElasticSearch is running and attempts to find it\'s version.'
|
||||
}
|
||||
]
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
export const icmpScanConfigurationSchema = {
|
||||
'title': 'Ping scanner',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'timeout': {
|
||||
'format': 'float',
|
||||
'title': 'Ping scan timeout',
|
||||
'type': 'number',
|
||||
'description': 'Maximum time to wait for ping response'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import {icmpScanConfigurationSchema} from './icmp_scan.js';
|
||||
import {scanTargetConfigurationSchema} from './scan_target.js';
|
||||
import {tcpScanConfigurationSchema} from './tcp_scan.js';
|
||||
|
||||
export const networkScanConfigurationSchema = {
|
||||
'title': 'Network analysis',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'fingerprinters': {
|
||||
'title': 'Fingerprinters',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'$ref': '#/definitions/fingerprinter_classes'
|
||||
}
|
||||
},
|
||||
'icmp': icmpScanConfigurationSchema,
|
||||
'targets': scanTargetConfigurationSchema,
|
||||
'tcp': tcpScanConfigurationSchema
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
export const pluginConfigurationSchema = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'name': {
|
||||
'title': 'Name',
|
||||
'type': 'string'
|
||||
},
|
||||
'safe': {
|
||||
'type': 'boolean'
|
||||
},
|
||||
'options': {
|
||||
'type': 'object'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
export const postBreachActions = {
|
||||
'title': 'Post-Breach Actions',
|
||||
'description': 'Runs scripts/commands on infected machines. These actions safely simulate what ' +
|
||||
'an adversary might do after breaching a new machine. Used in ATT&CK and Zero trust reports.',
|
||||
'type': 'string',
|
||||
'pluginDefs': {
|
||||
'CommunicateAsBackdoorUser':{'name': 'CommunicateAsBackdoorUser', 'options':{}},
|
||||
'ModifyShellStartupFiles':{'name': 'ModifyShellStartupFiles', 'options':{}},
|
||||
'HiddenFiles':{'name': 'HiddenFiles', 'options':{}},
|
||||
'TrapCommand':{'name': 'TrapCommand', 'options':{}},
|
||||
'ChangeSetuidSetgid':{'name': 'ChangeSetuidSetgid', 'options':{}},
|
||||
'ScheduleJobs':{'name': 'ScheduleJobs', 'options':{}},
|
||||
'Timestomping':{'name': 'Timestomping', 'options':{}},
|
||||
'SignedScriptProxyExecution':{'name': 'SignedScriptProxyExecution', 'options':{}},
|
||||
'AccountDiscovery':{'name': 'AccountDiscovery', 'options':{}},
|
||||
'ClearCommandHistory':{'name': 'ClearCommandHistory', 'options':{}},
|
||||
'ProcessListCollection':{'name': 'ProcessListCollection', 'options':{}}
|
||||
},
|
||||
'anyOf': [
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['CommunicateAsBackdoorUser'],
|
||||
'title': 'Communicate as Backdoor User',
|
||||
'safe': true,
|
||||
'info': 'Attempts to create a new user, create HTTPS requests as that ' +
|
||||
'user and delete the user ' +
|
||||
'afterwards.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['ModifyShellStartupFiles'],
|
||||
'title': 'Modify Shell Startup Files',
|
||||
'safe': true,
|
||||
'info': 'Attempts to modify shell startup files, like ~/.profile, ' +
|
||||
'~/.bashrc, ~/.bash_profile ' +
|
||||
'in linux, and profile.ps1 in windows. Reverts modifications done' +
|
||||
' afterwards.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['HiddenFiles'],
|
||||
'title': 'Hidden Files and Directories',
|
||||
'safe': true,
|
||||
'info': 'Attempts to create a hidden file and remove it afterward.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['TrapCommand'],
|
||||
'title': 'Trap Command',
|
||||
'safe': true,
|
||||
'info': 'On Linux systems, attempts to trap a terminate signal in order ' +
|
||||
'to execute a command upon receiving that signal. Removes the trap afterwards.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['ChangeSetuidSetgid'],
|
||||
'title': 'Setuid and Setgid',
|
||||
'safe': true,
|
||||
'info': 'On Linux systems, attempts to set the setuid and setgid bits of ' +
|
||||
'a new file. ' +
|
||||
'Removes the file afterwards.',
|
||||
'attack_techniques': ['T1166']
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['ScheduleJobs'],
|
||||
'title': 'Job Scheduling',
|
||||
'safe': true,
|
||||
'info': 'Attempts to create a scheduled job on the system and remove it.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['Timestomping'],
|
||||
'title': 'Timestomping',
|
||||
'safe': true,
|
||||
'info': 'Creates a temporary file and attempts to modify its time ' +
|
||||
'attributes. Removes the file afterwards.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['SignedScriptProxyExecution'],
|
||||
'title': 'Signed Script Proxy Execution',
|
||||
'safe': false,
|
||||
'info': 'On Windows systems, attempts to execute an arbitrary file ' +
|
||||
'with the help of a pre-existing signed script.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['AccountDiscovery'],
|
||||
'title': 'Account Discovery',
|
||||
'safe': true,
|
||||
'info': 'Attempts to get a listing of user accounts on the system.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['ClearCommandHistory'],
|
||||
'title': 'Clear Command History',
|
||||
'safe': false,
|
||||
'info': 'Attempts to clear the command history.'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'enum': ['ProcessListCollection'],
|
||||
'title': 'Process List Collector',
|
||||
'safe': true,
|
||||
'info': 'Collects a list of running processes on the machine.'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import {exploitationConfigurationSchema} from './exploitation.js';
|
||||
import {networkScanConfigurationSchema} from './network_scan.js';
|
||||
|
||||
export const propagationConfigurationSchema = {
|
||||
'title': 'Propagation',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'exploitation': exploitationConfigurationSchema,
|
||||
'maximum_depth': {
|
||||
'title': 'Maximum scan depth',
|
||||
'type': 'integer',
|
||||
'minimum': 1,
|
||||
'default': 2,
|
||||
'description': 'Amount of hops allowed for the monkey to spread from the ' +
|
||||
'Island server. \n' +
|
||||
' \u26A0' +
|
||||
' Note that setting this value too high may result in the ' +
|
||||
'Monkey propagating too far, '+
|
||||
'if the "Local network scan" is enabled'
|
||||
},
|
||||
'network_scan': networkScanConfigurationSchema
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
export const ransomwareSchema = {
|
||||
'title': 'Payloads',
|
||||
'properties': {
|
||||
'encryption': {
|
||||
'title': 'Ransomware simulation',
|
||||
'type': 'object',
|
||||
'description': 'To simulate ransomware encryption, you\'ll need to provide Infection ' +
|
||||
'Monkey with files that it can safely encrypt. On each machine where you would like ' +
|
||||
'the ransomware simulation to run, create a directory and put some files in it.' +
|
||||
'\n\nProvide the path to the directory that was created on each machine.',
|
||||
'properties': {
|
||||
'enabled': {
|
||||
'title': 'Encrypt files',
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'description': 'Ransomware encryption will be simulated by flipping every bit ' +
|
||||
'in the files contained within the target directories.'
|
||||
},
|
||||
'info_box': {
|
||||
'info': 'No files will be encrypted if a directory is not specified or doesn\'t ' +
|
||||
'exist on a victim machine.'
|
||||
},
|
||||
'directories': {
|
||||
'title': 'Directories to encrypt',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'linux_target_dir': {
|
||||
'title': 'Linux target directory',
|
||||
'type': 'string',
|
||||
'format': 'valid-ransomware-target-path-linux',
|
||||
'default': '',
|
||||
'description': 'A path to a directory on Linux systems that contains ' +
|
||||
'files that you will allow Infection Monkey to encrypt. If no ' +
|
||||
'directory is specified, no files will be encrypted.'
|
||||
},
|
||||
'windows_target_dir': {
|
||||
'title': 'Windows target directory',
|
||||
'type': 'string',
|
||||
'format': 'valid-ransomware-target-path-windows',
|
||||
'default': '',
|
||||
'description': 'A path to a directory on Windows systems that contains ' +
|
||||
'files that you will allow Infection Monkey to encrypt. If no ' +
|
||||
'directory is specified, no files will be encrypted.'
|
||||
}
|
||||
}
|
||||
},
|
||||
'text_box': {
|
||||
'text': 'Note: A README.txt will be left in the specified target directory.'
|
||||
}
|
||||
}
|
||||
},
|
||||
'other_behaviors': {
|
||||
'title': 'Other ransomware behavior',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'readme': {
|
||||
'title': 'Create a README.txt file',
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'description': 'Creates a README.txt ransomware note on infected systems.'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
export const scanTargetConfigurationSchema = {
|
||||
'title': 'Network',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'info_box': {
|
||||
'info': 'The Monkey scans its subnet if "Local network scan" is checked. '+
|
||||
'Additionally, the Monkey scans machines according to "Scan target list". '
|
||||
},
|
||||
'blocked_ips': {
|
||||
'title': 'Blocked IPs',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'type': 'string',
|
||||
'format': 'ip'
|
||||
},
|
||||
'default': [],
|
||||
'description': 'List of IPs that the monkey will not scan.'
|
||||
},
|
||||
'inaccessible_subnets': {
|
||||
'title': 'Network segmentation testing',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'type': 'string',
|
||||
'format': 'ip-range'
|
||||
},
|
||||
'default': [],
|
||||
'description': 'Test for network segmentation by providing a list of network segments that should NOT be accessible to each other.\n\n ' +
|
||||
'For example, if you configured the following three segments: ' +
|
||||
'"10.0.0.0/24", "11.0.0.2/32" and "12.2.3.0/24",' +
|
||||
'a Monkey running on 10.0.0.5 will try to access machines in ' +
|
||||
'the following subnets: ' +
|
||||
'11.0.0.2/32, 12.2.3.0/24. An alert on successful cross-segment connections ' +
|
||||
'will be shown in the reports. \n\n' +
|
||||
'Network segments can be IPs, subnets or hosts. Examples:\n' +
|
||||
'\tDefine a single-IP segment: "192.168.0.1"\n' +
|
||||
'\tDefine a segment using a network range: ' +
|
||||
'"192.168.0.5-192.168.0.20"\n' +
|
||||
'\tDefine a segment using an subnet IP mask: "192.168.0.5/24"\n' +
|
||||
'\tDefine a single-host segment: "printer.example"'
|
||||
},
|
||||
'local_network_scan': {
|
||||
'title': 'Local network scan',
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'description': 'Determines whether the Monkey will scan the local subnets of machines it runs on, ' +
|
||||
'in addition to the IPs that are configured manually in the "Scan target list"'
|
||||
},
|
||||
'subnets': {
|
||||
'title': 'Scan target list',
|
||||
'type': 'array',
|
||||
'uniqueItems': true,
|
||||
'items': {
|
||||
'type': 'string',
|
||||
'format': 'ip-range'
|
||||
},
|
||||
'default': [],
|
||||
'description': 'List of targets the Monkey will try to scan. Targets can be ' +
|
||||
'IPs, subnets or hosts. ' +
|
||||
'Examples:\n' +
|
||||
'\tTarget a specific IP: "192.168.0.1"\n' +
|
||||
'\tTarget a subnet using a network range: ' +
|
||||
'"192.168.0.5-192.168.0.20"\n'+
|
||||
'\tTarget a subnet using an IP mask: "192.168.0.5/24"\n' +
|
||||
'\tTarget a specific host: "printer.example"'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
export const tcpScanConfigurationSchema = {
|
||||
'title': 'TCP scanner',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'ports': {
|
||||
'title': 'TCP target ports',
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'integer'
|
||||
},
|
||||
'default': [22,2222,445,135,389,80,8080,443,8008,3306,7001,8088,5885,5986],
|
||||
'description': 'List of TCP ports the monkey will check whether they\'re open'
|
||||
},
|
||||
'timeout': {
|
||||
'title': 'TCP scan timeout',
|
||||
'format': 'float',
|
||||
'type': 'number',
|
||||
'description': 'Maximum time to wait for TCP response.'
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue