forked from p15670423/monkey
Refactored fingerprint scanners to add port on init
This commit is contained in:
parent
44077e6bfe
commit
7f5c07c1fd
|
@ -0,0 +1,10 @@
|
|||
|
||||
|
||||
# abstract, static method decorator
|
||||
class abstractstatic(staticmethod):
|
||||
__slots__ = ()
|
||||
|
||||
def __init__(self, function):
|
||||
super(abstractstatic, self).__init__(function)
|
||||
function.__isabstractmethod__ = True
|
||||
__isabstractmethod__ = True
|
|
@ -89,7 +89,10 @@ class SambaCryExploiter(HostExploiter):
|
|||
LOG.info(
|
||||
"Shares triggered successfully on host %s: %s" % (
|
||||
self.host.ip_addr, str(successfully_triggered_shares)))
|
||||
self.add_vuln_port(str(writable_shares_creds_dict))
|
||||
# TODO: add vulnerable url
|
||||
#for share, fullpath in successfully_triggered_shares:
|
||||
# self.add_vuln_url("smb://<username>@<hostname/ip>:<port>/<share_name>" % False,
|
||||
# self.host.ip_addr, False, share)
|
||||
return True
|
||||
else:
|
||||
LOG.info("No shares triggered successfully on host %s" % self.host.ip_addr)
|
||||
|
|
|
@ -18,19 +18,10 @@ class HostFinger(object):
|
|||
def _SCANNED_SERVICE(self):
|
||||
pass
|
||||
|
||||
def init_service(self, services, service_key):
|
||||
def init_service(self, services, service_key, port):
|
||||
services[service_key] = {}
|
||||
services[service_key]['display_name'] = self._SCANNED_SERVICE
|
||||
|
||||
def add_found_port(self, services, port, key=None):
|
||||
if key:
|
||||
services[key]['port'] = port
|
||||
else:
|
||||
for service in services:
|
||||
if services[service]['display_name'] == self._SCANNED_SERVICE:
|
||||
service[service]['port'] = port
|
||||
return
|
||||
raise KeyError
|
||||
services[service_key]['port'] = port
|
||||
|
||||
@abstractmethod
|
||||
def get_host_fingerprint(self, host):
|
||||
|
|
|
@ -36,11 +36,10 @@ class ElasticFinger(HostFinger):
|
|||
url = 'http://%s:%s/' % (host.ip_addr, ES_PORT)
|
||||
with closing(requests.get(url, timeout=ES_HTTP_TIMEOUT)) as req:
|
||||
data = json.loads(req.text)
|
||||
self.init_service(host.services, ES_SERVICE)
|
||||
self.init_service(host.services, ES_SERVICE, ES_PORT)
|
||||
host.services[ES_SERVICE]['cluster_name'] = data['cluster_name']
|
||||
host.services[ES_SERVICE]['name'] = data['name']
|
||||
host.services[ES_SERVICE]['version'] = data['version']['number']
|
||||
self.add_found_port(host.services, ES_PORT)
|
||||
return True
|
||||
except Timeout:
|
||||
LOG.debug("Got timeout while trying to read header information")
|
||||
|
|
|
@ -37,9 +37,8 @@ class HTTPFinger(HostFinger):
|
|||
with closing(head(url, verify=False, timeout=1)) as req:
|
||||
server = req.headers.get('Server')
|
||||
ssl = True if 'https://' in url else False
|
||||
self.init_service(host.services, ('tcp-' + port[1]))
|
||||
self.init_service(host.services, ('tcp-' + port[1]), port[0])
|
||||
host.services['tcp-' + port[1]]['name'] = 'http'
|
||||
self.add_found_port(host.services, port[0], ('tcp-' + port[1]))
|
||||
host.services['tcp-' + port[1]]['data'] = (server,ssl)
|
||||
LOG.info("Port %d is open on host %s " % (port[0], host))
|
||||
break # https will be the same on the same port
|
||||
|
|
|
@ -63,7 +63,7 @@ class MSSQLFinger(HostFinger):
|
|||
sock.close()
|
||||
return False
|
||||
|
||||
self.init_service(host.services, self._SCANNED_SERVICE)
|
||||
self.init_service(host.services, self._SCANNED_SERVICE, MSSQLFinger.SQL_BROWSER_DEFAULT_PORT)
|
||||
|
||||
# Loop through the server data
|
||||
instances_list = data[3:].decode().split(';;')
|
||||
|
@ -76,7 +76,6 @@ class MSSQLFinger(HostFinger):
|
|||
# Each instance's info is nested under its own name, if there are multiple instances
|
||||
# each will appear under its own name
|
||||
host.services[self._SCANNED_SERVICE][instance_info[1]][instance_info[i - 1]] = instance_info[i]
|
||||
self.add_found_port(host.services, MSSQLFinger.SQL_BROWSER_DEFAULT_PORT)
|
||||
# Close the socket
|
||||
sock.close()
|
||||
|
||||
|
|
|
@ -51,14 +51,13 @@ class MySQLFinger(HostFinger):
|
|||
|
||||
version, curpos = struct_unpack_tracker_string(data, curpos) # special coded to solve string parsing
|
||||
version = version[0]
|
||||
self.init_service(host.services, SQL_SERVICE)
|
||||
self.init_service(host.services, SQL_SERVICE, MYSQL_PORT)
|
||||
host.services[SQL_SERVICE]['version'] = version
|
||||
version = version.split('-')[0].split('.')
|
||||
host.services[SQL_SERVICE]['major_version'] = version[0]
|
||||
host.services[SQL_SERVICE]['minor_version'] = version[1]
|
||||
host.services[SQL_SERVICE]['build_version'] = version[2]
|
||||
thread_id, curpos = struct_unpack_tracker(data, curpos, "<I") # ignore thread id
|
||||
self.add_found_port(host.services, MYSQL_PORT)
|
||||
# protocol parsing taken from
|
||||
# https://nmap.org/nsedoc/scripts/mysql-info.html
|
||||
if protocol == 10:
|
||||
|
|
|
@ -114,7 +114,7 @@ class SMBFinger(HostFinger):
|
|||
s.settimeout(0.7)
|
||||
s.connect((host.ip_addr, SMB_PORT))
|
||||
|
||||
self.init_service(host.services, SMB_SERVICE)
|
||||
self.init_service(host.services, SMB_SERVICE, SMB_PORT)
|
||||
|
||||
h = SMBHeader(cmd="\x72", flag1="\x18", flag2="\x53\xc8")
|
||||
n = SMBNego(data=SMBNegoFingerData())
|
||||
|
@ -152,7 +152,6 @@ class SMBFinger(HostFinger):
|
|||
host.os['version'] = os_version
|
||||
else:
|
||||
host.services[SMB_SERVICE]['os-version'] = os_version
|
||||
self.add_found_port(host.services, SMB_PORT)
|
||||
return True
|
||||
except Exception as exc:
|
||||
LOG.debug("Error getting smb fingerprint: %s", exc)
|
||||
|
|
|
@ -46,13 +46,12 @@ class SSHFinger(HostFinger):
|
|||
is_open, banner = check_tcp_port(host.ip_addr, SSH_PORT, TIMEOUT, True)
|
||||
|
||||
if is_open:
|
||||
self.init_service(host.services, SSH_SERVICE_DEFAULT)
|
||||
self.init_service(host.services, SSH_SERVICE_DEFAULT, SSH_PORT)
|
||||
|
||||
if banner:
|
||||
host.services[SSH_SERVICE_DEFAULT]['banner'] = banner
|
||||
if self._banner_regex.search(banner):
|
||||
self._banner_match(SSH_SERVICE_DEFAULT, host, banner)
|
||||
self.add_found_port(host.services, SSH_PORT)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
|
|
@ -4,8 +4,6 @@ from random import shuffle
|
|||
import infection_monkey.config
|
||||
from infection_monkey.network import HostScanner, HostFinger
|
||||
from infection_monkey.network.tools import check_tcp_ports, tcp_port_to_service
|
||||
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
|
||||
from common.utils.attack_utils import ScanStatus
|
||||
|
||||
__author__ = 'itamar'
|
||||
|
||||
|
@ -38,8 +36,7 @@ class TcpScanner(HostScanner, HostFinger):
|
|||
self._config.tcp_scan_get_banner)
|
||||
for target_port, banner in izip_longest(ports, banners, fillvalue=None):
|
||||
service = tcp_port_to_service(target_port)
|
||||
self.init_service(host.services, service)
|
||||
self.add_found_port(host.services, target_port, key=service)
|
||||
self.init_service(host.services, service, target_port)
|
||||
if banner:
|
||||
host.services[service]['banner'] = banner
|
||||
if only_one_port:
|
||||
|
|
|
@ -56,12 +56,10 @@ class Root(flask_restful.Resource):
|
|||
infection_done = NodeService.is_monkey_finished_running()
|
||||
if not infection_done:
|
||||
report_done = False
|
||||
attack_report_done = False
|
||||
else:
|
||||
if is_any_exists:
|
||||
ReportService.get_report()
|
||||
AttackReportService.get_latest_report()
|
||||
report_done = ReportService.is_report_generated()
|
||||
attack_report_done = AttackReportService.is_report_generated()
|
||||
return dict(run_server=True, run_monkey=is_any_exists, infection_done=infection_done,
|
||||
report_done=report_done, attack_report_done=attack_report_done)
|
||||
report_done=report_done)
|
||||
|
|
|
@ -23,14 +23,14 @@ class AttackConfig(object):
|
|||
"""
|
||||
Gets technique by id
|
||||
:param technique_id: E.g. T1210
|
||||
:return: Technique object or false if technique is not found
|
||||
:return: Technique object or None if technique is not found
|
||||
"""
|
||||
attack_config = get_config()
|
||||
attack_config = AttackConfig.get_config()
|
||||
for key, attack_type in attack_config['properties'].items():
|
||||
for key, technique in attack_type['properties'].items():
|
||||
if key == technique_id:
|
||||
return technique
|
||||
return False
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_config_schema():
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
from monkey_island.cc.services.attack.technique_reports import T1210, T1197
|
||||
from monkey_island.cc.services.attack.attack_telem import get_latest_telem
|
||||
from monkey_island.cc.services.attack.attack_config import get_technique_values
|
||||
from monkey_island.cc.services.attack.attack_telem import AttackTelemService
|
||||
from monkey_island.cc.services.attack.attack_config import AttackConfig
|
||||
from monkey_island.cc.database import mongo
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
@ -9,8 +9,8 @@ __author__ = "VakarisZ"
|
|||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
TECHNIQUES = {'T1210': T1210,
|
||||
'T1197': T1197}
|
||||
TECHNIQUES = {'T1210': T1210.T1210,
|
||||
'T1197': T1197.T1197}
|
||||
|
||||
REPORT_NAME = 'new_report'
|
||||
|
||||
|
@ -25,8 +25,8 @@ class AttackReportService:
|
|||
Generates new report based on telemetries, replaces old report in db with new one.
|
||||
:return: Report object
|
||||
"""
|
||||
report = {'techniques': {}, 'meta': get_latest_telem(), 'name': REPORT_NAME}
|
||||
for tech_id, value in get_technique_values().items():
|
||||
report = {'techniques': {}, 'meta': AttackTelemService.get_latest_telem(), 'name': REPORT_NAME}
|
||||
for tech_id, value in AttackConfig.get_technique_values().items():
|
||||
if value:
|
||||
try:
|
||||
report['techniques'].update({tech_id: TECHNIQUES[tech_id].get_report_data()})
|
||||
|
@ -43,7 +43,7 @@ class AttackReportService:
|
|||
:return: report dict.
|
||||
"""
|
||||
if AttackReportService.is_report_generated():
|
||||
telem_time = get_latest_telem()
|
||||
telem_time = AttackTelemService.get_latest_telem()
|
||||
latest_report = mongo.db.attack_report.find_one({'name': REPORT_NAME})
|
||||
if telem_time and latest_report['meta'] and telem_time['time'] == latest_report['meta']['time']:
|
||||
return latest_report
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
from monkey_island.cc.services.attack.technique_reports.technique_service import *
|
||||
from monkey_island.cc.database import mongo
|
||||
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
TECHNIQUE = "T1197"
|
||||
MESSAGES = {
|
||||
'unscanned': "Monkey didn't try to use any bits jobs.",
|
||||
'scanned': "Monkey tried to use bits jobs but failed.",
|
||||
'used': "Monkey successfully used bits jobs at least once in the network."
|
||||
}
|
||||
|
||||
class T1197(AttackTechnique):
|
||||
tech_id = "T1197"
|
||||
unscanned_msg = "Monkey didn't try to use any bits jobs."
|
||||
scanned_msg = "Monkey tried to use bits jobs but failed."
|
||||
used_msg = "Monkey successfully used bits jobs at least once in the network."
|
||||
|
||||
def get_report_data():
|
||||
data = get_tech_base_data(TECHNIQUE, MESSAGES)
|
||||
bits_results = mongo.db.attack_results.aggregate([{'$match': {'technique': TECHNIQUE}},
|
||||
{'$group': {'_id': {'ip_addr': '$machine.ip_addr', 'usage': '$usage'},
|
||||
'ip_addr': {'$first': '$machine.ip_addr'},
|
||||
'domain_name': {'$first': '$machine.domain_name'},
|
||||
'usage': {'$first': '$usage'},
|
||||
'time': {'$first': '$time'}}
|
||||
}])
|
||||
bits_results = list(bits_results)
|
||||
data.update({'bits_jobs': bits_results})
|
||||
return data
|
||||
@staticmethod
|
||||
def get_report_data():
|
||||
data = T1197.get_tech_base_data(T1197)
|
||||
bits_results = mongo.db.attack_results.aggregate([{'$match': {'technique': T1197.tech_id}},
|
||||
{'$group': {'_id': {'ip_addr': '$machine.ip_addr', 'usage': '$usage'},
|
||||
'ip_addr': {'$first': '$machine.ip_addr'},
|
||||
'domain_name': {'$first': '$machine.domain_name'},
|
||||
'usage': {'$first': '$usage'},
|
||||
'time': {'$first': '$time'}}
|
||||
}])
|
||||
bits_results = list(bits_results)
|
||||
data.update({'bits_jobs': bits_results})
|
||||
return data
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from monkey_island.cc.services.attack.technique_reports.technique_service import *
|
||||
from common.utils.attack_utils import ScanStatus
|
||||
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
|
||||
from monkey_island.cc.database import mongo
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
|
@ -11,35 +12,43 @@ MESSAGES = {
|
|||
}
|
||||
|
||||
|
||||
def get_report_data():
|
||||
data = {'title': technique_title(TECHNIQUE)}
|
||||
scanned_services = get_scanned_services()
|
||||
exploited_services = get_exploited_services()
|
||||
if exploited_services:
|
||||
data.update({'status': ScanStatus.USED.name, 'message': MESSAGES['used']})
|
||||
elif scanned_services:
|
||||
data.update({'status': ScanStatus.SCANNED.name, 'message': MESSAGES['scanned']})
|
||||
else:
|
||||
data.update({'status': ScanStatus.UNSCANNED.name, 'message': MESSAGES['unscanned']})
|
||||
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
|
||||
return data
|
||||
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."
|
||||
used_msg = "Monkey scanned for remote services and exploited some on the network."
|
||||
|
||||
def get_scanned_services():
|
||||
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'scan'}},
|
||||
{'$sort': {'data.service_count': -1}},
|
||||
{'$group': {
|
||||
'_id': {'ip_addr': '$data.machine.ip_addr'},
|
||||
'machine': {'$first': '$data.machine'},
|
||||
'time': {'$first': '$timestamp'}}}])
|
||||
return list(results)
|
||||
@staticmethod
|
||||
def get_report_data():
|
||||
data = {'title': T1210.technique_title(TECHNIQUE)}
|
||||
scanned_services = T1210.get_scanned_services()
|
||||
exploited_services = T1210.get_exploited_services()
|
||||
if exploited_services:
|
||||
data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg})
|
||||
elif scanned_services:
|
||||
data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg})
|
||||
else:
|
||||
data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg})
|
||||
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def get_scanned_services():
|
||||
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'scan'}},
|
||||
{'$sort': {'data.service_count': -1}},
|
||||
{'$group': {
|
||||
'_id': {'ip_addr': '$data.machine.ip_addr'},
|
||||
'machine': {'$first': '$data.machine'},
|
||||
'time': {'$first': '$timestamp'}}}])
|
||||
return list(results)
|
||||
|
||||
def get_exploited_services():
|
||||
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'exploit', 'data.result': True}},
|
||||
{'$group': {
|
||||
'_id': {'ip_addr': '$data.machine.ip_addr'},
|
||||
'service': {'$first': '$data.info'},
|
||||
'machine': {'$first': '$data.machine'},
|
||||
'time': {'$first': '$timestamp'}}}])
|
||||
return list(results)
|
||||
@staticmethod
|
||||
def get_exploited_services():
|
||||
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'exploit', 'data.result': True}},
|
||||
{'$group': {
|
||||
'_id': {'ip_addr': '$data.machine.ip_addr'},
|
||||
'service': {'$first': '$data.info'},
|
||||
'machine': {'$first': '$data.machine'},
|
||||
'time': {'$first': '$timestamp'}}}])
|
||||
return list(results)
|
||||
|
|
|
@ -1 +1,63 @@
|
|||
__author__ = 'VakarisZ'
|
||||
import abc
|
||||
|
||||
from monkey_island.cc.database import mongo
|
||||
from common.utils.attack_utils import ScanStatus
|
||||
from monkey_island.cc.services.attack.attack_config import AttackConfig
|
||||
from common.utils.code_utils import abstractstatic
|
||||
|
||||
|
||||
class AttackTechnique(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractproperty
|
||||
def unscanned_msg(self):
|
||||
pass
|
||||
|
||||
@abc.abstractproperty
|
||||
def scanned_msg(self):
|
||||
pass
|
||||
|
||||
@abc.abstractproperty
|
||||
def used_msg(self):
|
||||
pass
|
||||
|
||||
@abc.abstractproperty
|
||||
def tech_id(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@abstractstatic
|
||||
def get_report_data():
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def technique_status(technique):
|
||||
"""
|
||||
Gets status of certain attack technique. If
|
||||
:param technique:
|
||||
:return:
|
||||
"""
|
||||
if mongo.db.attack_results.find_one({'status': ScanStatus.USED.value, 'technique': technique}):
|
||||
return ScanStatus.USED
|
||||
elif mongo.db.attack_results.find_one({'status': ScanStatus.SCANNED.value, 'technique': technique}):
|
||||
return ScanStatus.SCANNED
|
||||
else:
|
||||
return ScanStatus.UNSCANNED
|
||||
|
||||
@staticmethod
|
||||
def technique_title(technique):
|
||||
return AttackConfig.get_technique(technique)['title']
|
||||
|
||||
@staticmethod
|
||||
def get_tech_base_data(technique):
|
||||
data = {}
|
||||
status = AttackTechnique.technique_status(technique.tech_id)
|
||||
title = AttackTechnique.technique_title(technique.tech_id)
|
||||
data.update({'status': status.name, 'title': title})
|
||||
if status == ScanStatus.UNSCANNED:
|
||||
data.update({'message': technique.unscanned_msg})
|
||||
elif status == ScanStatus.SCANNED:
|
||||
data.update({'message': technique.scanned_msg})
|
||||
else:
|
||||
data.update({'message': technique.used_msg})
|
||||
return data
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
from monkey_island.cc.database import mongo
|
||||
from common.utils.attack_utils import ScanStatus
|
||||
from monkey_island.cc.services.attack.attack_config import get_technique
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
||||
|
||||
def technique_status(technique):
|
||||
"""
|
||||
Gets status of certain attack technique. If
|
||||
:param technique:
|
||||
:return:
|
||||
"""
|
||||
if mongo.db.attack_results.find_one({'status': ScanStatus.USED.value, 'technique': technique}):
|
||||
return ScanStatus.USED
|
||||
elif mongo.db.attack_results.find_one({'status': ScanStatus.SCANNED.value, 'technique': technique}):
|
||||
return ScanStatus.SCANNED
|
||||
else:
|
||||
return ScanStatus.UNSCANNED
|
||||
|
||||
|
||||
def technique_title(technique):
|
||||
return get_technique(technique)['title']
|
||||
|
||||
|
||||
def get_tech_base_data(technique, messages):
|
||||
data = {}
|
||||
status = technique_status(technique)
|
||||
title = technique_title(technique)
|
||||
data.update({'status': status.name, 'title': title})
|
||||
if status == ScanStatus.UNSCANNED:
|
||||
data.update({'message': messages['unscanned']})
|
||||
elif status == ScanStatus.SCANNED:
|
||||
data.update({'message': messages['scanned']})
|
||||
else:
|
||||
data.update({'message': messages['used']})
|
||||
return data
|
|
@ -14,7 +14,6 @@ import ReportPage from 'components/pages/ReportPage';
|
|||
import LicensePage from 'components/pages/LicensePage';
|
||||
import AuthComponent from 'components/AuthComponent';
|
||||
import LoginPageComponent from 'components/pages/LoginPage';
|
||||
import AttackReportPage from 'components/pages/AttackReportPage';
|
||||
|
||||
import 'normalize.css/normalize.css';
|
||||
import 'react-data-components/css/table-twbs.css';
|
||||
|
@ -85,7 +84,6 @@ class AppComponent extends AuthComponent {
|
|||
run_monkey: false,
|
||||
infection_done: false,
|
||||
report_done: false,
|
||||
attack_report_done:false,
|
||||
isLoggedIn: undefined
|
||||
}
|
||||
};
|
||||
|
@ -153,15 +151,6 @@ class AppComponent extends AuthComponent {
|
|||
: ''}
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink to="/attack_report">
|
||||
<span className="number">5.</span>
|
||||
ATT&CK report
|
||||
{this.state.completedSteps.attack_report_done ?
|
||||
<Icon name="check" className="pull-right checkmark text-success"/>
|
||||
: ''}
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink to="/start-over">
|
||||
<span className="number"><i className="fa fa-undo" style={{'marginLeft': '-1px'}}/></span>
|
||||
|
@ -196,7 +185,6 @@ class AppComponent extends AuthComponent {
|
|||
{this.renderRoute('/infection/telemetry', <TelemetryPage onStatusChange={this.updateStatus}/>)}
|
||||
{this.renderRoute('/start-over', <StartOverPage onStatusChange={this.updateStatus}/>)}
|
||||
{this.renderRoute('/report', <ReportPage onStatusChange={this.updateStatus}/>)}
|
||||
{this.renderRoute('/attack_report', <AttackReportPage onStatusChange={this.updateStatus}/>)}
|
||||
{this.renderRoute('/license', <LicensePage onStatusChange={this.updateStatus}/>)}
|
||||
</Col>
|
||||
</Row>
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
import React from 'react';
|
||||
import '../../styles/Collapse.scss'
|
||||
import ReactTable from "react-table";
|
||||
|
||||
let renderMachine = function (val) {
|
||||
return (
|
||||
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
|
||||
)
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
columns: [
|
||||
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x), style: { 'whiteSpace': 'unset' }, width: 200},
|
||||
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
|
||||
{Header: 'Usage', id: 'usage', accessor: x => x.usage, style: { 'whiteSpace': 'unset' }}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
class T1210 extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="data-table-container">
|
||||
<div>
|
||||
<div>{this.props.data.message}</div>
|
||||
{this.props.data.bits_jobs.length > 0 ? <div>BITS jobs were used in these machines: </div> : ''}
|
||||
</div>
|
||||
<br/>
|
||||
<ReactTable
|
||||
columns={columns}
|
||||
data={this.props.data.bits_jobs}
|
||||
showPagination={false}
|
||||
defaultPageSize={this.props.data.bits_jobs.length}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default T1210;
|
|
@ -0,0 +1,49 @@
|
|||
import React from 'react';
|
||||
import '../../../styles/Collapse.scss'
|
||||
import ReactTable from "react-table";
|
||||
|
||||
|
||||
class T1210 extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.columns = [ {Header: 'Machine',
|
||||
id: 'machine', accessor: x => T1210.renderMachine(x),
|
||||
style: { 'whiteSpace': 'unset' },
|
||||
width: 200},
|
||||
{Header: 'Time',
|
||||
id: 'time', accessor: x => x.time,
|
||||
style: { 'whiteSpace': 'unset' },
|
||||
width: 170},
|
||||
{Header: 'Usage',
|
||||
id: 'usage', accessor: x => x.usage,
|
||||
style: { 'whiteSpace': 'unset' }}
|
||||
]
|
||||
}
|
||||
|
||||
static renderMachine = (val) => {
|
||||
return (
|
||||
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
|
||||
)
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="data-table-container">
|
||||
<div>
|
||||
<div>{this.props.data.message}</div>
|
||||
{this.props.data.bits_jobs.length > 0 ? <div>BITS jobs were used in these machines: </div> : ''}
|
||||
</div>
|
||||
<br/>
|
||||
<ReactTable
|
||||
columns={this.columns}
|
||||
data={this.props.data.bits_jobs}
|
||||
showPagination={false}
|
||||
defaultPageSize={this.props.data.bits_jobs.length}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default T1210;
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import '../../styles/Collapse.scss'
|
||||
import '../../../styles/Collapse.scss'
|
||||
import {Link} from "react-router-dom";
|
||||
import ReactTable from "react-table";
|
||||
|
|
@ -11,6 +11,7 @@ import {Line} from 'rc-progress';
|
|||
import AuthComponent from '../AuthComponent';
|
||||
import PassTheHashMapPageComponent from "./PassTheHashMapPage";
|
||||
import StrongUsers from "components/report-components/StrongUsers";
|
||||
import AttackReport from "components/report-components/AttackReport";
|
||||
|
||||
let guardicoreLogoImage = require('../../images/guardicore-logo.png');
|
||||
let monkeyLogoImage = require('../../images/monkey-icon.svg');
|
||||
|
@ -140,6 +141,7 @@ class ReportPageComponent extends AuthComponent {
|
|||
{this.generateReportFindingsSection()}
|
||||
{this.generateReportRecommendationsSection()}
|
||||
{this.generateReportGlanceSection()}
|
||||
{this.generateAttackSection()}
|
||||
{this.generateReportFooter()}
|
||||
</div>
|
||||
<div className="text-center no-print" style={{marginTop: '20px'}}>
|
||||
|
@ -503,6 +505,21 @@ class ReportPageComponent extends AuthComponent {
|
|||
);
|
||||
}
|
||||
|
||||
generateAttackSection() {
|
||||
return (<div id="attack">
|
||||
<h3>
|
||||
ATT&CK report
|
||||
</h3>
|
||||
<p>
|
||||
This report shows information about ATT&CK techniques used by Infection Monkey.
|
||||
</p>
|
||||
<div>
|
||||
<AttackReport/>
|
||||
</div>
|
||||
<br />
|
||||
</div>)
|
||||
}
|
||||
|
||||
generateReportFooter() {
|
||||
return (
|
||||
<div id="footer" className="text-center" style={{marginTop: '20px'}}>
|
||||
|
|
|
@ -4,8 +4,8 @@ import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
|
|||
import {edgeGroupToColor, options} from 'components/map/MapOptions';
|
||||
import AuthComponent from '../AuthComponent';
|
||||
import Collapse from '@kunukn/react-collapse';
|
||||
import T1210 from '../attack/T1210';
|
||||
import T1197 from '../attack/T1197';
|
||||
import T1210 from '../attack/techniques/T1210';
|
||||
import T1197 from '../attack/techniques/T1197';
|
||||
import '../../styles/Collapse.scss'
|
||||
|
||||
const tech_components = {
|
||||
|
@ -146,14 +146,7 @@ class AttackReportPageComponent extends AuthComponent {
|
|||
} else {
|
||||
content = this.generateReportContent();
|
||||
}
|
||||
return (
|
||||
<Col xs={12} lg={8}>
|
||||
<h1 className="page-title no-print">5. ATT&CK Report</h1>
|
||||
<div style={{'fontSize': '1.2em'}}>
|
||||
{content}
|
||||
</div>
|
||||
</Col>
|
||||
);
|
||||
return ( <div> {content} </div> );
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue