Added jwt requirements to PBA endpoints, fixed bugs, added different

display if PBA succeeded than if failed.
This commit is contained in:
VakarisZ 2019-03-14 17:53:05 +02:00
parent 92615b848d
commit be598d0953
14 changed files with 81 additions and 52 deletions

View File

@ -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()

View File

@ -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
}
} }

View File

@ -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):
""" """

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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):

View File

@ -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. "

View File

@ -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();
} }
} }

View File

@ -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({

View File

@ -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) {

View File

@ -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'));

View File

@ -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);

View File

@ -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 {