T1210 refactored. Instead of dedicated telems, relevant info is appended to 'scan' and 'exploit' telemetries

This commit is contained in:
VakarisZ 2019-04-17 11:57:33 +03:00
parent 6fb06bc24d
commit c32d07ae34
23 changed files with 141 additions and 118 deletions

View File

@ -1,6 +1,7 @@
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
import infection_monkey.config import infection_monkey.config
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.utils import get_current_time_string
__author__ = 'itamar' __author__ = 'itamar'
@ -12,6 +13,7 @@ class HostExploiter(object):
# Usual values are 'vulnerability' or 'brute_force' # Usual values are 'vulnerability' or 'brute_force'
EXPLOIT_TYPE = ExploitType.VULNERABILITY EXPLOIT_TYPE = ExploitType.VULNERABILITY
_EXPLOITED_SERVICE = ''
def __init__(self, host): def __init__(self, host):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
@ -37,6 +39,21 @@ class HostExploiter(object):
def exploit_host(self): def exploit_host(self):
raise NotImplementedError() raise NotImplementedError()
def add_vuln_service_info(self, port=None, url=None):
if port:
service_endpoint = port
elif url:
service_endpoint = url
else:
raise NotImplementedError("You must pass either port or url to add a vulnerable service info.")
if not self._EXPLOITED_SERVICE:
raise NotImplementedError("You must override _EXPLOITED_SERVICE to name a service this exploiter "
"is targeting")
self._exploit_info['exploited_service'] = {'name': self._EXPLOITED_SERVICE,
'endpoint': service_endpoint,
'time': get_current_time_string()}
return
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

@ -29,6 +29,7 @@ class ElasticGroovyExploiter(WebRCE):
% """java.lang.Math.class.forName(\\"java.lang.Runtime\\").getRuntime().exec(\\"%s\\").getText()""" % """java.lang.Math.class.forName(\\"java.lang.Runtime\\").getRuntime().exec(\\"%s\\").getText()"""
_TARGET_OS_TYPE = ['linux', 'windows'] _TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Elastic search'
def __init__(self, host): def __init__(self, host):
super(ElasticGroovyExploiter, self).__init__(host) super(ElasticGroovyExploiter, self).__init__(host)
@ -58,8 +59,7 @@ class ElasticGroovyExploiter(WebRCE):
result = self.get_results(response) result = self.get_results(response)
if not result: if not result:
return False return False
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(url=url)
self.host, {'url': url, 'service': 'Elastic search'}).send()
return result[0] return result[0]
def upload_monkey(self, url, commands=None): def upload_monkey(self, url, commands=None):

View File

@ -13,8 +13,6 @@ import posixpath
from infection_monkey.exploit.web_rce import WebRCE from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.exploit.tools import HTTPTools, build_monkey_commandline, get_monkey_depth from infection_monkey.exploit.tools import HTTPTools, build_monkey_commandline, get_monkey_depth
from infection_monkey.model import MONKEY_ARG, ID_STRING, HADOOP_WINDOWS_COMMAND, HADOOP_LINUX_COMMAND from infection_monkey.model import MONKEY_ARG, ID_STRING, HADOOP_WINDOWS_COMMAND, HADOOP_LINUX_COMMAND
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
__author__ = 'VakarisZ' __author__ = 'VakarisZ'
@ -23,6 +21,7 @@ LOG = logging.getLogger(__name__)
class HadoopExploiter(WebRCE): class HadoopExploiter(WebRCE):
_TARGET_OS_TYPE = ['linux', 'windows'] _TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Hadoop'
HADOOP_PORTS = [["8088", False]] HADOOP_PORTS = [["8088", False]]
# How long we have our http server open for downloads in seconds # How long we have our http server open for downloads in seconds
DOWNLOAD_TIMEOUT = 60 DOWNLOAD_TIMEOUT = 60
@ -50,8 +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()
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(url=self.vulnerable_urls[0])
self.host, {'url': self.vulnerable_urls[0], 'service': 'Hadoop'}).send()
return True return True
def exploit(self, url, command): def exploit(self, url, command):

