# Credentials Dumping

## Living-off-the-Land Binaries

```
rundll32.exe C:\Windows\System32\comsvcs.dll MiniDump PID lsass.dmp full
```

## Globfuscation

```
&$env:???t??r???\*2\r[t-u]???[k-l]?2* $(gi $env:???t??r???\*2\c?m?[v-w]*l | % {
  $_.FullName }), `#-999999999999999999999999999999999999999999999999999999999999
  999999999999999999999999999999999999999999999999999999999999999999999999999999
  999999999999999999999999999999999999999999999999999999999999999999999999999999
  99999999999999999976-decoy $(gps l?a*s).id c:\t??p\dmp.log full;
```

## MiniDumpWriteDump

To use the `MiniDumpWriteDump` API, we need a `HANDLE` to `lsass.exe`. Assuming we got such a handle, we do the following:

1. Create a new file and get its handle.
2. Invoke the [MiniDumpWriteDump API](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump) on the `lsass.exe` handle and the file handle.

However, there is a variant that doesn't require writing to disk at all - we can save the entire dump to a memory buffer! To achieve that, we:

1. Create a buffer with some initial size.
2. Create a structure of type `MINIDUMP_CALLBACK_INFORMATION` and specify a callback function (and context).
3. Invoke the [MiniDumpWriteDump API](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump) on the `lsass.exe` handle and the callback pointer.
4. The callback accumulates the data from the minidump argument upon receivng a `IoWriteAllCallback` callback type. Ths might require us to dynamically enlarge the buffer with the `HeapReAlloc` API.

There are two variants to get a handle to `lsass.exe`:

### **Using OpenProcess**

This is the most direct and "normal" way of fetching the `lsass.exe` process handle:

1. Finding the process ID of `lsass.exe` with [CreateToolhelp32Snapshot API](https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot), as well as [Process32FirstW](https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32firstw) and [Process32NextW](https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32nextw) API calls.
2. Use the [OpenProcess](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess) API. For doing a Minidump, we will require the `PROCESS_QUERY_INFORMATION` and `PROCESS_VM_READ` access flags.

### **Stealing An Existing Handle**

Since `OpenProcess` is usually heavily monitored by security products, there is a sneakier option - duplicating an existing handle to `lsass.exe` some other process might have.

Similarly to the `OpenProcess` approach - we fetch the `lsass.exe` PID the usual way (`CreateToolhelp32Snapshot` and friends).

However, here our approach would be finding an existing handle to `lsass.exe` with sufficient access flags:

1. We call [ntdll!NtQuerySystemInformation](https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation) with the information class `SystemHandleInformation` (defined as 16) with a sufficiently large buffer. As of now, that information class is officially undocumented (but can be found [here](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi/system_information_class.htm)).
2. We treat the buffer as a [SYSTEM\_HANDLE\_INFORMATION](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/handle.htm) pointer (again officially undocumented).
3. For each handle, we skip if it belongs to the `lsass.exe` process ID itself, to our own process or the SYSTEM process ID (4).
4. We call `ntdll!NtDuplicateObject` to duplicate the handle. In this call we also specify the required access flags.
5. We call `ntdll!NtQueryObject` with type `OBJECT_TYPE_INFORMATION_CLASS` to get the duplicated handle type and make sure it's a `process` handle type.
6. We call the [QueryFullProcessImageNameW API](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-queryfullprocessimagenamew) and validate it's indeed `lsass.exe` (note it's a full name so extra parsing is required).
7. If all checks pass - we got a handle to `lsass.exe` that we've just duplicated! Otherwise, we clean up used resources and try a different handle.

**Note:** a running OS is not guaranteed to have an open `lsass.exe` by some process with sufficient access flags - if that's the case we can always revert to running `OpenProcess` as usual. However, all the native APIs (and especially the handle duplication) make it way stealtier than calling `OpenProcess` directly.

## PssCaptureSnapshot-based dumping

Similarly to the Minidump approach, we get a handle to `lsass.exe` by means of `OpenProcess` or handle duplication, but this time also with `PROCESS_DUP_HANDLE` access flag.

Then, we call the [PssCaptureSnapshot API](https://learn.microsoft.com/en-us/windows/win32/api/processsnapshot/nf-processsnapshot-psscapturesnapshot?redirectedfrom=MSDN) which returns us a pseudo-handle of type `HPSS`. As the name suggests, that handle captures a "snapshot" of the `lsass.exe` state (includng memory), and then could be used just like a normal handle to `ReadProcessMemory` or `MiniDumpWriteDump`.

The approach doesn't seem advantageous, but it's very reliable due to how it captures a snapshot (as opposed to direct `ReadProcessMemory` which has an inherent race condition, for example).

## SilentProcessExit-based dumping

This technique relies on a Windows mechanism that can invoke a callback once a process exits, as well as fooling the system into thinking the process indeed exited. To implement this technique, we do the following:

1. Get an `lsass.exe` handle (either via `OpenProcess` or by handle duplication).
2. Write to the registry under the [Image File Execution Options (IFEO)](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/xperf/image-file-execution-options) key `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\lsass.exe`. Value name is `GlobalFlag` which is of type `DWORD`, and we set it to the value of `0x200`, which corresponds to enabling the Silent Process Exit monitoring feature.
3. Write to the registry again, this time under `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\lsass.exe`, the value is a `DWORD` with the name `ReportingMode` and the value of `2`, which instructs the OS to perform a full memory dump.
4. Set the value `LocalDumpFolder` under `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\lsass.exe` to point to a folder we'd like to dump the memory to, and set the value `DumpType` (which is a `DWORD`) to be `2` (local memory dump).
5. Call `ntdll!RtlReportSilentProcessExit`, which is an undocumented function that would report that a silent process exit should occur for a given process handle (`lsass.exe` in our case).

At that point, our dump file has been created at the folder we assigned, and we can delete all added registry entries.

## Shtinikering

Originally done by [Deep Instinct](https://www.deepinstinct.com/), this method requires running as `SYSTEM` (can be validated using the [GetTokenInformation API](https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation) if necessary).

Just as before, we fetch a handle to `lsass.exe` with either `OpenProcess` or duplication, and then dumps using [Windows Error Reporting (WER)](https://en.wikipedia.org/wiki/Windows_Error_Reporting)!

To do this, we report an exception to WER via [ALPC](https://en.wikipedia.org/wiki/Local_Inter-Process_Communication):

1. We get some thread of `lsass.exe` (can be done with the `CreateToolhelp32Snapshot` API) - and save its thread ID.
2. We create two events that we will pass to the ALPC message: a "recovery event" and a "completion event".
3. We create a memory-mapped file that will contain a structure that'd maintain exception information (requires writable memory). That structure contains information for WER, including the events that we created, as well as exception information, process ID, the failing thread ID and so on.
4. We make sure WER service starts using [Windows Notification Facility (WNF)](https://blog.trailofbits.com/2023/05/15/introducing-windows-notification-facilitys-wnf-code-integrity/) using `ntdll!NtUpdateWnfStateData` and `ntdll!EtwEventWriteNoRegistration`.
5. We wait for WER to be available using `ntdll!NtWaitForSingleObject` on `\KernelObjects\SystemErrorPortReady`.
6. We connect to ALPC port `\WindowsErrorReportingServicePort` via `ntdll!NtAlpcConnectPort` and then send to message via `ntdll!NtAlpcSendWaitReceivePort`.
7. The dump will be under `%LocalAppData%\CrashDumps` - we take the freshest dump.
