diff --git a/infection_monkey/config.py b/infection_monkey/config.py index 4e87243a8..e881472d1 100644 --- a/infection_monkey/config.py +++ b/infection_monkey/config.py @@ -8,7 +8,8 @@ from itertools import product from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter, \ SambaCryExploiter, ElasticGroovyExploiter, Struts2Exploiter -from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger +from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger, \ + MSSQLFinger __author__ = 'itamar' @@ -145,7 +146,7 @@ class Configuration(object): max_iterations = 1 scanner_class = TcpScanner - finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger, ElasticFinger] + finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger, ElasticFinger, MSSQLFinger] exploiter_classes = [SmbExploiter, WmiExploiter, # Windows exploits SSHExploiter, ShellShockExploiter, SambaCryExploiter, # Linux ElasticGroovyExploiter, Struts2Exploiter # multi @@ -184,9 +185,9 @@ class Configuration(object): # Auto detect and scan local subnets local_network_scan = True - subnet_scan_list = ['', ] + subnet_scan_list = [] - blocked_ips = ['', ] + blocked_ips = [] # TCP Scanner HTTP_PORTS = [80, 8080, 443, diff --git a/infection_monkey/example.conf b/infection_monkey/example.conf index a6961331f..4857e3649 100644 --- a/infection_monkey/example.conf +++ b/infection_monkey/example.conf @@ -8,9 +8,9 @@ ], "keep_tunnel_open_time": 60, "subnet_scan_list": [ - "" + ], - "blocked_ips": [""], + "blocked_ips": [], "current_server": "41.50.73.31:5000", "alive": true, "collect_system_info": true, @@ -45,6 +45,7 @@ "HTTPFinger", "SMBFinger", "MySQLFinger", + "MSSQLFingerprint", "ElasticFinger" ], "max_iterations": 3, diff --git a/infection_monkey/network/__init__.py b/infection_monkey/network/__init__.py index a1df9d2e9..fa15e357c 100644 --- a/infection_monkey/network/__init__.py +++ b/infection_monkey/network/__init__.py @@ -27,3 +27,4 @@ from elasticfinger import ElasticFinger from mysqlfinger import MySQLFinger from info import local_ips from info import get_free_tcp_port +from mssql_fingerprint import MSSQLFinger \ No newline at end of file diff --git a/infection_monkey/network/mssql_fingerprint.py b/infection_monkey/network/mssql_fingerprint.py new file mode 100644 index 000000000..9409c2255 --- /dev/null +++ b/infection_monkey/network/mssql_fingerprint.py @@ -0,0 +1,74 @@ +import logging +import socket + +from model.host import VictimHost +from network import HostFinger + +__author__ = 'Maor Rayzin' + +LOG = logging.getLogger(__name__) + + +class MSSQLFinger(HostFinger): + + # Class related consts + SQL_BROWSER_DEFAULT_PORT = 1434 + BUFFER_SIZE = 4096 + TIMEOUT = 5 + SERVICE_NAME = 'MSSQL' + + def __init__(self): + self._config = __import__('config').WormConfiguration + + def get_host_fingerprint(self, host): + """Gets Microsoft SQL Server instance information by querying the SQL Browser service. + :arg: + host (VictimHost): The MS-SSQL Server to query for information. + + :returns: + Discovered server information written to the Host info struct. + True if success, False otherwise. + """ + + assert isinstance(host, VictimHost) + + # Create a UDP socket and sets a timeout + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.settimeout(self.TIMEOUT) + server_address = (str(host.ip_addr), self.SQL_BROWSER_DEFAULT_PORT) + + # The message is a CLNT_UCAST_EX packet to get all instances + # https://msdn.microsoft.com/en-us/library/cc219745.aspx + message = '\x03' + + # Encode the message as a bytesarray + message = message.encode() + + # send data and receive response + try: + LOG.info('Sending message to requested host: {0}, {1}'.format(host, message)) + sock.sendto(message, server_address) + data, server = sock.recvfrom(self.BUFFER_SIZE) + except socket.timeout: + LOG.info('Socket timeout reached, maybe browser service on host: {0} doesnt exist'.format(host)) + sock.close() + return False + + host.services[self.SERVICE_NAME] = {} + + # Loop through the server data + instances_list = data[3:].decode().split(';;') + LOG.info('{0} MSSQL instances found'.format(len(instances_list))) + for instance in instances_list: + instance_info = instance.split(';') + if len(instance_info) > 1: + host.services[self.SERVICE_NAME][instance_info[1]] = {} + 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 will appear under its own name + host.services[self.SERVICE_NAME][instance_info[1]][instance_info[i - 1]] = instance_info[i] + + # Close the socket + sock.close() + + return True diff --git a/monkey_island/cc/resources/root.py b/monkey_island/cc/resources/root.py index 56a7695c7..1d9141589 100644 --- a/monkey_island/cc/resources/root.py +++ b/monkey_island/cc/resources/root.py @@ -64,7 +64,6 @@ class Root(flask_restful.Resource): infection_done = NodeService.is_monkey_finished_running() if not infection_done: report_done = False - logger.info('Report generation cannot be completed, infection is not done.') else: report_done = ReportService.is_report_generated() return dict(run_server=True, run_monkey=is_any_exists, infection_done=infection_done, report_done=report_done) diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index c3534c95c..79d1e2c51 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -128,6 +128,14 @@ SCHEMA = { ], "title": "MySQLFinger" }, + { + "type": "string", + "enum": [ + "MSSQLFinger" + ], + "title": "MSSQLFinger" + }, + { "type": "string", "enum": [ @@ -374,6 +382,7 @@ SCHEMA = { "PingScanner", "HTTPFinger", "MySQLFinger", + "MSSQLFinger", "ElasticFinger" ], "description": "Determines which classes to use for fingerprinting"