diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index e1ebfcdcd..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, MySQLFinger +from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger from network.range import FixedRange __author__ = 'itamar' @@ -142,9 +142,9 @@ class Configuration(object): max_iterations = 1 scanner_class = TcpScanner - finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger] + finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger, MySQLFinger, ElasticFinger] exploiter_classes = [SmbExploiter, WmiExploiter, RdpExploiter, Ms08_067_Exploiter, # Windows exploits - SSHExploiter, ShellShockExploiter, SambaCryExploiter # Linux + SSHExploiter, ShellShockExploiter, SambaCryExploiter, # Linux ] # how many victims to look for in a single scan iteration @@ -188,7 +188,17 @@ class Configuration(object): HTTP_PORTS = [80, 8080, 443, 8008, # HTTP alternate ] - tcp_target_ports = [22, 2222, 445, 135, 3389, 3306, ] + tcp_target_ports = [22, + 2222, + 445, + 135, + 3389, + 80, + 8080, + 443, + 8008, + 3306, + 9200] tcp_target_ports.extend(HTTP_PORTS) tcp_scan_timeout = 3000 # 3000 Milliseconds tcp_scan_interval = 200 @@ -213,6 +223,10 @@ class Configuration(object): # User and password dictionaries for exploits. def get_exploit_user_password_pairs(self): + """ + Returns all combinations of the configurations users and passwords + :return: + """ return product(self.exploit_user_list, self.exploit_password_list) exploit_user_list = ['Administrator', 'root', 'user'] diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index 6ef9558ae..3db576ad3 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -41,6 +41,7 @@ "HTTPFinger", "SMBFinger", "MySQLFinger" + "ElasticFinger", ], "max_iterations": 3, "monkey_log_path_windows": "%temp%\\~df1563.tmp", @@ -85,7 +86,8 @@ 8080, 443, 3306, - 8008 + 8008, + 9200 ], "timeout_between_iterations": 10, "use_file_logging": true, diff --git a/chaos_monkey/network/__init__.py b/chaos_monkey/network/__init__.py index e7f22de28..a1df9d2e9 100644 --- a/chaos_monkey/network/__init__.py +++ b/chaos_monkey/network/__init__.py @@ -23,6 +23,7 @@ from tcp_scanner import TcpScanner 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/elasticfinger.py b/chaos_monkey/network/elasticfinger.py new file mode 100644 index 000000000..730decf4f --- /dev/null +++ b/chaos_monkey/network/elasticfinger.py @@ -0,0 +1,48 @@ +import json +import logging +from contextlib import closing + +import requests +from requests.exceptions import Timeout, ConnectionError + +from model.host import VictimHost +from network import HostFinger + +ES_PORT = 9200 +ES_SERVICE = 'elastic-search-9200' +ES_HTTP_TIMEOUT = 5 +LOG = logging.getLogger(__name__) +__author__ = 'danielg' + + +class ElasticFinger(HostFinger): + """ + Fingerprints elastic search clusters, only on port 9200 + """ + + def __init__(self): + self._config = __import__('config').WormConfiguration + + def get_host_fingerprint(self, host): + """ + Returns elasticsearch metadata + :param host: + :return: Success/failure, data is saved in the host struct + """ + assert isinstance(host, VictimHost) + try: + url = 'http://%s:%s/' % (host.ip_addr, ES_PORT) + with closing(requests.get(url, timeout=ES_HTTP_TIMEOUT)) as req: + data = json.loads(req.text) + host.services[ES_SERVICE] = {} + host.services[ES_SERVICE]['cluster_name'] = data['cluster_name'] + host.services[ES_SERVICE]['name'] = data['name'] + host.services[ES_SERVICE]['version'] = data['version']['number'] + return True + except Timeout: + LOG.debug("Got timeout while trying to read header information") + except ConnectionError: # Someone doesn't like us + LOG.debug("Unknown connection error") + except KeyError: + LOG.debug("Failed parsing the ElasticSearch JSOn response") + return False diff --git a/chaos_monkey/system_info/__init__.py b/chaos_monkey/system_info/__init__.py index b9a16d459..ddf13d885 100644 --- a/chaos_monkey/system_info/__init__.py +++ b/chaos_monkey/system_info/__init__.py @@ -1,8 +1,10 @@ -import sys import socket +import sys + import psutil from enum import IntEnum -from network.info import get_host_subnets, local_ips + +from network.info import get_host_subnets __author__ = 'uri' @@ -68,7 +70,7 @@ class InfoCollector(object): "cmdline": " ".join(process.cmdline()), "full_image_path": process.exe(), } - except psutil.AccessDenied: + except (psutil.AccessDenied, WindowsError): # we may be running as non root # and some processes are impossible to acquire in Windows/Linux # in this case we'll just add what we can @@ -78,7 +80,8 @@ class InfoCollector(object): "cmdline": "ACCESS DENIED", "full_image_path": "null", } - pass + continue + self.info['process_list'] = processes def get_network_info(self):