Add Kerberos TGS-REP and AS-REP prefix detection
Adds $krb5tgs$ (Kerberoasting) and $krb5asrep$ (AS-REP roasting) to PREFIX_RULES — both common in Active Directory attacks and emitted by Impacket/Rubeus in hashcat format. Includes matching tests for each prefix.
This commit is contained in:
parent
7822ef1d49
commit
87c8e2c003
|
|
@ -177,10 +177,26 @@ PREFIX_RULES: list[tuple[str, str, str]] = [
|
|||
("{SHA}", "LDAP SHA", "LDAP SHA-1 (base64 payload)"),
|
||||
("{SMD5}", "LDAP SMD5", "LDAP salted MD5 (base64 payload)"),
|
||||
("{MD5}", "LDAP MD5", "LDAP MD5 (base64 payload)"),
|
||||
|
||||
("{CRYPT}", "LDAP CRYPT", "LDAP wrapping a crypt(3) hash"),
|
||||
|
||||
# Kerberos — Active Directory attack hashes. Both are emitted by
|
||||
# Impacket's GetUserSPNs.py / GetNPUsers.py and Rubeus in
|
||||
# "hashcat" format. The digit right after the second `$` is the
|
||||
# Kerberos encryption type (23 = RC4, 17 = AES128, 18 = AES256)
|
||||
# and decides which hashcat -m mode to crack it with, but it does
|
||||
# not change WHAT the hash is, so we match on the prefix alone
|
||||
("$krb5tgs$", "Kerberos TGS-REP (Kerberoasting)",
|
||||
"service ticket hash from Kerberoasting; etype digit after $krb5tgs$ "
|
||||
"(23=RC4, 17/18=AES) picks the hashcat mode"),
|
||||
("$krb5asrep$", "Kerberos AS-REP (AS-REP Roasting)",
|
||||
"pre-auth-disabled account hash from AS-REP roasting; etype digit "
|
||||
"after $krb5asrep$ (23=RC4, 17/18=AES) picks the hashcat mode"),
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Length-and-hex rules — fallback when no prefix matched
|
||||
# =============================================================================
|
||||
|
|
|
|||
|
|
@ -141,6 +141,41 @@ def test_django_pbkdf2_prefix_is_recognized() -> None:
|
|||
assert candidates[0].algorithm == "Django PBKDF2-SHA256"
|
||||
|
||||
|
||||
def test_kerberos_tgs_prefix_is_recognized() -> None:
|
||||
"""
|
||||
Kerberoasting hashes start with `$krb5tgs$` and should be
|
||||
reported as a Kerberos TGS-REP with HIGH confidence
|
||||
|
||||
Sample is a real-shaped RC4 (`etype 23`) service ticket hash,
|
||||
the format Impacket's GetUserSPNs.py and Rubeus both emit.
|
||||
identify() never decodes the ticket payload, so a short
|
||||
fake tail after the two known `$`-delimited fields is enough
|
||||
"""
|
||||
# $krb5tgs$<etype>$*<user>$<realm>$<spn>*$<checksum>$<edata2>
|
||||
sample = "$krb5tgs$23$*user$REALM.COM$cifs/host.realm.com*$checksumhere$edata2here"
|
||||
candidates = identify(sample)
|
||||
assert candidates
|
||||
assert candidates[0].algorithm == "Kerberos TGS-REP (Kerberoasting)"
|
||||
assert candidates[0].confidence == "high"
|
||||
|
||||
|
||||
def test_kerberos_asrep_prefix_is_recognized() -> None:
|
||||
"""
|
||||
AS-REP roasting hashes start with `$krb5asrep$` and should be
|
||||
reported as a Kerberos AS-REP with HIGH confidence
|
||||
|
||||
Sample mirrors what Impacket's GetNPUsers.py and Rubeus's
|
||||
`asreproast` output for an account with Kerberos pre-auth
|
||||
disabled. As with TGS-REP, identify() only inspects the prefix
|
||||
"""
|
||||
# $krb5asrep$<etype>$<user>@<realm>:<checksum>$<edata2>
|
||||
sample = "$krb5asrep$23$user@REALM.COM:checksumhere$edata2here"
|
||||
candidates = identify(sample)
|
||||
assert candidates
|
||||
assert candidates[0].algorithm == "Kerberos AS-REP (AS-REP Roasting)"
|
||||
assert candidates[0].confidence == "high"
|
||||
|
||||
|
||||
def test_apr1_prefix_is_recognized() -> None:
|
||||
"""
|
||||
Apache `.htpasswd` MD5 hashes start with $apr1$
|
||||
|
|
|
|||
Loading…
Reference in New Issue