From cdc576e77e654485db0cd33a09a739552eb7fd0d Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Wed, 22 Aug 2018 19:31:26 +0300 Subject: [PATCH 1/4] Make mimikatz inside zip and extract only if config says so --- infection_monkey/config.py | 3 +- infection_monkey/exploit/sambacry.py | 7 +-- infection_monkey/exploit/tools.py | 7 --- infection_monkey/monkey.spec | 31 ++++++++--- infection_monkey/pyinstaller_utils.py | 24 +++++++++ infection_monkey/readme.txt | 6 ++- .../system_info/mimikatz_collector.py | 31 +++++++++-- .../system_info/windows_info_collector.py | 13 +++-- infection_monkey/utils.py | 1 + monkey_island/cc/services/config.py | 51 +++++++++---------- 10 files changed, 119 insertions(+), 55 deletions(-) create mode 100644 infection_monkey/pyinstaller_utils.py diff --git a/infection_monkey/config.py b/infection_monkey/config.py index 818bc75a0..8b458bd02 100644 --- a/infection_monkey/config.py +++ b/infection_monkey/config.py @@ -273,13 +273,12 @@ class Configuration(object): # system info collection collect_system_info = True + should_use_mimikatz = True ########################### # systeminfo config ########################### - mimikatz_dll_name = "mk.dll" - extract_azure_creds = True diff --git a/infection_monkey/exploit/sambacry.py b/infection_monkey/exploit/sambacry.py index 930cd8854..bddac84a1 100644 --- a/infection_monkey/exploit/sambacry.py +++ b/infection_monkey/exploit/sambacry.py @@ -19,7 +19,8 @@ import monkeyfs from exploit import HostExploiter from model import DROPPER_ARG from network.smbfinger import SMB_SERVICE -from tools import build_monkey_commandline, get_target_monkey_by_os, get_binaries_dir_path, get_monkey_depth +from tools import build_monkey_commandline, get_target_monkey_by_os, get_monkey_depth +from pyinstaller_utils import get_binary_file_path __author__ = 'itay.mizeretz' @@ -306,9 +307,9 @@ class SambaCryExploiter(HostExploiter): def get_monkey_runner_bin_file(self, is_32bit): if is_32bit: - return open(path.join(get_binaries_dir_path(), self.SAMBACRY_RUNNER_FILENAME_32), "rb") + return open(get_binary_file_path(self.SAMBACRY_RUNNER_FILENAME_32), "rb") else: - return open(path.join(get_binaries_dir_path(), self.SAMBACRY_RUNNER_FILENAME_64), "rb") + return open(get_binary_file_path(self.SAMBACRY_RUNNER_FILENAME_64), "rb") def get_monkey_commandline_file(self, location): return BytesIO(DROPPER_ARG + build_monkey_commandline(self.host, get_monkey_depth() - 1, location)) diff --git a/infection_monkey/exploit/tools.py b/infection_monkey/exploit/tools.py index dbbd8070a..28f65cc69 100644 --- a/infection_monkey/exploit/tools.py +++ b/infection_monkey/exploit/tools.py @@ -471,13 +471,6 @@ def build_monkey_commandline(target_host, depth, location=None): GUID, target_host.default_tunnel, target_host.default_server, depth, location) -def get_binaries_dir_path(): - if getattr(sys, 'frozen', False): - return sys._MEIPASS - else: - return os.path.dirname(os.path.abspath(__file__)) - - def get_monkey_depth(): from config import WormConfiguration return WormConfiguration.depth diff --git a/infection_monkey/monkey.spec b/infection_monkey/monkey.spec index cb9c6130e..7e3e254c4 100644 --- a/infection_monkey/monkey.spec +++ b/infection_monkey/monkey.spec @@ -1,22 +1,37 @@ # -*- mode: python -*- import os import platform +import zipfile + +# Name of zip file that will be created +MIMIKATZ_ZIP_NAME = 'tmpzipfile123456.zip' +# Name of zip file in monkey. That's the name of the file in the _MEI folder +MIMIKATZ_ZIP_NAME_MONKEY = MIMIKATZ_ZIP_NAME +# Name of mimikatz dll in zip archive +MIMIKATZ_DLL_NAME_ZIP = 'tmpzipfile123456.dll' +# Password for mimikatz zip +MIMIKATZ_ZIP_PASSWORD = 'HEDFGFDSgfsdg4235342#@$^@#shd35' + + +def get_mimikatz_zip_path(): + if platform.architecture()[0] == "32bit": + return '.\\bin\\mk32.zip' + else: + return '.\\bin\\mk64.zip' + + a = Analysis(['main.py'], pathex=['.', '..'], hiddenimports=['_cffi_backend', 'queue'], hookspath=None, runtime_hooks=None) - -a.binaries += [('sc_monkey_runner32.so', '.\\bin\\sc_monkey_runner32.so', 'BINARY')] -a.binaries += [('sc_monkey_runner64.so', '.\\bin\\sc_monkey_runner64.so', 'BINARY')] +a.binaries += [('sc_monkey_runner32.so', '.\\bin\\sc_monkey_runner32.so', 'BINARY')] +a.binaries += [('sc_monkey_runner64.so', '.\\bin\\sc_monkey_runner64.so', 'BINARY')] -if platform.system().find("Windows")>= 0: +if platform.system().find("Windows") >= 0: a.datas = [i for i in a.datas if i[0].find('Include') < 0] - if platform.architecture()[0] == "32bit": - a.binaries += [('mk.dll', '.\\bin\\mk32.dll', 'BINARY')] - else: - a.binaries += [('mk.dll', '.\\bin\\mk64.dll', 'BINARY')] + a.binaries += [(MIMIKATZ_ZIP_NAME_MONKEY, get_mimikatz_zip_path(), 'BINARY')] pyz = PYZ(a.pure) exe = EXE(pyz, diff --git a/infection_monkey/pyinstaller_utils.py b/infection_monkey/pyinstaller_utils.py new file mode 100644 index 000000000..c31e7748c --- /dev/null +++ b/infection_monkey/pyinstaller_utils.py @@ -0,0 +1,24 @@ +import os +import sys + + +__author__ = 'itay.mizeretz' + +def get_binaries_dir_path(): + """ + Gets the path to the binaries dir (files packaged in pyinstaller if it was used, infection_monkey dir otherwise) + :return: Binaries dir path + """ + if getattr(sys, 'frozen', False): + return sys._MEIPASS + else: + return os.path.dirname(os.path.abspath(__file__)) + + +def get_binary_file_path(filename): + """ + Gets the path to a binary file + :param filename: name of the file + :return: Path to file + """ + return os.path.join(get_binaries_dir_path(), filename) diff --git a/infection_monkey/readme.txt b/infection_monkey/readme.txt index 67c4033d9..0096f98ab 100644 --- a/infection_monkey/readme.txt +++ b/infection_monkey/readme.txt @@ -70,4 +70,8 @@ Sambacry requires two standalone binaries to execute remotely. Mimikatz is required for the Monkey to be able to steal credentials on Windows. It's possible to either compile from sources (requires Visual Studio 2013 and up) or download the binaries from https://github.com/guardicore/mimikatz/releases/tag/1.0.0 -Download both 32 and 64 bit DLLs and place them under [code location]\infection_monkey\bin \ No newline at end of file +Download both 32 and 64 bit zipped DLLs and place them under [code location]\infection_monkey\bin +Alternatively, if you build Mimikatz, put each version in a zip file. +1. The zip should contain only the Mimikatz DLL named tmpzipfile123456.dll +2. It should be protected using the password 'VTQpsJPXgZuXhX6x3V84G'. +3. The zip file should be named mk32.zip/mk64.zip accordingly. \ No newline at end of file diff --git a/infection_monkey/system_info/mimikatz_collector.py b/infection_monkey/system_info/mimikatz_collector.py index 65f326256..365a00648 100644 --- a/infection_monkey/system_info/mimikatz_collector.py +++ b/infection_monkey/system_info/mimikatz_collector.py @@ -2,6 +2,9 @@ import binascii import ctypes import logging import socket +import zipfile + +from pyinstaller_utils import get_binary_file_path, get_binaries_dir_path __author__ = 'itay.mizeretz' @@ -13,12 +16,30 @@ class MimikatzCollector(object): Password collection module for Windows using Mimikatz. """ - def __init__(self): - try: + # Name of Mimikatz DLL. Must be name of file in Mimikatz zip. + MIMIKATZ_DLL_NAME = 'tmpzipfile123456.dll' - self._isInit = False - self._config = __import__('config').WormConfiguration - self._dll = ctypes.WinDLL(self._config.mimikatz_dll_name) + # Name of ZIP containing Mimikatz. Must be identical to one on monkey.spec + MIMIKATZ_ZIP_NAME = 'tmpzipfile123456.zip' + + # Password to Mimikatz zip file + MIMIKATZ_ZIP_PASSWORD = r'VTQpsJPXgZuXhX6x3V84G' + + def __init__(self): + self._config = __import__('config').WormConfiguration + self._isInit = False + self._dll = None + self._collect = None + self._get = None + self.init_mimikatz() + + def init_mimikatz(self): + try: + with zipfile.ZipFile(get_binary_file_path(MimikatzCollector.MIMIKATZ_ZIP_NAME), 'r') as mimikatz_zip: + mimikatz_zip.extract(self.MIMIKATZ_DLL_NAME, path=get_binaries_dir_path(), + pwd=self.MIMIKATZ_ZIP_PASSWORD) + + self._dll = ctypes.WinDLL(get_binary_file_path(self.MIMIKATZ_DLL_NAME)) collect_proto = ctypes.WINFUNCTYPE(ctypes.c_int) get_proto = ctypes.WINFUNCTYPE(MimikatzCollector.LogonData) self._collect = collect_proto(("collect", self._dll)) diff --git a/infection_monkey/system_info/windows_info_collector.py b/infection_monkey/system_info/windows_info_collector.py index 610c4e8e3..b3657f0f0 100644 --- a/infection_monkey/system_info/windows_info_collector.py +++ b/infection_monkey/system_info/windows_info_collector.py @@ -15,6 +15,7 @@ class WindowsInfoCollector(InfoCollector): def __init__(self): super(WindowsInfoCollector, self).__init__() + self._config = __import__('config').WormConfiguration def get_info(self): """ @@ -28,7 +29,13 @@ class WindowsInfoCollector(InfoCollector): self.get_process_list() self.get_network_info() self.get_azure_info() - mimikatz_collector = MimikatzCollector() - mimikatz_info = mimikatz_collector.get_logon_info() - self.info["credentials"].update(mimikatz_info) + self._get_mimikatz_info() + return self.info + + def _get_mimikatz_info(self): + if self._config.should_use_mimikatz: + LOG.info("Using mimikatz") + self.info["credentials"].update(MimikatzCollector().get_logon_info()) + else: + LOG.info("Not using mimikatz") diff --git a/infection_monkey/utils.py b/infection_monkey/utils.py index e2f66bd03..b39cd44f5 100644 --- a/infection_monkey/utils.py +++ b/infection_monkey/utils.py @@ -29,3 +29,4 @@ def is_64bit_python(): def is_windows_os(): return sys.platform.startswith("win") + diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 8781f2b21..ebd099e1e 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -279,6 +279,31 @@ SCHEMA = { } } }, + "system_info": { + "title": "System info", + "type": "object", + "properties": { + "extract_azure_creds": { + "title": "Harvest Azure Credentials", + "type": "boolean", + "default": True, + "description": + "Determine if the Monkey should try to harvest password credentials from Azure VMs" + }, + "collect_system_info": { + "title": "Collect system info", + "type": "boolean", + "default": True, + "description": "Determines whether to collect system info" + }, + "should_use_mimikatz": { + "title": "Should use Mimikatz", + "type": "boolean", + "default": True, + "description": "Determines whether to use Mimikatz" + }, + } + }, "life_cycle": { "title": "Life cycle", "type": "object", @@ -339,12 +364,6 @@ SCHEMA = { "description": "The name of the mutex used to determine whether the monkey is already running" }, - "collect_system_info": { - "title": "Collect system info", - "type": "boolean", - "default": True, - "description": "Determines whether to collect system info" - }, "keep_tunnel_open_time": { "title": "Keep tunnel open time", "type": "integer", @@ -536,26 +555,6 @@ SCHEMA = { "description": "List of SSH key pairs to use, when trying to ssh into servers" } } - }, - "systemInfo": { - "title": "System collection", - "type": "object", - "properties": { - "mimikatz_dll_name": { - "title": "Mimikatz DLL name", - "type": "string", - "default": "mk.dll", - "description": - "Name of Mimikatz DLL (should be the same as in the monkey's pyinstaller spec file)" - }, - "extract_azure_creds": { - "title": "Harvest Azure Credentials", - "type": "boolean", - "default": True, - "description": - "Determine if the Monkey should try to harvest password credentials from Azure VMs" - } - } } } }, From 5489a68049eea9606a57853fe558b3ac911f47f8 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Thu, 23 Aug 2018 14:10:50 +0300 Subject: [PATCH 2/4] Remove unecessary consts --- infection_monkey/monkey.spec | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/infection_monkey/monkey.spec b/infection_monkey/monkey.spec index 7e3e254c4..2f536dcdc 100644 --- a/infection_monkey/monkey.spec +++ b/infection_monkey/monkey.spec @@ -3,14 +3,8 @@ import os import platform import zipfile -# Name of zip file that will be created -MIMIKATZ_ZIP_NAME = 'tmpzipfile123456.zip' # Name of zip file in monkey. That's the name of the file in the _MEI folder -MIMIKATZ_ZIP_NAME_MONKEY = MIMIKATZ_ZIP_NAME -# Name of mimikatz dll in zip archive -MIMIKATZ_DLL_NAME_ZIP = 'tmpzipfile123456.dll' -# Password for mimikatz zip -MIMIKATZ_ZIP_PASSWORD = 'HEDFGFDSgfsdg4235342#@$^@#shd35' +MIMIKATZ_ZIP_NAME = 'tmpzipfile123456.zip' def get_mimikatz_zip_path(): @@ -31,7 +25,7 @@ a.binaries += [('sc_monkey_runner64.so', '.\\bin\\sc_monkey_runner64.so', 'BINAR if platform.system().find("Windows") >= 0: a.datas = [i for i in a.datas if i[0].find('Include') < 0] - a.binaries += [(MIMIKATZ_ZIP_NAME_MONKEY, get_mimikatz_zip_path(), 'BINARY')] + a.binaries += [(MIMIKATZ_ZIP_NAME, get_mimikatz_zip_path(), 'BINARY')] pyz = PYZ(a.pure) exe = EXE(pyz, @@ -43,4 +37,5 @@ exe = EXE(pyz, debug=False, strip=None, upx=True, - console=True , icon='monkey.ico') + console=True, + icon='monkey.ico') From 5b6a9595f46dbdeb7268b3ce7bced16f6fbeae1d Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Wed, 29 Aug 2018 16:56:55 +0300 Subject: [PATCH 3/4] mimikatz zip is now in datas --- infection_monkey/monkey.spec | 3 +-- infection_monkey/pyinstaller_utils.py | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infection_monkey/monkey.spec b/infection_monkey/monkey.spec index 2f536dcdc..b4449361b 100644 --- a/infection_monkey/monkey.spec +++ b/infection_monkey/monkey.spec @@ -1,7 +1,6 @@ # -*- mode: python -*- import os import platform -import zipfile # Name of zip file in monkey. That's the name of the file in the _MEI folder MIMIKATZ_ZIP_NAME = 'tmpzipfile123456.zip' @@ -25,7 +24,7 @@ a.binaries += [('sc_monkey_runner64.so', '.\\bin\\sc_monkey_runner64.so', 'BINAR if platform.system().find("Windows") >= 0: a.datas = [i for i in a.datas if i[0].find('Include') < 0] - a.binaries += [(MIMIKATZ_ZIP_NAME, get_mimikatz_zip_path(), 'BINARY')] + a.datas += [(MIMIKATZ_ZIP_NAME, get_mimikatz_zip_path(), 'BINARY')] pyz = PYZ(a.pure) exe = EXE(pyz, diff --git a/infection_monkey/pyinstaller_utils.py b/infection_monkey/pyinstaller_utils.py index c31e7748c..d169bda6a 100644 --- a/infection_monkey/pyinstaller_utils.py +++ b/infection_monkey/pyinstaller_utils.py @@ -4,6 +4,7 @@ import sys __author__ = 'itay.mizeretz' + def get_binaries_dir_path(): """ Gets the path to the binaries dir (files packaged in pyinstaller if it was used, infection_monkey dir otherwise) From cd020668efd2833bded9fec10827ec76581950a0 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Wed, 29 Aug 2018 16:58:33 +0300 Subject: [PATCH 4/4] Add note regarding 7zip --- infection_monkey/readme.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infection_monkey/readme.txt b/infection_monkey/readme.txt index 0096f98ab..c90b1f6af 100644 --- a/infection_monkey/readme.txt +++ b/infection_monkey/readme.txt @@ -74,4 +74,5 @@ Download both 32 and 64 bit zipped DLLs and place them under [code location]\inf Alternatively, if you build Mimikatz, put each version in a zip file. 1. The zip should contain only the Mimikatz DLL named tmpzipfile123456.dll 2. It should be protected using the password 'VTQpsJPXgZuXhX6x3V84G'. -3. The zip file should be named mk32.zip/mk64.zip accordingly. \ No newline at end of file +3. The zip file should be named mk32.zip/mk64.zip accordingly. +4. Zipping with 7zip has been tested. Other zipping software may not work. \ No newline at end of file