View File

@ -239,6 +239,7 @@ class RdpExploiter(HostExploiter):
_TARGET_OS_TYPE = ['windows'] _TARGET_OS_TYPE = ['windows']
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
_EXPLOITED_SERVICE = 'RDP'
def __init__(self, host): def __init__(self, host):
super(RdpExploiter, self).__init__(host) super(RdpExploiter, self).__init__(host)
@ -316,6 +317,7 @@ class RdpExploiter(HostExploiter):
if client_factory.success: if client_factory.success:
if not self._config.rdp_use_vbs_download: if not self._config.rdp_use_vbs_download:
VictimHostTelem("T1197", ScanStatus.USED.value, self.host, BITS_UPLOAD_STRING) VictimHostTelem("T1197", ScanStatus.USED.value, self.host, BITS_UPLOAD_STRING)
self.add_vuln_service_info(port=RDP_PORT)
exploited = True exploited = True
self.report_login_attempt(True, user, password) self.report_login_attempt(True, user, password)
break break

View File

@ -21,8 +21,6 @@ from infection_monkey.model import DROPPER_ARG
from infection_monkey.network.smbfinger import SMB_SERVICE from infection_monkey.network.smbfinger import SMB_SERVICE
from infection_monkey.exploit.tools import build_monkey_commandline, get_target_monkey_by_os, get_monkey_depth from infection_monkey.exploit.tools import build_monkey_commandline, get_target_monkey_by_os, get_monkey_depth
from infection_monkey.pyinstaller_utils import get_binary_file_path from infection_monkey.pyinstaller_utils import get_binary_file_path
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'
@ -36,6 +34,7 @@ class SambaCryExploiter(HostExploiter):
""" """
_TARGET_OS_TYPE = ['linux'] _TARGET_OS_TYPE = ['linux']
_EXPLOITED_SERVICE = "Samba"
# Name of file which contains the monkey's commandline # Name of file which contains the monkey's commandline
SAMBACRY_COMMANDLINE_FILENAME = "monkey_commandline.txt" SAMBACRY_COMMANDLINE_FILENAME = "monkey_commandline.txt"
# Name of file which contains the runner's result # Name of file which contains the runner's result
@ -90,8 +89,7 @@ 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)))
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(port='139 or 445')
self.host, {'port': '139/445', 'service': 'Samba'}).send()
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)

View File

@ -11,8 +11,6 @@ from infection_monkey.exploit.tools import get_target_monkey, HTTPTools, get_mon
from infection_monkey.model import DROPPER_ARG from infection_monkey.model import DROPPER_ARG
from infection_monkey.exploit.shellshock_resources import CGI_FILES from infection_monkey.exploit.shellshock_resources import CGI_FILES
from infection_monkey.exploit.tools import build_monkey_commandline from infection_monkey.exploit.tools import build_monkey_commandline
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
__author__ = 'danielg' __author__ = 'danielg'
@ -28,6 +26,7 @@ class ShellShockExploiter(HostExploiter):
} }
_TARGET_OS_TYPE = ['linux'] _TARGET_OS_TYPE = ['linux']
_EXPLOITED_SERVICE = 'Bash'
def __init__(self, host): def __init__(self, host):
super(ShellShockExploiter, self).__init__(host) super(ShellShockExploiter, self).__init__(host)
@ -145,8 +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
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(url=url)
self.host, {'url': url, 'service': 'Bash'}).send()
return True return True
return False return False

View File

