forked from p15670423/monkey
Added jwt requirements to PBA endpoints, fixed bugs, added different
display if PBA succeeded than if failed.
This commit is contained in:
parent
92615b848d
commit
be598d0953
|
@ -271,10 +271,10 @@ class Configuration(object):
|
||||||
extract_azure_creds = True
|
extract_azure_creds = True
|
||||||
|
|
||||||
post_breach_actions = []
|
post_breach_actions = []
|
||||||
custom_pba_linux_cmd = ""
|
custom_PBA_linux_cmd = ""
|
||||||
custom_pba_windows_cmd = ""
|
custom_PBA_windows_cmd = ""
|
||||||
custom_pba_linux_file_info = None
|
PBA_linux_filename = None
|
||||||
custom_pba_windows_file_info = None
|
PBA_windows_filename = None
|
||||||
|
|
||||||
|
|
||||||
WormConfiguration = Configuration()
|
WormConfiguration = Configuration()
|
||||||
|
|
|
@ -97,12 +97,5 @@
|
||||||
"use_file_logging": true,
|
"use_file_logging": true,
|
||||||
"victims_max_exploit": 7,
|
"victims_max_exploit": 7,
|
||||||
"victims_max_find": 30,
|
"victims_max_find": 30,
|
||||||
"post_breach_actions" : [],
|
"post_breach_actions" : []
|
||||||
"custom_post_breach" : { "linux": "",
|
|
||||||
"windows": "",
|
|
||||||
"linux_file": None,
|
|
||||||
"windows_file": None,
|
|
||||||
"windows_file_info": None,
|
|
||||||
"linux_file_info": None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,15 @@ class FileExecution(PBA):
|
||||||
self.windows_filename = WormConfiguration.PBA_windows_filename
|
self.windows_filename = WormConfiguration.PBA_windows_filename
|
||||||
super(FileExecution, self).__init__("File execution", linux_command, windows_command)
|
super(FileExecution, self).__init__("File execution", linux_command, windows_command)
|
||||||
|
|
||||||
def execute_linux(self):
|
def _execute_linux(self):
|
||||||
FileExecution.download_PBA_file(FileExecution.get_dest_dir(WormConfiguration, True),
|
FileExecution.download_PBA_file(FileExecution.get_dest_dir(WormConfiguration, True),
|
||||||
self.linux_filename)
|
self.linux_filename)
|
||||||
return super(FileExecution, self).execute_linux()
|
return super(FileExecution, self)._execute_linux()
|
||||||
|
|
||||||
def execute_win(self):
|
def _execute_win(self):
|
||||||
FileExecution.download_PBA_file(FileExecution.get_dest_dir(WormConfiguration, True),
|
FileExecution.download_PBA_file(FileExecution.get_dest_dir(WormConfiguration, True),
|
||||||
self.windows_filename)
|
self.windows_filename)
|
||||||
return super(FileExecution, self).execute_win()
|
return super(FileExecution, self)._execute_win()
|
||||||
|
|
||||||
def add_default_command(self, is_linux):
|
def add_default_command(self, is_linux):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -36,7 +36,7 @@ class PBA(object):
|
||||||
if command:
|
if command:
|
||||||
hostname = socket.gethostname()
|
hostname = socket.gethostname()
|
||||||
ControlClient.send_telemetry('post_breach', {'command': command,
|
ControlClient.send_telemetry('post_breach', {'command': command,
|
||||||
'output': exec_funct(),
|
'result': exec_funct(),
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
'hostname': hostname,
|
'hostname': hostname,
|
||||||
'ip': socket.gethostbyname(hostname)
|
'ip': socket.gethostbyname(hostname)
|
||||||
|
@ -46,18 +46,23 @@ class PBA(object):
|
||||||
"""
|
"""
|
||||||
Default linux PBA execution function. Override it if additional functionality is needed
|
Default linux PBA execution function. Override it if additional functionality is needed
|
||||||
"""
|
"""
|
||||||
self._execute_default(self.linux_command)
|
return self._execute_default(self.linux_command)
|
||||||
|
|
||||||
def _execute_win(self):
|
def _execute_win(self):
|
||||||
"""
|
"""
|
||||||
Default linux PBA execution function. Override it if additional functionality is needed
|
Default linux PBA execution function. Override it if additional functionality is needed
|
||||||
"""
|
"""
|
||||||
self._execute_default(self.windows_command)
|
return self._execute_default(self.windows_command)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _execute_default(command):
|
def _execute_default(command):
|
||||||
|
"""
|
||||||
|
Default post breach command execution routine
|
||||||
|
:param command: What command to execute
|
||||||
|
:return: Tuple of command's output string and boolean, indicating if it succeeded
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
|
return subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True), True
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
# Return error output of the command
|
# Return error output of the command
|
||||||
return e.output
|
return e.output, False
|
||||||
|
|
|
@ -51,22 +51,22 @@ class PostBreach(object):
|
||||||
command_pba = PBA(name="Custom")
|
command_pba = PBA(name="Custom")
|
||||||
|
|
||||||
# Add linux commands to PBA's
|
# Add linux commands to PBA's
|
||||||
if config['PBA_linux_filename']:
|
if config.PBA_linux_filename:
|
||||||
if config['custom_PBA_linux_cmd']:
|
if config.custom_PBA_linux_cmd:
|
||||||
file_pba.linux_command = config['custom_PBA_linux_cmd']
|
file_pba.linux_command = config.custom_PBA_linux_cmd
|
||||||
else:
|
else:
|
||||||
file_pba.add_default_command(is_linux=True)
|
file_pba.add_default_command(is_linux=True)
|
||||||
elif config['custom_PBA_linux_cmd']:
|
elif config.custom_PBA_linux_cmd:
|
||||||
command_pba.linux_command = config['custom_PBA_linux_cmd']
|
command_pba.linux_command = config.custom_PBA_linux_cmd
|
||||||
|
|
||||||
# Add windows commands to PBA's
|
# Add windows commands to PBA's
|
||||||
if config['PBA_windows_filename']:
|
if config.PBA_windows_filename:
|
||||||
if config['custom_PBA_windows_cmd']:
|
if config.custom_PBA_windows_cmd:
|
||||||
file_pba.windows_command = config['custom_PBA_windows_cmd']
|
file_pba.windows_command = config.custom_PBA_windows_cmd
|
||||||
else:
|
else:
|
||||||
file_pba.add_default_command(is_linux=False)
|
file_pba.add_default_command(is_linux=False)
|
||||||
elif config['custom_PBA_windows_cmd']:
|
elif config.custom_PBA_windows_cmd:
|
||||||
command_pba.windows_command = config['custom_PBA_windows_cmd']
|
command_pba.windows_command = config.custom_PBA_windows_cmd
|
||||||
|
|
||||||
# Add PBA's to list
|
# Add PBA's to list
|
||||||
if file_pba.linux_command or file_pba.windows_command:
|
if file_pba.linux_command or file_pba.windows_command:
|
||||||
|
|
|
@ -55,13 +55,13 @@ class FileUpload(flask_restful.Resource):
|
||||||
:param file_type: Type indicates which file was deleted, linux of windows
|
:param file_type: Type indicates which file was deleted, linux of windows
|
||||||
:return: Empty response
|
:return: Empty response
|
||||||
"""
|
"""
|
||||||
file_conf_path = PBA_LINUX_FILENAME_PATH if file_type == 'PBAlinux' else PBA_WINDOWS_FILENAME_PATH
|
filename_path = PBA_LINUX_FILENAME_PATH if file_type == 'PBAlinux' else PBA_WINDOWS_FILENAME_PATH
|
||||||
filename = ConfigService.get_config_value(file_conf_path)
|
filename = ConfigService.get_config_value(filename_path)
|
||||||
file_path = os.path.join(UPLOADS_DIR, filename)
|
file_path = os.path.join(UPLOADS_DIR, filename)
|
||||||
try:
|
try:
|
||||||
if os.path.exists(file_path):
|
if os.path.exists(file_path):
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
ConfigService.set_config_value(file_conf_path, {'size': '0', 'name': ''})
|
ConfigService.set_config_value(filename_path, '')
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
LOG.error("Can't remove previously uploaded post breach files: %s" % e)
|
LOG.error("Can't remove previously uploaded post breach files: %s" % e)
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,7 @@ import functools
|
||||||
import logging
|
import logging
|
||||||
from jsonschema import Draft4Validator, validators
|
from jsonschema import Draft4Validator, validators
|
||||||
from six import string_types
|
from six import string_types
|
||||||
from werkzeug.utils import secure_filename
|
|
||||||
import os
|
import os
|
||||||
import base64
|
|
||||||
|
|
||||||
from cc.database import mongo
|
from cc.database import mongo
|
||||||
from cc.encryptor import encryptor
|
from cc.encryptor import encryptor
|
||||||
|
@ -36,7 +34,7 @@ ENCRYPTED_CONFIG_STRINGS = \
|
||||||
['cnc', 'aws_config', 'aws_secret_access_key']
|
['cnc', 'aws_config', 'aws_secret_access_key']
|
||||||
]
|
]
|
||||||
|
|
||||||
UPLOADS_DIR = '/cc/userUploads'
|
UPLOADS_DIR = 'monkey_island/cc/userUploads'
|
||||||
|
|
||||||
# Where to find file names in config
|
# Where to find file names in config
|
||||||
PBA_WINDOWS_FILENAME_PATH = ['monkey', 'behaviour', 'PBA_windows_filename']
|
PBA_WINDOWS_FILENAME_PATH = ['monkey', 'behaviour', 'PBA_windows_filename']
|
||||||
|
@ -315,14 +313,12 @@ class ConfigService:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove_PBA_files():
|
def remove_PBA_files():
|
||||||
if ConfigService.get_config():
|
if ConfigService.get_config():
|
||||||
linux_file_name = ConfigService.get_config_value(
|
linux_filename = ConfigService.get_config_value(PBA_WINDOWS_FILENAME_PATH)
|
||||||
['monkey', 'behaviour', 'custom_post_breach', 'linux_file_info', 'name'])
|
windows_filename = ConfigService.get_config_value(PBA_LINUX_FILENAME_PATH)
|
||||||
windows_file_name = ConfigService.get_config_value(
|
if linux_filename:
|
||||||
['monkey', 'behaviour', 'custom_post_breach', 'windows_file_info', 'name'])
|
ConfigService.remove_file(linux_filename)
|
||||||
if linux_file_name:
|
if windows_filename:
|
||||||
ConfigService.remove_file(linux_file_name)
|
ConfigService.remove_file(windows_filename)
|
||||||
if windows_file_name:
|
|
||||||
ConfigService.remove_file(windows_file_name)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove_file(file_name):
|
def remove_file(file_name):
|
||||||
|
|
|
@ -329,13 +329,13 @@ SCHEMA = {
|
||||||
"Reference your file by filename."
|
"Reference your file by filename."
|
||||||
},
|
},
|
||||||
"custom_PBA_windows_cmd": {
|
"custom_PBA_windows_cmd": {
|
||||||
"title": "Windows command",
|
"title": "Windows post breach command",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "Windows command to be executed after breaching."
|
"description": "Windows command to be executed after breaching."
|
||||||
},
|
},
|
||||||
"PBA_windows_file": {
|
"PBA_windows_file": {
|
||||||
"title": "Windows file",
|
"title": "Windows post breach file",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "data-url",
|
"format": "data-url",
|
||||||
"description": "File to be executed after breaching. "
|
"description": "File to be executed after breaching. "
|
||||||
|
|
|
@ -6,6 +6,7 @@ class AuthComponent extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
this.auth = new AuthService();
|
this.auth = new AuthService();
|
||||||
this.authFetch = this.auth.authFetch;
|
this.authFetch = this.auth.authFetch;
|
||||||
|
this.jwtHeader = this.auth.jwtHeader();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,13 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
|
|
||||||
PBAwindows = () => {
|
PBAwindows = () => {
|
||||||
return (<FilePond
|
return (<FilePond
|
||||||
server='/api/fileUpload/PBAwindows'
|
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()}
|
files={this.getWinPBAfile()}
|
||||||
onupdatefiles={fileItems => {
|
onupdatefiles={fileItems => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -211,7 +217,13 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
|
|
||||||
PBAlinux = () => {
|
PBAlinux = () => {
|
||||||
return (<FilePond
|
return (<FilePond
|
||||||
server='/api/fileUpload/PBAlinux'
|
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()}
|
files={this.getLinuxPBAfile()}
|
||||||
onupdatefiles={fileItems => {
|
onupdatefiles={fileItems => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
|
@ -13,9 +13,19 @@ let renderMachine = function (data) {
|
||||||
return <div>{data.label} ( {renderIpAddresses(data)} )</div>
|
return <div>{data.label} ( {renderIpAddresses(data)} )</div>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let renderPbaResults = function (results) {
|
||||||
|
let pbaClass = "";
|
||||||
|
if (results[1]){
|
||||||
|
pbaClass="pba-success"
|
||||||
|
} else {
|
||||||
|
pbaClass="pba-danger"
|
||||||
|
}
|
||||||
|
return <div className={pbaClass}> {results[0]} </div>
|
||||||
|
};
|
||||||
|
|
||||||
const subColumns = [
|
const subColumns = [
|
||||||
{id: 'pba_name', Header: "Name", accessor: x => x.name, style: { 'white-space': 'unset' }},
|
{id: 'pba_name', Header: "Name", accessor: x => x.name, style: { 'white-space': 'unset' }},
|
||||||
{id: 'pba_output', Header: "Output", accessor: x => x.output, style: { 'white-space': 'unset' }}
|
{id: 'pba_output', Header: "Output", accessor: x => renderPbaResults(x.result), style: { 'white-space': 'unset' }}
|
||||||
];
|
];
|
||||||
|
|
||||||
let renderDetails = function (data) {
|
let renderDetails = function (data) {
|
||||||
|
|
|
@ -4,8 +4,6 @@ import ReactDOM from 'react-dom';
|
||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
import App from './components/Main';
|
import App from './components/Main';
|
||||||
import Bootstrap from 'bootstrap/dist/css/bootstrap.css'; // eslint-disable-line no-unused-vars
|
import Bootstrap from 'bootstrap/dist/css/bootstrap.css'; // eslint-disable-line no-unused-vars
|
||||||
import { FilePond, registerPlugin } from 'react-filepond';
|
|
||||||
import 'filepond/dist/filepond.min.css';
|
|
||||||
|
|
||||||
// Render the main component into the dom
|
// Render the main component into the dom
|
||||||
ReactDOM.render(<App />, document.getElementById('app'));
|
ReactDOM.render(<App />, document.getElementById('app'));
|
||||||
|
|
|
@ -15,6 +15,12 @@ export default class AuthService {
|
||||||
return this._authFetch(url, options);
|
return this._authFetch(url, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jwtHeader = () => {
|
||||||
|
if (this._loggedIn()) {
|
||||||
|
return 'JWT ' + this._getToken();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
hashSha3(text) {
|
hashSha3(text) {
|
||||||
let hash = new SHA3(512);
|
let hash = new SHA3(512);
|
||||||
hash.update(text);
|
hash.update(text);
|
||||||
|
|
|
@ -424,6 +424,14 @@ body {
|
||||||
top: 30%;
|
top: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pba-danger {
|
||||||
|
background-color: #ffc7af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pba-success {
|
||||||
|
background-color: #afd2a2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Print report styling */
|
/* Print report styling */
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
|
|
Loading…
Reference in New Issue