pass-the-hash to perform remote network authentication without needing the original password.
4 thoughts on “MD4 hash of the password”
$pwd = read-host -assecurestring -prompt “pwd”
new-localuser -name name -password $pwd
creating an instance of .NET System.Security.SecureString Class when read a secure string.
remove-localuser -name name
only removes the account; the deletion doesn’t guarantee that any
resources the user might have created will be removed. For this reason, the LSA should never
reuse a RID: that might allow a new user access to resources for a previous user account that was
deleted.
The runtime provides no guarantees that memory
buffer will be zeroed when it gets moved or freed.
The SecureString class
encrypts the string in memory and decrypts it only when it needs to be passed to native
code. The decrypted contents are stored in a native memory allocation, which allows the
caller to be sure that the value hasn’t been copied and can be zeroed before being
freed.
1️⃣ What is “native memory allocation”?
Native memory means memory managed outside the .NET garbage-collected heap — typically allocated by unmanaged Windows API functions (like LocalAlloc, HeapAlloc, or VirtualAlloc).
It’s “native” because it’s the same kind of memory you’d work with in C or C++, not managed by .NET’s automatic memory management.
SecureString uses native memory when holding the decrypted string so that:
.NET GC won’t move it around in memory (avoiding extra copies).
The program can directly control when and how the memory is erased and freed.
2️⃣ Why does this matter for security?
Normally in .NET, strings are immutable and live in the managed heap. This means:
You can’t change the contents after creation.
You can’t easily zero it out from memory when done.
Garbage collection may copy it around, leaving old copies of sensitive data in RAM.
With native memory allocation:
The decrypted password is never stored in the normal managed heap.
It’s stored in a fixed, unmanaged memory buffer that the developer can:
Zero out immediately after use (overwrite with zeros so it’s unrecoverable).
Free the memory as soon as possible.
This reduces the risk of the plaintext password lingering in memory where malware, a memory dump, or debugging tools could find it.
3️⃣ In plain English
When SecureString finally decrypts your password:
It puts it in a special, manually controlled memory area that isn’t managed by .NET’s garbage collector.
This lets the code guarantee two things:
No automatic copying happens behind the scenes.
It can wipe that memory clean immediately after use.
What actually happens in practice – RID
On a standalone machine, every time you create a new local account, Windows increments an internal counter to assign the next RID.
Deleted accounts’ RIDs are never recycled — the counter keeps going up.
On domain controllers, the same idea applies: the domain RID pool increments and never reuses an old one.
Reuse could only happen in extremely rare cases, such as:
Manual tampering with the SAM database or Active Directory.
RID counter reset due to backup restoration from a very old snapshot (dangerous!).
Wrap-around after the RID hits the maximum value (practically impossible — max is 2³²-1, meaning you’d have to create billions of accounts).
$pwd = read-host -assecurestring -prompt “pwd”
new-localuser -name name -password $pwd
creating an instance of .NET System.Security.SecureString Class when read a secure string.
remove-localuser -name name
only removes the account; the deletion doesn’t guarantee that any
resources the user might have created will be removed. For this reason, the LSA should never
reuse a RID: that might allow a new user access to resources for a previous user account that was
deleted.
The runtime provides no guarantees that memory
buffer will be zeroed when it gets moved or freed.
The SecureString class
encrypts the string in memory and decrypts it only when it needs to be passed to native
code. The decrypted contents are stored in a native memory allocation, which allows the
caller to be sure that the value hasn’t been copied and can be zeroed before being
freed.
1️⃣ What is “native memory allocation”?
Native memory means memory managed outside the .NET garbage-collected heap — typically allocated by unmanaged Windows API functions (like LocalAlloc, HeapAlloc, or VirtualAlloc).
It’s “native” because it’s the same kind of memory you’d work with in C or C++, not managed by .NET’s automatic memory management.
SecureString uses native memory when holding the decrypted string so that:
.NET GC won’t move it around in memory (avoiding extra copies).
The program can directly control when and how the memory is erased and freed.
2️⃣ Why does this matter for security?
Normally in .NET, strings are immutable and live in the managed heap. This means:
You can’t change the contents after creation.
You can’t easily zero it out from memory when done.
Garbage collection may copy it around, leaving old copies of sensitive data in RAM.
With native memory allocation:
The decrypted password is never stored in the normal managed heap.
It’s stored in a fixed, unmanaged memory buffer that the developer can:
Zero out immediately after use (overwrite with zeros so it’s unrecoverable).
Free the memory as soon as possible.
This reduces the risk of the plaintext password lingering in memory where malware, a memory dump, or debugging tools could find it.
3️⃣ In plain English
When SecureString finally decrypts your password:
It puts it in a special, manually controlled memory area that isn’t managed by .NET’s garbage collector.
This lets the code guarantee two things:
No automatic copying happens behind the scenes.
It can wipe that memory clean immediately after use.
What actually happens in practice – RID
On a standalone machine, every time you create a new local account, Windows increments an internal counter to assign the next RID.
Deleted accounts’ RIDs are never recycled — the counter keeps going up.
On domain controllers, the same idea applies: the domain RID pool increments and never reuses an old one.
Reuse could only happen in extremely rare cases, such as:
Manual tampering with the SAM database or Active Directory.
RID counter reset due to backup restoration from a very old snapshot (dangerous!).
Wrap-around after the RID hits the maximum value (practically impossible — max is 2³²-1, meaning you’d have to create billions of accounts).