@ -10,8 +10,6 @@ from infection_monkey.network import SMBFinger
from infection_monkey.network.tools import check_tcp_port from infection_monkey.network.tools import check_tcp_port
from infection_monkey.exploit.tools import build_monkey_commandline from infection_monkey.exploit.tools import build_monkey_commandline
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
LOG = getLogger(__name__) LOG = getLogger(__name__)
@ -19,6 +17,7 @@ LOG = getLogger(__name__)
class SmbExploiter(HostExploiter): class SmbExploiter(HostExploiter):
_TARGET_OS_TYPE = ['windows'] _TARGET_OS_TYPE = ['windows']
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
_EXPLOITED_SERVICE = 'SMB'
KNOWN_PROTOCOLS = { KNOWN_PROTOCOLS = {
'139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139), '139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139),
'445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445), '445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445),
@ -70,10 +69,8 @@ class SmbExploiter(HostExploiter):
LOG.debug("Successfully logged in %r using SMB (%s : %s : %s : %s)", LOG.debug("Successfully logged in %r using SMB (%s : %s : %s : %s)",
self.host, user, password, lm_hash, ntlm_hash) self.host, user, password, lm_hash, ntlm_hash)
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash) self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
VictimHostTelem('T1210', ScanStatus.USED.value, self.host, self.add_vuln_service_info(port=("%s or %s" % (SmbExploiter.KNOWN_PROTOCOLS['139/SMB'][1],
{'port': ("%s or %s" % (SmbExploiter.KNOWN_PROTOCOLS['139/SMB'][1], SmbExploiter.KNOWN_PROTOCOLS['445/SMB'][1])))
SmbExploiter.KNOWN_PROTOCOLS['445/SMB'][1])),
'service': 'SMB'}).send()
exploited = True exploited = True
break break
else: else:
@ -143,8 +140,6 @@ class SmbExploiter(HostExploiter):
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)",
remote_full_path, self.host, cmdline) remote_full_path, self.host, cmdline)
VictimHostTelem('T1210', ScanStatus.USED.value, self.host, self.add_vuln_service_info(port=("%s or %s" % (SmbExploiter.KNOWN_PROTOCOLS['139/SMB'][1],
{'port': ("%s or %s" % (SmbExploiter.KNOWN_PROTOCOLS['139/SMB'][1], SmbExploiter.KNOWN_PROTOCOLS['445/SMB'][1])))
SmbExploiter.KNOWN_PROTOCOLS['445/SMB'][1])),
'service': 'Elastic'}).send()
return True return True

View File

@ -11,8 +11,6 @@ from infection_monkey.model import MONKEY_ARG
from infection_monkey.network.tools import check_tcp_port from infection_monkey.network.tools import check_tcp_port
from infection_monkey.exploit.tools import build_monkey_commandline from infection_monkey.exploit.tools import build_monkey_commandline
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
__author__ = 'hoffer' __author__ = 'hoffer'
@ -24,6 +22,7 @@ TRANSFER_UPDATE_RATE = 15
class SSHExploiter(HostExploiter): class SSHExploiter(HostExploiter):
_TARGET_OS_TYPE = ['linux', None] _TARGET_OS_TYPE = ['linux', None]
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
_EXPLOITED_SERVICE = 'SSH'
def __init__(self, host): def __init__(self, host):
super(SSHExploiter, self).__init__(host) super(SSHExploiter, self).__init__(host)
@ -83,12 +82,11 @@ class SSHExploiter(HostExploiter):
LOG.debug("Successfully logged in %r using SSH (%s : %s)", LOG.debug("Successfully logged in %r using SSH (%s : %s)",
self.host, user, curpass) self.host, user, curpass)
exploited = True exploited = True
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(port=port)
self.host, {'port': port, 'service': 'SSH'}).send()
self.report_login_attempt(True, user, curpass) self.report_login_attempt(True, user, curpass)
break break
except Exception as exc: except paramiko.AuthenticationException as exc:
LOG.debug("Error logging into victim %r with user" LOG.debug("Error logging into victim %r with user"
" %s and password '%s': (%s)", self.host, " %s and password '%s': (%s)", self.host,
user, curpass, exc) user, curpass, exc)

View File

@ -10,8 +10,6 @@ import re
import logging import logging
from infection_monkey.exploit.web_rce import WebRCE from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
__author__ = "VakarisZ" __author__ = "VakarisZ"
@ -22,6 +20,7 @@ DOWNLOAD_TIMEOUT = 300
class Struts2Exploiter(WebRCE): class Struts2Exploiter(WebRCE):
_TARGET_OS_TYPE = ['linux', 'windows'] _TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Struts2'
def __init__(self, host): def __init__(self, host):
super(Struts2Exploiter, self).__init__(host, None) super(Struts2Exploiter, self).__init__(host, None)
@ -93,6 +92,5 @@ class Struts2Exploiter(WebRCE):
except httplib.IncompleteRead as e: except httplib.IncompleteRead as e:
page = e.partial page = e.partial
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(url=url)
self.host, {'url': url, 'service': 'Struts2'}).send()
return page return page

