PBA file refactoring almost working

This commit is contained in:
VakarisZ 2020-06-30 16:07:43 +03:00
parent 6cc4c85132
commit aad9e5069e
5 changed files with 270 additions and 151 deletions

View File

@ -1,4 +1,6 @@
{
"server_config": "password",
"deployment": "develop"
}
"deployment": "develop",
"user": "test",
"password_hash": "9ece086e9bac491fac5c1d1046ca11d737b92a2b2ebd93f005d7b710110c0a678288166e7fbe796883a4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14"
}

View File

@ -0,0 +1,91 @@
import React from 'react';
import AuthComponent from '../AuthComponent';
import {FilePond} from 'react-filepond';
import 'filepond/dist/filepond.min.css';
class PbaInput extends AuthComponent {
constructor(props) {
super(props);
console.log("Constructor called");
// set schema from server
this.state = this.getStateFromProps(this.props);
}
getStateFromProps(props){
let options = props.options
// set schema from server
return {
PBAFile: options.PbaFile,
filename: options.filename,
apiEndpoint: options.apiEndpoint,
setPbaFile: options.setPbaFile
};
}
getPBAfile() {
if (this.state.PBAFile.length !== 0) {
return this.state.PBAFile
return PbaInput.getMockPBAfile(this.state.PBAFile)
} else if (this.state.filename) {
return PbaInput.getFullPBAfile(this.state.filename)
}
}
static getMockPBAfile(mockFile) {
let pbaFile = [{
name: mockFile.name,
source: mockFile.name,
options: {
type: 'limbo'
}
}];
pbaFile[0].options.file = mockFile;
return pbaFile
}
static getFullPBAfile(filename) {
return [{
source: filename,
options: {
type: 'limbo'
}
}];
}
getServerParams(path) {
return {
url: path,
process: this.getRequestParams(),
revert: this.getRequestParams(),
restore: this.getRequestParams(),
load: this.getRequestParams(),
fetch: this.getRequestParams()
}
}
getRequestParams() {
return {headers: {'Authorization': this.jwtHeader}}
}
render() {
return (<FilePond
key={this.state.apiEndpoint}
server={this.getServerParams(this.state.apiEndpoint)}
files={this.getPBAfile()}
onupdatefiles={fileItems => {
if (fileItems.length > 0) {
this.state.setPbaFile([fileItems[0].file], fileItems[0].file.name)
} else {
this.state.setPbaFile([], "")
}
}}
/>)
}
}
export default PbaInput;

View File

@ -0,0 +1,70 @@
import ArrayFieldTemplate from "../ui-components/AdvancedMultipleSelect";
import PbaInput from "./PbaInput";
import {API_PBA_LINUX, API_PBA_WINDOWS} from '../pages/ConfigurePage';
export default function UiSchema(props) {
const UiSchema = {
basic: {
'ui:order': ['general', 'credentials'],
credentials: {
exploit_password_list: {
"ui:ArrayFieldTemplate": ArrayFieldTemplate
}
}
},
basic_network: {},
monkey: {
behaviour: {
custom_PBA_linux_cmd: {
'ui:widget': 'textarea',
'ui:emptyValue': ''
},
PBA_linux_file: {
'ui:widget': PbaInput,
'ui:options': {
PbaFile: props.configuration.PBAlinuxFile,
filename: props.configuration.configuration.monkey.behaviour.PBA_linux_filename,
apiEndpoint: API_PBA_LINUX,
setPbaFile: props.setPbaFileLinux
}
},
custom_PBA_windows_cmd: {
'ui:widget': 'textarea',
'ui:emptyValue': ''
},
PBA_windows_file: {
'ui:widget': PbaInput,
'ui:options': {
PbaFile: props.configuration.PBAwindowsFile,
filename: props.configuration.configuration.monkey.behaviour.PBA_windows_filename,
apiEndpoint: API_PBA_WINDOWS,
setPbaFile: props.setPbaFileWindows
}
},
PBA_linux_filename: {
classNames: 'linux-pba-file-info',
'ui:emptyValue': ''
},
PBA_windows_filename: {
classNames: 'windows-pba-file-info',
'ui:emptyValue': ''
}
}
},
cnc: {},
network: {},
exploits: {
general: {
exploiter_classes: {
"ui:ArrayFieldTemplate": ArrayFieldTemplate
}
}
},
internal: {
general: {
started_on_island: {'ui:widget': 'hidden'}
}
}
}
return UiSchema[props.configuration.selectedSection]
}

View File

