Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ or (to dev)
```text
git clone git+https://github.com/login-securite/DonPAPI.git
cd DonPAPI
poetry update
poetry install
poetry run DonPAPI
```

Expand Down Expand Up @@ -129,7 +129,7 @@ authentication:

attacks:
-c COLLECTORS, --collectors COLLECTORS
Chromium, Certificates, CredMan, Files, Firefox, MobaXterm, MRemoteNG, RDCMan, SCCM, Vaults, VNC, Wifi, All (all
Chromium, Certificates, CredMan, Files, Firefox, MobaXterm, MRemoteNG, RDCMan, SCCM, Vaults, VNC, Wifi, Custom (as specified in config), All (all
previous) (default: All)
-nr, --no-remoteops Disable Remote Ops operations (basically no Remote Registry operations, no DPAPI System Credentials)
--fetch-pvk Will automatically use domain backup key from database, and if not already dumped, will dump it on a domain controller
Expand Down Expand Up @@ -181,7 +181,16 @@ share = C$
remote_filepath = \Users\Default\AppData\Local\Temp
filename_regex = \d{4}-\d{4}-\d{4}-[0-9]{4}
file_extension = .log
```
```

#### Collectors config

The collectors section in the config offers the option to define a custom set of collectors to run, as well as to specify collectors that will always be excluded (for example when using 'All' as collector). The config file is located at ~/.donpapi/donpapi.conf.
```toml
[collectors]
collectors_list = Chromium,Firefox,CredMan,MobaXterm,MRemoteNG,RDCMan,SCCM,Vaults,VNC,Wifi
always_exclude =
```

#### Recover

Expand Down
24 changes: 16 additions & 8 deletions donpapi/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,24 @@ def set_main_logger(logger , host = "\U0001F480"):
"hostname": "",
}

def load_collectors(root, collectors_list) -> Tuple[List, List] :
def load_collectors(root, collectors_list, config) -> Tuple[List, List] :
loaded_collectors = []
available_collectors = []
for _, collector_name, _ in iter_modules(path=[f"{root}/collectors/"]):
available_collectors.append(collector_name)
if "All" in collectors_list:
loaded_collectors.append(getattr(import_module(f"donpapi.collectors.{collector_name}"), collector_name))
elif "Custom" in collectors_list:
if collector_name in config.custom_collectors_list:
loaded_collectors.append(getattr(import_module(f"donpapi.collectors.{collector_name}"), collector_name))
else:
if collector_name in collectors_list:
loaded_collectors.append(getattr(import_module(f"donpapi.collectors.{collector_name}"), collector_name))

if config.always_exclude_collectors:
for collector in loaded_collectors:
if collector.__name__ in config.always_exclude_collectors:
loaded_collectors.remove(collector)
return available_collectors, loaded_collectors

def fetch_all_computers(options):
Expand Down Expand Up @@ -215,7 +223,7 @@ def main():
group_authent.add_argument("-r", "--recover-file", metavar="/home/user/.donpapi/recover/recover_1718281433", type=str, help="The recover file path. If used, the other parameters will be ignored")

group_attacks = collect_subparser.add_argument_group('attacks')
group_attacks.add_argument('-c','--collectors', action="store", default="All", help= ", ".join(load_collectors(root, [])[0])+", All (all previous) (default: All). Possible to chain multiple collectors comma separated")
group_attacks.add_argument('-c','--collectors', action="store", default="All", help= ", ".join(load_collectors(root, [], DonPAPIConfig())[0])+", Custom (as specified in config), All (all previous) (default: All). Possible to chain multiple collectors comma separated")
group_attacks.add_argument("-nr","--no-remoteops", action="store_true", help="Disable Remote Ops operations (basically no Remote Registry operations, no DPAPI System Credentials)")
group_attacks.add_argument("--fetch-pvk", action="store_true", help=("Will automatically use domain backup key from database, and if not already dumped, will dump it on a domain controller"))
group_attacks.add_argument("--pvkfile", action="store", help=("Pvk file with domain backup key"))
Expand Down Expand Up @@ -281,6 +289,10 @@ def main():
db = Database(db_engine)

if options.action == "collect":
# Parse config file ?
donpapi_config = DonPAPIConfig()
if not options.no_config:
donpapi_config = parse_config_file()

# Handle recover file
current_target_recovered = []
Expand Down Expand Up @@ -330,7 +342,8 @@ def main():
pvkbytes = fetch_domain_backupkey(options, db)