View File

@ -10,8 +10,6 @@ from requests import post, exceptions
from infection_monkey.exploit.web_rce import WebRCE from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.exploit.tools import get_free_tcp_port, get_interface_to_target from infection_monkey.exploit.tools import get_free_tcp_port, get_interface_to_target
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
import threading import threading
import logging import logging
@ -46,6 +44,7 @@ HEADERS = {
class WebLogicExploiter(WebRCE): class WebLogicExploiter(WebRCE):
_TARGET_OS_TYPE = ['linux', 'windows'] _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(WebLogicExploiter, self).__init__(host, {'linux': '/tmp/monkey.sh',
@ -70,8 +69,7 @@ class WebLogicExploiter(WebRCE):
print('[!] Connection Error') print('[!] Connection Error')
print(e) print(e)
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(url=url)
self.host, {'url': url, 'service': 'Weblogic'}).send()
return True return True
def add_vulnerable_urls(self, urls, stop_checking=False): def add_vulnerable_urls(self, urls, stop_checking=False):

View File

@ -10,8 +10,6 @@ from infection_monkey.exploit.tools import SmbTools, WmiTools, AccessDeniedExcep
get_monkey_depth, build_monkey_commandline get_monkey_depth, build_monkey_commandline
from infection_monkey.model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS from infection_monkey.model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS
from common.utils.exploit_enum import ExploitType from common.utils.exploit_enum import ExploitType
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -19,6 +17,7 @@ LOG = logging.getLogger(__name__)
class WmiExploiter(HostExploiter): class WmiExploiter(HostExploiter):
_TARGET_OS_TYPE = ['windows'] _TARGET_OS_TYPE = ['windows']
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
_EXPLOITED_SERVICE = 'WMI (Windows Management Instrumentation)'
def __init__(self, host): def __init__(self, host):
super(WmiExploiter, self).__init__(host) super(WmiExploiter, self).__init__(host)
@ -106,8 +105,7 @@ class WmiExploiter(HostExploiter):
LOG.info("Executed dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)", LOG.info("Executed dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)",
remote_full_path, self.host, result.ProcessId, result.ReturnValue, cmdline) remote_full_path, self.host, result.ProcessId, result.ReturnValue, cmdline)
VictimHostTelem('T1210', ScanStatus.USED.value, self.add_vuln_service_info(port='unknown')
self.host, {'port': 'unknown', 'service': 'WMI'}).send()
success = True success = True
else: else:
LOG.debug("Error executing dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)", LOG.debug("Error executing dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)",

View File

@ -1,4 +1,5 @@
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from infection_monkey.utils import get_current_time_string
__author__ = 'itamar' __author__ = 'itamar'
@ -14,10 +15,27 @@ class HostScanner(object):
class HostFinger(object): class HostFinger(object):
__metaclass__ = ABCMeta __metaclass__ = ABCMeta
_SCANNED_SERVICE = ''
def format_service_info(self, port=None, url=None):
if port:
service_endpoint = port
elif url:
service_endpoint = url
else:
raise NotImplementedError("You must pass either port or url to get formatted service info.")
if not self._SCANNED_SERVICE:
raise NotImplementedError("You must override _SCANNED_SERVICE property"
" to name what service is being scanned.")
return {'display_name': self._SCANNED_SERVICE,
'endpoint': service_endpoint,
'time': get_current_time_string()}
@abstractmethod @abstractmethod
def get_host_fingerprint(self, host): def get_host_fingerprint(self, host):
raise NotImplementedError() raise NotImplementedError()
from infection_monkey.network.ping_scanner import PingScanner from infection_monkey.network.ping_scanner import PingScanner
from infection_monkey.network.tcp_scanner import TcpScanner from infection_monkey.network.tcp_scanner import TcpScanner
from infection_monkey.network.smbfinger import SMBFinger from infection_monkey.network.smbfinger import SMBFinger
@ -26,4 +44,4 @@ from infection_monkey.network.httpfinger import HTTPFinger
from infection_monkey.network.elasticfinger import ElasticFinger from infection_monkey.network.elasticfinger import ElasticFinger
from infection_monkey.network.mysqlfinger import MySQLFinger from infection_monkey.network.mysqlfinger import MySQLFinger
from infection_monkey.network.info import local_ips, get_free_tcp_port from infection_monkey.network.info import local_ips, get_free_tcp_port
from infection_monkey.network.mssql_fingerprint import MSSQLFinger from infection_monkey.network.mssql_fingerprint import MSSQLFinger

View File

@ -8,8 +8,6 @@ from requests.exceptions import Timeout, ConnectionError
import infection_monkey.config import infection_monkey.config
from infection_monkey.model.host import VictimHost from infection_monkey.model.host import VictimHost
from infection_monkey.network import HostFinger from infection_monkey.network import HostFinger
from common.utils.attack_utils import ScanStatus
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
ES_PORT = 9200 ES_PORT = 9200
ES_SERVICE = 'elastic-search-9200' ES_SERVICE = 'elastic-search-9200'
@ -22,6 +20,7 @@ class ElasticFinger(HostFinger):
""" """
Fingerprints elastic search clusters, only on port 9200 Fingerprints elastic search clusters, only on port 9200
""" """
_SCANNED_SERVICE = 'Elastic search'
def __init__(self): def __init__(self):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
@ -41,8 +40,7 @@ class ElasticFinger(HostFinger):
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']
VictimHostTelem('T1210', ScanStatus.SCANNED.value, host.services[ES_SERVICE].update(self.format_service_info(url=url))
host, {'port': ES_PORT, 'service': 'Elastic'}).send()
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")

View File

@ -1,8 +1,6 @@
import infection_monkey.config import infection_monkey.config
from infection_monkey.network import HostFinger from infection_monkey.network import HostFinger
from infection_monkey.model.host import VictimHost from infection_monkey.model.host import VictimHost
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
import logging import logging
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -12,6 +10,7 @@ class HTTPFinger(HostFinger):
""" """
Goal is to recognise HTTP servers, where what we currently care about is apache. Goal is to recognise HTTP servers, where what we currently care about is apache.
""" """
_SCANNED_SERVICE = 'HTTP'
def __init__(self): def __init__(self):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
@ -42,8 +41,7 @@ class HTTPFinger(HostFinger):
host.services['tcp-' + port[1]]['name'] = 'http' host.services['tcp-' + port[1]]['name'] = 'http'
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))
VictimHostTelem('T1210', ScanStatus.SCANNED.value, host.services['tcp-' + port[1]].update(self.format_service_info(port=port[0]))
host, {'port': port[0], 'service': 'HTTP/HTTPS'}).send()
break # https will be the same on the same port break # https will be the same on the same port
except Timeout: except Timeout:
pass pass

View File

@ -4,8 +4,6 @@ import socket
from infection_monkey.model.host import VictimHost from infection_monkey.model.host import VictimHost
from infection_monkey.network import HostFinger from infection_monkey.network import HostFinger
import infection_monkey.config import infection_monkey.config
from common.utils.attack_utils import ScanStatus
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
__author__ = 'Maor Rayzin' __author__ = 'Maor Rayzin'
@ -18,7 +16,7 @@ class MSSQLFinger(HostFinger):
SQL_BROWSER_DEFAULT_PORT = 1434 SQL_BROWSER_DEFAULT_PORT = 1434
BUFFER_SIZE = 4096 BUFFER_SIZE = 4096
TIMEOUT = 5 TIMEOUT = 5
SERVICE_NAME = 'MSSQL' _SCANNED_SERVICE = 'MSSQL'
def __init__(self): def __init__(self):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
@ -65,22 +63,20 @@ class MSSQLFinger(HostFinger):
sock.close() sock.close()
return False return False
host.services[self.SERVICE_NAME] = {} host.services[self._SCANNED_SERVICE] = {}
# Loop through the server data # Loop through the server data
instances_list = data[3:].decode().split(';;') instances_list = data[3:].decode().split(';;')
LOG.info('{0} MSSQL instances found'.format(len(instances_list))) LOG.info('{0} MSSQL instances found'.format(len(instances_list)))
VictimHostTelem('T1210', ScanStatus.SCANNED.value,
host, {'port': MSSQLFinger.SQL_BROWSER_DEFAULT_PORT, 'service': 'MsSQL'}).send()
for instance in instances_list: for instance in instances_list:
instance_info = instance.split(';') instance_info = instance.split(';')
if len(instance_info) > 1: if len(instance_info) > 1:
host.services[self.SERVICE_NAME][instance_info[1]] = {} host.services[self._SCANNED_SERVICE][instance_info[1]] = {}
for i in range(1, len(instance_info), 2): for i in range(1, len(instance_info), 2):
# 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.SERVICE_NAME][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]
host.services[self._SCANNED_SERVICE].update(self.format_service_info(port=MSSQLFinger.SQL_BROWSER_DEFAULT_PORT))
# Close the socket # Close the socket
sock.close() sock.close()

View File

@ -5,12 +5,9 @@ import infection_monkey.config
from infection_monkey.model.host import VictimHost from infection_monkey.model.host import VictimHost
from infection_monkey.network import HostFinger from infection_monkey.network import HostFinger
from infection_monkey.network.tools import struct_unpack_tracker, struct_unpack_tracker_string from infection_monkey.network.tools import struct_unpack_tracker, struct_unpack_tracker_string
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
MYSQL_PORT = 3306 MYSQL_PORT = 3306
SQL_SERVICE = 'mysqld-3306' SQL_SERVICE = 'mysqld-3306'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -18,7 +15,7 @@ class MySQLFinger(HostFinger):
""" """
Fingerprints mysql databases, only on port 3306 Fingerprints mysql databases, only on port 3306
""" """
_SCANNED_SERVICE = 'MySQL'
SOCKET_TIMEOUT = 0.5 SOCKET_TIMEOUT = 0.5
HEADER_SIZE = 4 # in bytes HEADER_SIZE = 4 # in bytes
@ -61,8 +58,7 @@ class MySQLFinger(HostFinger):
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
VictimHostTelem('T1210', ScanStatus.SCANNED.value, host.services[SQL_SERVICE].update(self.format_service_info(port=MYSQL_PORT))
host, {'port': MYSQL_PORT, 'service': 'MYSQL'}).send()
# 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:

View File

@ -5,8 +5,6 @@ from odict import odict
from infection_monkey.network import HostFinger from infection_monkey.network import HostFinger
from infection_monkey.model.host import VictimHost from infection_monkey.model.host import VictimHost
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
SMB_PORT = 445 SMB_PORT = 445
SMB_SERVICE = 'tcp-445' SMB_SERVICE = 'tcp-445'
@ -102,6 +100,8 @@ class SMBSessionFingerData(Packet):
class SMBFinger(HostFinger): class SMBFinger(HostFinger):
_SCANNED_SERVICE = 'SMB'
def __init__(self): def __init__(self):
from infection_monkey.config import WormConfiguration from infection_monkey.config import WormConfiguration
self._config = WormConfiguration self._config = WormConfiguration
@ -152,8 +152,7 @@ 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
VictimHostTelem('T1210', ScanStatus.SCANNED.value, host.services[SMB_SERVICE].update(self.format_service_info(port=SMB_PORT))
host, {'port': SMB_PORT, 'service': 'SMB'}).send()
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)

View File

@ -4,8 +4,6 @@ import infection_monkey.config
from infection_monkey.model.host import VictimHost from infection_monkey.model.host import VictimHost
from infection_monkey.network import HostFinger from infection_monkey.network import HostFinger
from infection_monkey.network.tools import check_tcp_port from infection_monkey.network.tools import check_tcp_port
from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem
from common.utils.attack_utils import ScanStatus
SSH_PORT = 22 SSH_PORT = 22
SSH_SERVICE_DEFAULT = 'tcp-22' SSH_SERVICE_DEFAULT = 'tcp-22'
@ -16,6 +14,8 @@ LINUX_DIST_SSH = ['ubuntu', 'debian']
class SSHFinger(HostFinger): class SSHFinger(HostFinger):
_SCANNED_SERVICE = 'SSH'
def __init__(self): def __init__(self):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
self._banner_regex = re.compile(SSH_REGEX, re.IGNORECASE) self._banner_regex = re.compile(SSH_REGEX, re.IGNORECASE)
@ -51,8 +51,7 @@ class SSHFinger(HostFinger):
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)
VictimHostTelem('T1210', ScanStatus.SCANNED.value, host.services[SSH_SERVICE_DEFAULT].update(self.format_service_info(port=SSH_PORT))
host, {'port': SSH_PORT, 'service': 'SSH'}).send()
return True return True
return False return False

