Brazil - SMB3overKerberos (network)

When we investigate the PCAP, we notice many AS-REQ packets which is indicative of an AS-REP Roasting Attack.

The rough outline of kerberos authentication is:

  1. The client requests a TGT from the Authentication Server (AS) with an AS-REQ.

  2. The AS returns a message containing the TGT to the client in an AS-REP.

  3. The client saves the obtained TGT in the LSASS memory of the terminal.

  4. Because the cached TGT in memory proves that the client has been authenticated, the client sends a TGS-REQ to the server, including the information of the service to be used.

  5. The server returns data including the service session key to the client in a TGS-REP.

  6. The client uses the service session key and service session ID obtained from the TGSREP to access the desired service (e.g., SMB).

I used https://github.com/jalvarezz13/Krb5RoastParser to parse AS-REQ packets using the command

python krb5_roast_parser.py sample.pcap as_req

and cracked the hash via hashcat using

hashcat -m 19900 hashed.txt rockyou.txt

this allows us to find that the password for Charles@LAB.LOCAL is Passw0rd!

Now using Charles' credentials, we need to obtain the TGT session key from the AS-REP Packet (packet 103). The ciphertext is shown here:

Details on this encryption can be found at the following links: https://datatracker.ietf.org/doc/html/rfc3962 https://blog.redforce.io/windows-authentication-attacks-part-2-kerberos

Now we can use impacket for the decryption of the cipher, which gives us the session key:

from binascii import hexlify
from impacket.krb5.crypto import string_to_key, _enctype_table, Key
from binascii import unhexlify
from pyasn1.codec.der import decoder

etype = _enctype_table[18] # AES256-CTS-HMAC-SHA1-96
passphrase = "Passw0rd!"
realm = "LAB.LOCAL"
username = "Charles"
salt = realm + username
long_term_key = string_to_key(enctype=18, string=passphrase, salt=salt).contents.hex()
print(f"long term key: {long_term_key}")
key = Key(18, unhexlify(long_term_key))
ct = "bfa81e7d05853726903be6744875d1e0882d0d3e3c86e8710896a9d5dfccf38b6c44fd5915308e9dec96e9b786aa7da3092b28e033cc6fec883bfaa0fcf4d8fe71eb4e7144ca85e92e084a4bc7d51f75446bda880a21f52117af13a3628c481ca0fa7deef6645f8ec75566250fce5eb4694537aa3ce35c6c331a9fbb377e639c9212cb506c6d7729964e1b371df5c5ce364a6a68d52484e882b2436d1183c2a8879ba0bd72611998f30b6514f0af2f64a8d60ae5be369d5c223ecf79288689cbd16f4c297c2cf3775a9873f6b7326d9b3590ec68b3b7db41a9e1ab9d37f3ccb8af0e8bf5aeb67c531aefd28f3b2db7729b8400b33a286616a4c597930fcf1d66afd82e5f26ca43912868"
pt = etype.decrypt(key, 3, bytes.fromhex(ct)) # 3 refers to usage for AS-REP encrypted part
dec = decoder.decode(pt)
for i in dec:
    print(i)

The result is:

Sequence:
 field-0=Sequence:
  field-0=18
  field-1=0x09325be3bd041fe8a26024d029b46c80376ed00c42a5e54611d4126e109a4e7d
...

So the session key is 0x09325be3bd041fe8a26024d029b46c80376ed00c42a5e54611d4126e109a4e7d.

Now we need to obtain the service session key for from the TGS-REP packet which is packet 113.

We can decrypt this using the TGS Session Key we just obtained as follows:

from binascii import hexlify, unhexlify
from impacket.krb5.crypto import _enctype_table, Key
from pyasn1.codec.der import decoder
from impacket.krb5.asn1 import EncTGSRepPart

tgs_cipher = "fcf9dd13884739cafa73ae43f14caf29cbd1ecc3fa5192c938b80ecf302980a52506323854bf85dc367256f746b5338acc0750aeb29215bfd7fd273df8cd170f964f301eec37e98754cb91c8bc669ccac419ec664fca8e295c1cdc66177e8ff734d94a667e0f7f1b283bed16641ea8742b067b59a0072664d1cb5d3ca8ffe69c994d0638c2ad40d116252a567c33d2c516b8d5be59b0b7528340e8b1f258ea5db054a73527fe4cf8ccb403e5c2cef7152e34a78057cc8f7483ca56b6ee6a87c9118e37062436af4f2994258259f4eed17f507dd17739afb743839efdc8aed2b616a390b3a262f64611a9c8680e3456579a89ff23"
tgt_session_key = "09325be3bd041fe8a26024d029b46c80376ed00c42a5e54611d4126e109a4e7d"
etype = 18
ciphertext = unhexlify(tgs_cipher)
key = Key(etype, unhexlify(tgt_session_key))
# 8: usage for TGS-REP encrypted part, encrypted with TGS session key
plaintext = _enctype_table[etype].decrypt(key, 8, ciphertext)
decoded, _ = decoder.decode(plaintext, asn1Spec=EncTGSRepPart())
svc_key = decoded['key']
print("service session key:", hexlify(bytes(svc_key['keyvalue'])).decode())

The session key we get is fa1a501f6828025cc5feb7dfe1968de4. Recall that we need both service session key and service session id to decrypt the encrypted SMB3 packets. We can get the service session id from packet 119 where the SMB session was established.

To decrypt the smb traffic, in Wireshark, go to Edit > Preference > Protocols > SMB2, select Edit in Secret session keys for decryption, and enter the service session ID and service session key. Note that the Session ID obtained above was 0x0000bc000000003d, but endian conversion is required when entering it from Wireshark settings. Service Session ID: 3d00000000bc0000 Service Session Key: fa1a501f6828025cc5feb7dfe1968de4

Now we can go to the read response to the read request for flag.txt and view the decrypted smb response, thus obtaining the flag: CSG_FLAG{Nothing_escapes_my_sight!}

Last updated