@ -3,9 +3,8 @@ import Form from 'react-jsonschema-form-bs4';
import {Col, Modal, Nav, Button} from 'react-bootstrap';
import FileSaver from 'file-saver';
import AuthComponent from '../AuthComponent';
import {FilePond} from 'react-filepond';
import 'filepond/dist/filepond.min.css';
import ConfigMatrixComponent from '../attack/ConfigMatrixComponent';
import UiSchema from '../configuration-components/UiSchema';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faInfoCircle} from '@fortawesome/free-solid-svg-icons/faInfoCircle';
import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck';
@ -13,20 +12,19 @@ import {faExclamationCircle} from '@fortawesome/free-solid-svg-icons/faExclamati
const ATTACK_URL = '/api/attack';
const CONFIG_URL = '/api/configuration/island';
export const API_PBA_LINUX = '/api/fileUpload/PBAlinux';
export const API_PBA_WINDOWS = '/api/fileUpload/PBAwindows';
class ConfigurePageComponent extends AuthComponent {
constructor(props) {
super(props);
this.PBAwindowsPond = null;
this.PBAlinuxPond = null;
this.currentSection = 'attack';
this.currentFormData = {};
this.initialConfig = {};
this.initialAttackConfig = {};
this.sectionsOrder = ['attack', 'basic', 'basic_network', 'monkey', 'cnc', 'network', 'exploits', 'internal'];
this.uiSchemas = this.getUiSchemas();
// set schema from server
this.state = {
schema: {},
configuration: {},
@ -34,51 +32,11 @@ class ConfigurePageComponent extends AuthComponent {
lastAction: 'none',
sections: [],
selectedSection: 'attack',
PBAwinFile: [],
PBAlinuxFile: [],
showAttackAlert: false
};
}
showAttackAlert: false,
getUiSchemas() {
return ({
basic: {'ui:order': ['general', 'credentials']},
basic_network: {},
monkey: {
behaviour: {
custom_PBA_linux_cmd: {
'ui:widget': 'textarea',
'ui:emptyValue': ''
},
PBA_linux_file: {
'ui:widget': this.PBAlinux
},
custom_PBA_windows_cmd: {
'ui:widget': 'textarea',
'ui:emptyValue': ''
},
PBA_windows_file: {
'ui:widget': this.PBAwindows
},
PBA_linux_filename: {
classNames: 'linux-pba-file-info',
'ui:emptyValue': ''
},
PBA_windows_filename: {
classNames: 'windows-pba-file-info',
'ui:emptyValue': ''
}
}
},
cnc: {},
network: {},
exploits: {},
internal: {
general: {
started_on_island: {'ui:widget': 'hidden'}
}
}
})
PBAwindowsFile: [],
PBAlinuxFile: []
};
}
setInitialConfig(config) {
@ -122,7 +80,7 @@ class ConfigurePageComponent extends AuthComponent {
.then(res => res.json())
.then(data => {
this.setInitialConfig(data.configuration);
this.setState({configuration: data.configuration})
this.setState({configuration: data.configuration});
})
};
@ -271,7 +229,6 @@ class ConfigurePageComponent extends AuthComponent {
};
resetConfig = () => {
this.removePBAfiles();
this.authFetch(CONFIG_URL,
{
method: 'POST',
@ -280,14 +237,15 @@ class ConfigurePageComponent extends AuthComponent {
})
.then(res => res.json())
.then(res => {
this.setState({
lastAction: 'reset',
schema: res.schema,
configuration: res.configuration
});
this.setInitialConfig(res.configuration);
this.props.onStatusChange();
});
this.setState({
lastAction: 'reset',
schema: res.schema,
configuration: res.configuration
});
this.setInitialConfig(res.configuration);
this.props.onStatusChange();
}
);
this.authFetch(ATTACK_URL, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
@ -298,23 +256,22 @@ class ConfigurePageComponent extends AuthComponent {
this.setState({attackConfig: res.configuration});
this.setInitialAttackConfig(res.configuration);
})
this.removePBAfile(API_PBA_WINDOWS, this.setPbaFileWindows)
this.removePBAfile(API_PBA_LINUX, this.setPbaFileLinux)
};
removePBAfiles() {
// We need to clean files from widget, local state and configuration (to sync with bac end)
if (this.PBAwindowsPond !== null) {
this.PBAwindowsPond.removeFile();
}
if (this.PBAlinuxPond !== null) {
this.PBAlinuxPond.removeFile();
}
removePBAfile(apiEndpoint, setParamsFnc) {
this.sendPbaRemoveRequest(apiEndpoint)
setParamsFnc([], "")
}
sendPbaRemoveRequest(apiEndpoint) {
let request_options = {
method: 'DELETE',
headers: {'Content-Type': 'text/plain'}
};
this.authFetch('/api/fileUpload/PBAlinux', request_options);
this.authFetch('/api/fileUpload/PBAwindows', request_options);
this.setState({PBAlinuxFile: [], PBAwinFile: []});
this.authFetch(apiEndpoint, request_options);
}
setConfigOnImport = (event) => {
@ -366,82 +323,6 @@ class ConfigurePageComponent extends AuthComponent {
event.target.value = null;
};
PBAwindows = () => {
return (<FilePond
server={{
url: '/api/fileUpload/PBAwindows',
process: {headers: {'Authorization': this.jwtHeader}},
revert: {headers: {'Authorization': this.jwtHeader}},
restore: {headers: {'Authorization': this.jwtHeader}},
load: {headers: {'Authorization': this.jwtHeader}},
fetch: {headers: {'Authorization': this.jwtHeader}}
}}
files={this.getWinPBAfile()}
onupdatefiles={fileItems => {
this.setState({
PBAwinFile: fileItems.map(fileItem => fileItem.file)
})
}}
ref={ref => this.PBAwindowsPond = ref}
/>)
};
PBAlinux = () => {
return (<FilePond
server={{
url: '/api/fileUpload/PBAlinux',
process: {headers: {'Authorization': this.jwtHeader}},
revert: {headers: {'Authorization': this.jwtHeader}},
restore: {headers: {'Authorization': this.jwtHeader}},
load: {headers: {'Authorization': this.jwtHeader}},
fetch: {headers: {'Authorization': this.jwtHeader}}
}}
files={this.getLinuxPBAfile()}
onupdatefiles={fileItems => {
this.setState({
PBAlinuxFile: fileItems.map(fileItem => fileItem.file)
})
}}
ref={ref => this.PBAlinuxPond = ref}
/>)
};
getWinPBAfile() {
if (this.state.PBAwinFile.length !== 0) {
return ConfigurePageComponent.getMockPBAfile(this.state.PBAwinFile[0])
} else if (this.state.configuration.monkey.behaviour.PBA_windows_filename) {
return ConfigurePageComponent.getFullPBAfile(this.state.configuration.monkey.behaviour.PBA_windows_filename)
}
}
getLinuxPBAfile() {
if (this.state.PBAlinuxFile.length !== 0) {
return ConfigurePageComponent.getMockPBAfile(this.state.PBAlinuxFile[0])
} else if (this.state.configuration.monkey.behaviour.PBA_linux_filename) {
return ConfigurePageComponent.getFullPBAfile(this.state.configuration.monkey.behaviour.PBA_linux_filename)
}
}
static getFullPBAfile(filename) {
return [{
source: filename,
options: {
type: 'limbo'
}
}];
}
static getMockPBAfile(mockFile) {
let pbaFile = [{
source: mockFile.name,
options: {
type: 'limbo'
}
}];
pbaFile[0].options.file = mockFile;
return pbaFile
}
renderMatrix = () => {
return (<ConfigMatrixComponent configuration={this.state.attackConfig}
submit={this.componentDidMount}
@ -449,12 +330,15 @@ class ConfigurePageComponent extends AuthComponent {
change={this.attackTechniqueChange}/>)
};
renderConfigContent = (displayedSchema) => {
return (<div>
{this.renderBasicNetworkWarning()}
<Form schema={displayedSchema}
uiSchema={this.uiSchemas[this.state.selectedSection]}
uiSchema={UiSchema({
configuration: this.state,
setPbaFileWindows: this.setPbaFileWindows,
setPbaFileLinux: this.setPbaFileLinux,
})}
formData={this.state.configuration[this.state.selectedSection]}
onChange={this.onChange}
noValidate={true}
@ -464,6 +348,27 @@ class ConfigurePageComponent extends AuthComponent {
</div>)
};
setPbaFileWindows = (pbaFile, filename) => {
let pbaFileDeepCopy = JSON.parse(JSON.stringify(pbaFile))
let config = this.state.configuration
config.monkey.behaviour.PBA_windows_filename = filename
this.setState({
PBAwindowsFile: pbaFileDeepCopy,
configuration: config
})
}
setPbaFileLinux = (pbaFile, filename) => {
let pbaFileDeepCopy = JSON.parse(JSON.stringify(pbaFile))
let config = this.state.configuration
config.monkey.behaviour.PBA_linux_filename = filename
console.log(config);
this.setState({
PBAlinuxFile: pbaFileDeepCopy,
configuration: config
})
}
renderBasicNetworkWarning = () => {
if (this.state.selectedSection === 'basic_network') {
return (<div className='alert alert-info'>
@ -495,6 +400,7 @@ class ConfigurePageComponent extends AuthComponent {
displayedSchema = this.state.schema['properties'][this.state.selectedSection];
displayedSchema['definitions'] = this.state.schema['definitions'];
}
let content = '';
if (this.state.selectedSection === 'attack' && Object.entries(this.state.attackConfig).length !== 0) {
content = this.renderMatrix()

View File

@ -0,0 +1,50 @@
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;