View File

@ -13,6 +13,9 @@ BANNER_READ = 1024
class TcpScanner(HostScanner, HostFinger): class TcpScanner(HostScanner, HostFinger):
_SCANNED_SERVICE = 'unknown(TCP)'
def __init__(self): def __init__(self):
self._config = infection_monkey.config.WormConfiguration self._config = infection_monkey.config.WormConfiguration
@ -33,12 +36,10 @@ class TcpScanner(HostScanner, HostFinger):
ports, banners = check_tcp_ports(host.ip_addr, target_ports, self._config.tcp_scan_timeout / 1000.0, ports, banners = check_tcp_ports(host.ip_addr, target_ports, self._config.tcp_scan_timeout / 1000.0,
self._config.tcp_scan_get_banner) self._config.tcp_scan_get_banner)
for port in ports:
VictimHostTelem('T1210', ScanStatus.SCANNED.value,
host, {'port': port, 'service': 'unknown(TCP)'}).send()
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)
host.services[service] = {} host.services[service] = {}
host.services[service].update(self.format_service_info(port=target_port))
if banner: if banner:
host.services[service]['banner'] = banner host.services[service]['banner'] = banner
if only_one_port: if only_one_port:

View File

@ -3,7 +3,7 @@ import requests
import json import json
from infection_monkey.control import ControlClient from infection_monkey.control import ControlClient
import logging import logging
import datetime from infection_monkey.utils import get_current_time_string
__author__ = "VakarisZ" __author__ = "VakarisZ"
@ -21,7 +21,7 @@ class AttackTelem(object):
""" """
self.technique = technique self.technique = technique
self.result = status self.result = status
self.data = {'status': status, 'id': GUID, 'time': AttackTelem.get_current_time_string()} self.data = {'status': status, 'id': GUID, 'time': get_current_time_string()}
if data: if data:
self.data.update(data) self.data.update(data)
@ -40,13 +40,3 @@ class AttackTelem(object):
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warn("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
@staticmethod
def get_current_time_string():
time = datetime.datetime.now()
return "%s-%s-%s %s:%s:%s" % (time.date().year,
time.date().month,
time.date().day,
time.time().hour,
time.time().minute,
time.time().second)

View File

@ -2,7 +2,7 @@ import os
import sys import sys
import shutil import shutil
import struct import struct
import datetime
from infection_monkey.config import WormConfiguration from infection_monkey.config import WormConfiguration
@ -58,3 +58,12 @@ def get_monkey_dir_path():
return WormConfiguration.monkey_dir_windows return WormConfiguration.monkey_dir_windows
else: else:
return WormConfiguration.monkey_dir_linux return WormConfiguration.monkey_dir_linux
def get_current_time_string():
time = datetime.datetime.now()
return "%s-%s-%s %s:%s:%s" % (time.date().year,
time.date().month,
time.date().day,
time.time().hour,
time.time().minute,
time.time().second)

View File

@ -12,24 +12,35 @@ MESSAGES = {
def get_report_data(): def get_report_data():
data = get_tech_base_data(TECHNIQUE, MESSAGES) data = {'title': technique_title(TECHNIQUE)}
found_services = get_res_by_status(ScanStatus.SCANNED.value) scanned_services = get_scanned_services()
exploited_services = get_res_by_status(ScanStatus.USED.value) exploited_services = get_exploited_services()
data.update({'found_services': found_services, 'exploited_services': 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 return data
def get_res_by_status(status): def get_scanned_services():
results = mongo.db.attack_results.aggregate([{'$match': {'technique': TECHNIQUE, 'status': status}}, results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'scan'}},
{'$group': { {'$group': {
'_id': {'ip_addr': '$machine.ip_addr', '_id': {'ip_addr': '$data.machine.ip_addr',
'port': '$port', 'services': '$data.machine.services'
'url': '$url'}, },
'ip_addr': {'$first': '$machine.ip_addr'}, 'machine': {'$first': '$data.machine'}}}])
'domain_name': {'$first': '$machine.domain_name'}, return list(results)
'port': {'$first': '$port'},
'url': {'$first': '$url'},
'service': {'$last': '$service'}, def get_exploited_services():
'time': {'$first': '$time'}} results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'exploit', 'data.result': True}},
}]) {'$group': {
'_id': {'ip_addr': '$data.machine.ip_addr',
'info': '$data.info'
},
'service': {'$first': '$data.info.exploited_service'},
'machine': {'$first': '$data.machine'}}}])
return list(results) return list(results)

