diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index e5a7d736a..b9d250cd8 100644 --- a/chaos_monkey/config.py +++ b/chaos_monkey/config.py @@ -7,7 +7,7 @@ from itertools import product from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter, \ SambaCryExploiter -from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, ElasticFinger +from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger from network.range import FixedRange __author__ = 'itamar' @@ -142,7 +142,7 @@ class Configuration(object): max_iterations = 1 scanner_class = TcpScanner - finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, ElasticFinger, ] + finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger, ElasticFinger] exploiter_classes = [SmbExploiter, WmiExploiter, RdpExploiter, Ms08_067_Exploiter, # Windows exploits SSHExploiter, ShellShockExploiter, SambaCryExploiter, # Linux ] @@ -197,6 +197,7 @@ class Configuration(object): 8080, 443, 8008, + 3306, 9200] tcp_target_ports.extend(HTTP_PORTS) tcp_scan_timeout = 3000 # 3000 Milliseconds diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index 982482cdf..3db576ad3 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -39,8 +39,9 @@ "SSHFinger", "PingScanner", "HTTPFinger", + "SMBFinger", + "MySQLFinger" "ElasticFinger", - "SMBFinger" ], "max_iterations": 3, "monkey_log_path_windows": "%temp%\\~df1563.tmp", @@ -84,6 +85,7 @@ 80, 8080, 443, + 3306, 8008, 9200 ], diff --git a/chaos_monkey/network/__init__.py b/chaos_monkey/network/__init__.py index 8e31d3f11..a1df9d2e9 100644 --- a/chaos_monkey/network/__init__.py +++ b/chaos_monkey/network/__init__.py @@ -24,5 +24,6 @@ from smbfinger import SMBFinger from sshfinger import SSHFinger from httpfinger import HTTPFinger from elasticfinger import ElasticFinger +from mysqlfinger import MySQLFinger from info import local_ips from info import get_free_tcp_port diff --git a/chaos_monkey/network/mysqlfinger.py b/chaos_monkey/network/mysqlfinger.py new file mode 100644 index 000000000..39baa05ac --- /dev/null +++ b/chaos_monkey/network/mysqlfinger.py @@ -0,0 +1,85 @@ +import logging +import socket + +from model.host import VictimHost +from network import HostFinger +from .tools import struct_unpack_tracker, struct_unpack_tracker_string + +MYSQL_PORT = 3306 +SQL_SERVICE = 'mysqld-3306' + +LOG = logging.getLogger(__name__) + + +class MySQLFinger(HostFinger): + """ + Fingerprints mysql databases, only on port 3306 + """ + + SOCKET_TIMEOUT = 0.5 + HEADER_SIZE = 4 # in bytes + + def __init__(self): + self._config = __import__('config').WormConfiguration + + def get_host_fingerprint(self, host): + """ + Returns mySQLd data using the host header + :param host: + :return: Success/failure, data is saved in the host struct + """ + assert isinstance(host, VictimHost) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(self.SOCKET_TIMEOUT) + + try: + s.connect((host.ip_addr, MYSQL_PORT)) + header = s.recv(self.HEADER_SIZE) # max header size? + + response, curpos = struct_unpack_tracker(header, 0, "I") + response = response[0] + response_length = response & 0xff # first byte is significant + data = s.recv(response_length) + # now we can start parsing + protocol, curpos = struct_unpack_tracker(data, 0, "B") + protocol = protocol[0] + + if protocol == 0xFF: + # error code, bug out + LOG.debug("Mysql server returned error") + return False + + version, curpos = struct_unpack_tracker_string(data, curpos) # special coded to solve string parsing + version = version[0] + host.services[SQL_SERVICE] = {} + host.services[SQL_SERVICE]['version'] = version + version = version.split('-')[0].split('.') + host.services[SQL_SERVICE]['major_version'] = version[0] + host.services[SQL_SERVICE]['minor_version'] = version[1] + host.services[SQL_SERVICE]['build_version'] = version[2] + thread_id, curpos = struct_unpack_tracker(data, curpos, "