# Handling collectors
_, collectors = load_collectors(root, options.collectors.split(","))
_, collectors = load_collectors(root, options.collectors.split(","), donpapi_config)
donpapi_logger.display(f"Loaded the following collectors: {','.join(collector.__name__ for collector in collectors)}")

# Target selection
targets = []
Expand Down Expand Up @@ -358,11 +371,6 @@ def main():
donpapi_logger.display("Loaded {i} targets".format(i=len(targets)))
donpapi_logger.debug(f"Targets :{targets}")

# Parse config file ?
donpapi_config = DonPAPIConfig()
if not options.no_config:
donpapi_config = parse_config_file()

# Let's rock
try:
asyncio.run(start_dpp(
Expand Down
8 changes: 7 additions & 1 deletion donpapi/lib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@
DEFAULT_REMOTE_FILEPATH = "\\Users\\Default\\AppData\\Local\\Temp"
DEFAULT_FILENAME_REGEX = r"\d{4}-\d{4}-\d{4}-[0-9]{4}"
DEFAULT_FILE_EXTENSION = ".log"
DEFAULT_CUSTOM_COLLECTORS_LIST = "Chromium,Firefox,CredMan,MobaXterm,MRemoteNG,RDCMan,SCCM,Vaults,VNC,Wifi"
DEFAULT_ALWAYS_EXCLUDE_COLLECTORS = ""

@dataclass
class DonPAPIConfig:
custom_share: str = DEFAULT_CUSTOM_SHARE
custom_remote_filepath: str = DEFAULT_REMOTE_FILEPATH
custom_filename_regex: str = DEFAULT_FILENAME_REGEX
custom_file_extension: str = DEFAULT_FILE_EXTENSION
custom_collectors_list: str = DEFAULT_CUSTOM_COLLECTORS_LIST
always_exclude_collectors: str = DEFAULT_ALWAYS_EXCLUDE_COLLECTORS

def parse_config_file():
donpapi_config = configparser.ConfigParser()
donpapi_config.read(DPP_CONFIG_FILE_PATH)

if "secretsdump" not in donpapi_config.sections():
if "secretsdump" not in donpapi_config.sections() or "collectors" not in donpapi_config.sections():
first_run()
donpapi_config.read(DPP_CONFIG_FILE_PATH)

Expand All @@ -29,4 +33,6 @@ def parse_config_file():
custom_remote_filepath = donpapi_config.get("secretsdump", "remote_filepath", fallback=DEFAULT_REMOTE_FILEPATH),
custom_filename_regex = donpapi_config.get("secretsdump", "filename_regex", fallback=DEFAULT_FILENAME_REGEX),
custom_file_extension = donpapi_config.get("secretsdump", "file_extension", fallback=DEFAULT_FILE_EXTENSION),
custom_collectors_list = donpapi_config.get("collectors", "collectors_list", fallback=DEFAULT_CUSTOM_COLLECTORS_LIST),
always_exclude_collectors = donpapi_config.get("collectors", "always_exclude", fallback=DEFAULT_ALWAYS_EXCLUDE_COLLECTORS),
)
3 changes: 3 additions & 0 deletions donpapi/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
def create_recover_file(dirpath, targets, options):
timestamp = int(time.time())
filepath = os.path.join(dirpath, DPP_RECOVER_DIR_NAME, f"recover_{timestamp}")
recover_dirpath = os.path.join(dirpath, DPP_RECOVER_DIR_NAME)
if not os.path.exists(recover_dirpath):
os.makedirs(recover_dirpath)
with open(filepath, "w") as f:
write_recover_file(f, [f"{json.dumps(vars(options))}\n", ",".join(targets)])

Expand Down
5 changes: 4 additions & 1 deletion donpapi/res/donpapi.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
share = C$
remote_filepath = \Users\Default\AppData\Local\Temp
filename_regex = \d{4}-\d{4}-\d{4}-[0-9]{4}
file_extension = .log
file_extension = .log
[collectors]
collectors_list = Certificates,Chromium,CloudCredentials,CredMan,Firefox,IDEProjects,MRemoteNG,MobaXTerm,NotepadPP,PasswordManagers,PowerShellHistory,RDCMan,RecentFiles,RecycleBin,SCCM,SSHSecrets,VNC,Vaults,VersionControlSystems,Wam,Wifi
always_exclude =