View File

@ -10,21 +10,26 @@ let renderMachine = function (val) {
) )
}; };
let renderPort = function (service){ let formatScanned = function (data){
if(service.url){ let result = [];
return service.url for(let service in data.machine.services){
} else { let scanned_service = {'machine': data.machine,
return service.port 'service': {'endpoint': data.machine.services[service].endpoint,
'name': data.machine.services[service].display_name,
'time': data.machine.services[service].time}};
result.push(scanned_service)
} }
return result
}; };
const columns = [ const columns = [
{ {
columns: [ columns: [
{Header: 'Machine', id: 'machine', accessor: x => renderMachine(x), style: { 'whiteSpace': 'unset' }, width: 200}, {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine),
{Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170}, style: { 'whiteSpace': 'unset' }, width: 200},
{Header: 'Port/url', id: 'port', accessor: x =>renderPort(x), style: { 'whiteSpace': 'unset' }}, {Header: 'Time', id: 'time', accessor: x => x.service.time, style: { 'whiteSpace': 'unset' }, width: 170},
{Header: 'Service', id: 'service', accessor: x => x.service, style: { 'whiteSpace': 'unset' }} {Header: 'Port/url', id: 'port', accessor: x =>x.service.endpoint, style: { 'whiteSpace': 'unset' }},
{Header: 'Service', id: 'service', accessor: x => x.service.name, style: { 'whiteSpace': 'unset' }}
] ]
} }
]; ];
@ -35,7 +40,7 @@ class T1210 extends React.Component {
super(props); super(props);
} }
renderFoundServices(data) { renderScannedServices(data) {
return ( return (
<div> <div>
<br/> <br/>
@ -64,11 +69,14 @@ class T1210 extends React.Component {
} }
render() { render() {
let scanned_services = this.props.data.scanned_services.map(formatScanned).flat();
console.log(scanned_services);
console.log(this.props.data);
return ( return (
<div> <div>
<div>{this.props.data.message}</div> <div>{this.props.data.message}</div>
{this.props.data.found_services.length > 0 ? {scanned_services.length > 0 ?
this.renderFoundServices(this.props.data.found_services) : ''} this.renderScannedServices(scanned_services) : ''}
{this.props.data.exploited_services.length > 0 ? {this.props.data.exploited_services.length > 0 ?
this.renderExploitedServices(this.props.data.exploited_services) : ''} this.renderExploitedServices(this.props.data.exploited_services) : ''}
<div className="attack-report footer-text"> <div className="attack-report footer-text">