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(
|
LOG.info(
|
||||||
"Shares triggered successfully on host %s: %s" % (
|
"Shares triggered successfully on host %s: %s" % (
|
||||||
self.host.ip_addr, str(successfully_triggered_shares)))
|
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
|
return True
|
||||||
else:
|
else:
|
||||||
LOG.info("No shares triggered successfully on host %s" % self.host.ip_addr)
|
LOG.info("No shares triggered successfully on host %s" % self.host.ip_addr)
|
||||||
|
|
|
@ -18,19 +18,10 @@ class HostFinger(object):
|
||||||
def _SCANNED_SERVICE(self):
|
def _SCANNED_SERVICE(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def init_service(self, services, service_key):
|
def init_service(self, services, service_key, port):
|
||||||
services[service_key] = {}
|
services[service_key] = {}
|
||||||
services[service_key]['display_name'] = self._SCANNED_SERVICE
|
services[service_key]['display_name'] = self._SCANNED_SERVICE
|
||||||
|
services[service_key]['port'] = port
|
||||||
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
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_host_fingerprint(self, host):
|
def get_host_fingerprint(self, host):
|
||||||
|
|
|
@ -36,11 +36,10 @@ class ElasticFinger(HostFinger):
|
||||||
url = 'http://%s:%s/' % (host.ip_addr, ES_PORT)
|
url = 'http://%s:%s/' % (host.ip_addr, ES_PORT)
|
||||||
with closing(requests.get(url, timeout=ES_HTTP_TIMEOUT)) as req:
|
with closing(requests.get(url, timeout=ES_HTTP_TIMEOUT)) as req:
|
||||||
data = json.loads(req.text)
|
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]['cluster_name'] = data['cluster_name']
|
||||||
host.services[ES_SERVICE]['name'] = data['name']
|
host.services[ES_SERVICE]['name'] = data['name']
|
||||||
host.services[ES_SERVICE]['version'] = data['version']['number']
|
host.services[ES_SERVICE]['version'] = data['version']['number']
|
||||||
self.add_found_port(host.services, ES_PORT)
|
|
||||||
return True
|
return True
|
||||||
except Timeout:
|
except Timeout:
|
||||||
LOG.debug("Got timeout while trying to read header information")
|
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:
|
with closing(head(url, verify=False, timeout=1)) as req:
|
||||||
server = req.headers.get('Server')
|
server = req.headers.get('Server')
|
||||||
ssl = True if 'https://' in url else False
|
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'
|
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)
|
host.services['tcp-' + port[1]]['data'] = (server,ssl)
|
||||||
LOG.info("Port %d is open on host %s " % (port[0], host))
|
LOG.info("Port %d is open on host %s " % (port[0], host))
|
||||||
break # https will be the same on the same port
|
break # https will be the same on the same port
|
||||||
|
|
|
@ -63,7 +63,7 @@ class MSSQLFinger(HostFinger):
|
||||||
sock.close()
|
sock.close()
|
||||||
return False
|
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
|
# Loop through the server data
|
||||||
instances_list = data[3:].decode().split(';;')
|
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 instance's info is nested under its own name, if there are multiple instances
|
||||||
# each will appear under its own name
|
# each will appear under its own name
|
||||||
host.services[self._SCANNED_SERVICE][instance_info[1]][instance_info[i - 1]] = instance_info[i]
|
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
|
# Close the socket
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
|
|
|
@ -51,14 +51,13 @@ class MySQLFinger(HostFinger):
|
||||||
|
|
||||||
version, curpos = struct_unpack_tracker_string(data, curpos) # special coded to solve string parsing
|
version, curpos = struct_unpack_tracker_string(data, curpos) # special coded to solve string parsing
|
||||||
version = version[0]
|
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
|
host.services[SQL_SERVICE]['version'] = version
|
||||||
version = version.split('-')[0].split('.')
|
version = version.split('-')[0].split('.')
|
||||||
host.services[SQL_SERVICE]['major_version'] = version[0]
|
host.services[SQL_SERVICE]['major_version'] = version[0]
|
||||||
host.services[SQL_SERVICE]['minor_version'] = version[1]
|
host.services[SQL_SERVICE]['minor_version'] = version[1]
|
||||||
host.services[SQL_SERVICE]['build_version'] = version[2]
|
host.services[SQL_SERVICE]['build_version'] = version[2]
|
||||||
thread_id, curpos = struct_unpack_tracker(data, curpos, "<I") # ignore thread id
|
thread_id, curpos = struct_unpack_tracker(data, curpos, "<I") # ignore thread id
|
||||||
self.add_found_port(host.services, MYSQL_PORT)
|
|
||||||
# protocol parsing taken from
|
# protocol parsing taken from
|
||||||
# https://nmap.org/nsedoc/scripts/mysql-info.html
|
# https://nmap.org/nsedoc/scripts/mysql-info.html
|
||||||
if protocol == 10:
|
if protocol == 10:
|
||||||
|
|
|
@ -114,7 +114,7 @@ class SMBFinger(HostFinger):
|
||||||
s.settimeout(0.7)
|
s.settimeout(0.7)
|
||||||
s.connect((host.ip_addr, SMB_PORT))
|
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")
|
h = SMBHeader(cmd="\x72", flag1="\x18", flag2="\x53\xc8")
|
||||||
n = SMBNego(data=SMBNegoFingerData())
|
n = SMBNego(data=SMBNegoFingerData())
|
||||||
|
@ -152,7 +152,6 @@ class SMBFinger(HostFinger):
|
||||||
host.os['version'] = os_version
|
host.os['version'] = os_version
|
||||||
else:
|
else:
|
||||||
host.services[SMB_SERVICE]['os-version'] = os_version
|
host.services[SMB_SERVICE]['os-version'] = os_version
|
||||||
self.add_found_port(host.services, SMB_PORT)
|
|
||||||
return True
|
return True
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.debug("Error getting smb fingerprint: %s", 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)
|
is_open, banner = check_tcp_port(host.ip_addr, SSH_PORT, TIMEOUT, True)
|
||||||
|
|
||||||
if is_open:
|
if is_open:
|
||||||
self.init_service(host.services, SSH_SERVICE_DEFAULT)
|
self.init_service(host.services, SSH_SERVICE_DEFAULT, SSH_PORT)
|
||||||
|
|
||||||
if banner:
|
if banner:
|
||||||
host.services[SSH_SERVICE_DEFAULT]['banner'] = banner
|
host.services[SSH_SERVICE_DEFAULT]['banner'] = banner
|
||||||
if self._banner_regex.search(banner):
|
if self._banner_regex.search(banner):
|
||||||
self._banner_match(SSH_SERVICE_DEFAULT, host, banner)
|
self._banner_match(SSH_SERVICE_DEFAULT, host, banner)
|
||||||
self.add_found_port(host.services, SSH_PORT)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -4,8 +4,6 @@ from random import shuffle
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
from infection_monkey.network import HostScanner, HostFinger
|
from infection_monkey.network import HostScanner, HostFinger
|
||||||
from infection_monkey.network.tools import check_tcp_ports, tcp_port_to_service
|
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'
|
__author__ = 'itamar'
|
||||||
|
|
||||||
|
@ -38,8 +36,7 @@ class TcpScanner(HostScanner, HostFinger):
|
||||||
self._config.tcp_scan_get_banner)
|
self._config.tcp_scan_get_banner)
|
||||||
for target_port, banner in izip_longest(ports, banners, fillvalue=None):
|
for target_port, banner in izip_longest(ports, banners, fillvalue=None):
|
||||||
service = tcp_port_to_service(target_port)
|
service = tcp_port_to_service(target_port)
|
||||||
self.init_service(host.services, service)
|
self.init_service(host.services, service, target_port)
|
||||||
self.add_found_port(host.services, target_port, key=service)
|
|
||||||
if banner:
|
if banner:
|
||||||
host.services[service]['banner'] = banner
|
host.services[service]['banner'] = banner
|
||||||
if only_one_port:
|
if only_one_port:
|
||||||
|
|
|
@ -56,12 +56,10 @@ class Root(flask_restful.Resource):
|
||||||
infection_done = NodeService.is_monkey_finished_running()
|
infection_done = NodeService.is_monkey_finished_running()
|
||||||
if not infection_done:
|
if not infection_done:
|
||||||
report_done = False
|
report_done = False
|
||||||
attack_report_done = False
|
|
||||||
else:
|
else:
|
||||||
if is_any_exists:
|
if is_any_exists:
|
||||||
ReportService.get_report()
|
ReportService.get_report()
|
||||||
AttackReportService.get_latest_report()
|
AttackReportService.get_latest_report()
|
||||||
report_done = ReportService.is_report_generated()
|
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,
|
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
|
Gets technique by id
|
||||||
:param technique_id: E.g. T1210
|
: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, attack_type in attack_config['properties'].items():
|
||||||
for key, technique in attack_type['properties'].items():
|
for key, technique in attack_type['properties'].items():
|
||||||
if key == technique_id:
|
if key == technique_id:
|
||||||
return technique
|
return technique
|
||||||
return False
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_config_schema():
|
def get_config_schema():
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
from monkey_island.cc.services.attack.technique_reports import T1210, T1197
|
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_telem import AttackTelemService
|
||||||
from monkey_island.cc.services.attack.attack_config import get_technique_values
|
from monkey_island.cc.services.attack.attack_config import AttackConfig
|
||||||
from monkey_island.cc.database import mongo
|
from monkey_island.cc.database import mongo
|
||||||
|
|
||||||
__author__ = "VakarisZ"
|
__author__ = "VakarisZ"
|
||||||
|
@ -9,8 +9,8 @@ __author__ = "VakarisZ"
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
TECHNIQUES = {'T1210': T1210,
|
TECHNIQUES = {'T1210': T1210.T1210,
|
||||||
'T1197': T1197}
|
'T1197': T1197.T1197}
|
||||||
|
|
||||||
REPORT_NAME = 'new_report'
|
REPORT_NAME = 'new_report'
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ class AttackReportService:
|
||||||
Generates new report based on telemetries, replaces old report in db with new one.
|
Generates new report based on telemetries, replaces old report in db with new one.
|
||||||
:return: Report object
|
:return: Report object
|
||||||
"""
|
"""
|
||||||
report = {'techniques': {}, 'meta': get_latest_telem(), 'name': REPORT_NAME}
|
report = {'techniques': {}, 'meta': AttackTelemService.get_latest_telem(), 'name': REPORT_NAME}
|
||||||
for tech_id, value in get_technique_values().items():
|
for tech_id, value in AttackConfig.get_technique_values().items():
|
||||||
if value:
|
if value:
|
||||||
try:
|
try:
|
||||||
report['techniques'].update({tech_id: TECHNIQUES[tech_id].get_report_data()})
|
report['techniques'].update({tech_id: TECHNIQUES[tech_id].get_report_data()})
|
||||||
|
@ -43,7 +43,7 @@ class AttackReportService:
|
||||||
:return: report dict.
|
:return: report dict.
|
||||||
"""
|
"""
|
||||||
if AttackReportService.is_report_generated():
|
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})
|
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']:
|
if telem_time and latest_report['meta'] and telem_time['time'] == latest_report['meta']['time']:
|
||||||
return latest_report
|
return latest_report
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
from monkey_island.cc.services.attack.technique_reports.technique_service import *
|
|
||||||
from monkey_island.cc.database import mongo
|
from monkey_island.cc.database import mongo
|
||||||
|
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
|
||||||
|
|
||||||
__author__ = "VakarisZ"
|
__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():
|
@staticmethod
|
||||||
data = get_tech_base_data(TECHNIQUE, MESSAGES)
|
def get_report_data():
|
||||||
bits_results = mongo.db.attack_results.aggregate([{'$match': {'technique': TECHNIQUE}},
|
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'},
|
{'$group': {'_id': {'ip_addr': '$machine.ip_addr', 'usage': '$usage'},
|
||||||
'ip_addr': {'$first': '$machine.ip_addr'},
|
'ip_addr': {'$first': '$machine.ip_addr'},
|
||||||
'domain_name': {'$first': '$machine.domain_name'},
|
'domain_name': {'$first': '$machine.domain_name'},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from monkey_island.cc.services.attack.technique_reports.technique_service import *
|
|
||||||
from common.utils.attack_utils import ScanStatus
|
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"
|
__author__ = "VakarisZ"
|
||||||
|
|
||||||
|
@ -11,21 +12,29 @@ MESSAGES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_report_data():
|
class T1210(AttackTechnique):
|
||||||
data = {'title': technique_title(TECHNIQUE)}
|
|
||||||
scanned_services = get_scanned_services()
|
tech_id = "T1210"
|
||||||
exploited_services = get_exploited_services()
|
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."
|
||||||
|
|
||||||
|
@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:
|
if exploited_services:
|
||||||
data.update({'status': ScanStatus.USED.name, 'message': MESSAGES['used']})
|
data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg})
|
||||||
elif scanned_services:
|
elif scanned_services:
|
||||||
data.update({'status': ScanStatus.SCANNED.name, 'message': MESSAGES['scanned']})
|
data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg})
|
||||||
else:
|
else:
|
||||||
data.update({'status': ScanStatus.UNSCANNED.name, 'message': MESSAGES['unscanned']})
|
data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg})
|
||||||
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
|
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def get_scanned_services():
|
def get_scanned_services():
|
||||||
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'scan'}},
|
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'scan'}},
|
||||||
{'$sort': {'data.service_count': -1}},
|
{'$sort': {'data.service_count': -1}},
|
||||||
{'$group': {
|
{'$group': {
|
||||||
|
@ -34,8 +43,8 @@ def get_scanned_services():
|
||||||
'time': {'$first': '$timestamp'}}}])
|
'time': {'$first': '$timestamp'}}}])
|
||||||
return list(results)
|
return list(results)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def get_exploited_services():
|
def get_exploited_services():
|
||||||
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'exploit', 'data.result': True}},
|
results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'exploit', 'data.result': True}},
|
||||||
{'$group': {
|
{'$group': {
|
||||||
'_id': {'ip_addr': '$data.machine.ip_addr'},
|
'_id': {'ip_addr': '$data.machine.ip_addr'},
|
||||||
|
|
|
@ -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 LicensePage from 'components/pages/LicensePage';
|
||||||
import AuthComponent from 'components/AuthComponent';
|
import AuthComponent from 'components/AuthComponent';
|
||||||
import LoginPageComponent from 'components/pages/LoginPage';
|
import LoginPageComponent from 'components/pages/LoginPage';
|
||||||
import AttackReportPage from 'components/pages/AttackReportPage';
|
|
||||||
|
|
||||||
import 'normalize.css/normalize.css';
|
import 'normalize.css/normalize.css';
|
||||||
import 'react-data-components/css/table-twbs.css';
|
import 'react-data-components/css/table-twbs.css';
|
||||||
|
@ -85,7 +84,6 @@ class AppComponent extends AuthComponent {
|
||||||
run_monkey: false,
|
run_monkey: false,
|
||||||
infection_done: false,
|
infection_done: false,
|
||||||
report_done: false,
|
report_done: false,
|
||||||
attack_report_done:false,
|
|
||||||
isLoggedIn: undefined
|
isLoggedIn: undefined
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -153,15 +151,6 @@ class AppComponent extends AuthComponent {
|
||||||
: ''}
|
: ''}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</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>
|
<li>
|
||||||
<NavLink to="/start-over">
|
<NavLink to="/start-over">
|
||||||
<span className="number"><i className="fa fa-undo" style={{'marginLeft': '-1px'}}/></span>
|
<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('/infection/telemetry', <TelemetryPage onStatusChange={this.updateStatus}/>)}
|
||||||
{this.renderRoute('/start-over', <StartOverPage onStatusChange={this.updateStatus}/>)}
|
{this.renderRoute('/start-over', <StartOverPage onStatusChange={this.updateStatus}/>)}
|
||||||
{this.renderRoute('/report', <ReportPage 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}/>)}
|
{this.renderRoute('/license', <LicensePage onStatusChange={this.updateStatus}/>)}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</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 React from 'react';
|
||||||
import '../../styles/Collapse.scss'
|
import '../../../styles/Collapse.scss'
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {Line} from 'rc-progress';
|
||||||
import AuthComponent from '../AuthComponent';
|
import AuthComponent from '../AuthComponent';
|
||||||
import PassTheHashMapPageComponent from "./PassTheHashMapPage";
|
import PassTheHashMapPageComponent from "./PassTheHashMapPage";
|
||||||
import StrongUsers from "components/report-components/StrongUsers";
|
import StrongUsers from "components/report-components/StrongUsers";
|
||||||
|
import AttackReport from "components/report-components/AttackReport";
|
||||||
|
|
||||||
let guardicoreLogoImage = require('../../images/guardicore-logo.png');
|
let guardicoreLogoImage = require('../../images/guardicore-logo.png');
|
||||||
let monkeyLogoImage = require('../../images/monkey-icon.svg');
|
let monkeyLogoImage = require('../../images/monkey-icon.svg');
|
||||||
|
@ -140,6 +141,7 @@ class ReportPageComponent extends AuthComponent {
|
||||||
{this.generateReportFindingsSection()}
|
{this.generateReportFindingsSection()}
|
||||||
{this.generateReportRecommendationsSection()}
|
{this.generateReportRecommendationsSection()}
|
||||||
{this.generateReportGlanceSection()}
|
{this.generateReportGlanceSection()}
|
||||||
|
{this.generateAttackSection()}
|
||||||
{this.generateReportFooter()}
|
{this.generateReportFooter()}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center no-print" style={{marginTop: '20px'}}>
|
<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() {
|
generateReportFooter() {
|
||||||
return (
|
return (
|
||||||
<div id="footer" className="text-center" style={{marginTop: '20px'}}>
|
<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 {edgeGroupToColor, options} from 'components/map/MapOptions';
|
||||||
import AuthComponent from '../AuthComponent';
|
import AuthComponent from '../AuthComponent';
|
||||||
import Collapse from '@kunukn/react-collapse';
|
import Collapse from '@kunukn/react-collapse';
|
||||||
import T1210 from '../attack/T1210';
|
import T1210 from '../attack/techniques/T1210';
|
||||||
import T1197 from '../attack/T1197';
|
import T1197 from '../attack/techniques/T1197';
|
||||||
import '../../styles/Collapse.scss'
|
import '../../styles/Collapse.scss'
|
||||||
|
|
||||||
const tech_components = {
|
const tech_components = {
|
||||||
|
@ -146,14 +146,7 @@ class AttackReportPageComponent extends AuthComponent {
|
||||||
} else {
|
} else {
|
||||||
content = this.generateReportContent();
|
content = this.generateReportContent();
|
||||||
}
|
}
|
||||||
return (
|
return ( <div> {content} </div> );
|
||||||
<Col xs={12} lg={8}>
|
|
||||||
<h1 className="page-title no-print">5. ATT&CK Report</h1>
|
|
||||||
<div style={{'fontSize': '1.2em'}}>
|
|
||||||
{content}
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue