Kerberos
High-Level
Scapy provides several high-level utilities related to Kerberos:
Ticketer
: a module that allows manipulating Kerberos tickets: - Request TGT/ST - Generate aKerberosSSP
from a ST - Renew tickets - Read, create, write ccache files - Read, create, write keytab files - Kerberos armoring (via FAST) is available - S4U2Self / S4U2Proxy are implemented - KPasswd is implementedKerberosSSP
: an implementation of a GSSAPI SSP for Kerberos, usable in any of Scapy’s client that support GSSAPI. - Encryption/MIC using GSSAPI is available - Channel bindings are supported - U2U (User-To-User) is fully supported - [MS-KKDCP] (KDC proxy) is supported
Ticketer module
The Ticketer module can be used both from the CLI or programmatically. This section tries to give many usage examples of features that are available. For more detail regarding the parameters of the functions, it is encouraged to have a look at their docstrings.
Request TGT:
>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.request_tgt("Administrator@DOMAIN.LOCAL")
Enter password: ************
>>> t.show()
Tickets:
0. Administrator@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
Start time End time Renew until Auth time
31/08/23 11:38:34 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34
Then request a ST, using the TGT:
>>> # The TGT we just got has an ID of 0
>>> t.request_st(0, "host/dc1.domain.local")
>>> t.show()
Tickets:
0. Administrator@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
Start time End time Renew until Auth time
31/08/23 11:38:34 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34
1. Administrator@DOMAIN.LOCAL -> host/dc1.domain.local@DOMAIN.LOCAL
Start time End time Renew until Auth time
31/08/23 11:39:07 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34
Use ticket as SSP: the
.ssp()
function.
>>> # We use ticket 1 from the above store.
>>> smbclient("dc1.domain.local", ssp=t.ssp(1))
Renew a TGT or ST:
>>> t.renew(0) # renew TGT
>>> t.renew(1) # renew ST. Works only with 'host/' SPNs
Import tickets from a ccache:
Note
We first added a realm DOMAIN.LOCAL
with a kdc to /etc/krb5.conf
$ kinit Administrator@DOMAIN.LOCAL
Password for Administrator@DOMAIN.LOCAL:
$ scapy
>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.open_ccache("/tmp/krb5cc_1000")
>>> t.show()
Tickets:
1. Administrator@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
Start time End time Renew until Auth time
31/08/23 12:08:15 31/08/23 22:08:15 01/09/23 12:08:12 31/08/23 12:08:15
Export tickets into a ccache:
>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.request_tgt("Administrator@domain.local", password="ScapyScapy1")
>>> t.save("/tmp/krb5cc_1000")
>>> exit()
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: Administrator@DOMAIN.LOCAL
Valid starting Expires Service principal
08/31/2023 12:08:15 08/31/2023 23:08:15 krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
renew until 09/01/2023 12:08:12
Perform S4U2Self
>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.request_tgt("SERVER1$@domain.local", key=Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, bytes.fromhex("63a2577d8bf6abeba0847cded36b9aed202c23750eb9c56b6155be1cc946bb1d")))
>>> t.request_st(0, "host/SERVER1", for_user="Administrator@domain.local")
>>> t.show()
CCache tickets:
0. SERVER1$@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
canonicalize+pre-authent+initial+renewable+forwardable
Start time End time Renew until Auth time
15/04/25 20:15:17 16/04/25 06:10:22 16/04/25 06:10:22 15/04/25 20:15:17
1. Administrator@domain.local -> host/SERVER1@DOMAIN.LOCAL
canonicalize+pre-authent+renewable+forwardable
Start time End time Renew until Auth time
15/04/25 20:15:20 16/04/25 06:10:22 16/04/25 06:10:22 15/04/25 20:15:17
Load and use keytab for client
>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.open_keytab("test.keytab")
>>> t.show()
Keytab name: test.keytab
Principal Timestamp KVNO Keytype
Administrator@domain.local 14/04/25 21:47:59 0 AES128-CTS-HMAC-SHA1-96
Administrator@domain.local 14/04/25 21:47:59 0 AES256-CTS-HMAC-SHA1-96
Administrator@domain.local 14/04/25 21:47:59 0 RC4-HMAC
No tickets in CCache.
>>> t.request_tgt("Administrator@domain.local")
Load and use keytab for server:
>>> t.open_keytab("server1.keytab")
>>> t.show()
Keytab name: server1.keytab
Principal Timestamp KVNO Keytype
host/Server1.domain.local@DOMAIN.LOCAL 01/01/70 01:00:00 10 RC4-HMAC
No tickets in CCache.
>>> ssp = t.ssp("host/Server11.domain.local@DOMAIN.LOCAL")
>>> # Example: start a SMB server
>>> smbserver(ssp=ssp)
Create client keytab:
>>> t = Ticketer()
>>> t.add_cred("Administrator@domain.local", etypes="all")
Enter password: ************
>>> t.show()
Keytab name: UNSAVED
Principal Timestamp KVNO Keytype
Administrator@domain.local 15/04/25 20:24:13 1 AES128-CTS-HMAC-SHA1-96
Administrator@domain.local 15/04/25 20:24:13 2 AES256-CTS-HMAC-SHA1-96
Administrator@domain.local 15/04/25 20:24:13 3 RC4-HMAC
No tickets in CCache.
Change password using kpasswd in ‘set’ mode:
>>> t = Ticketer()
>>> t.request_tgt("Administrator@domain.local")
Enter password: ************
>>> t.kpasswdset(0, "SERVER1$@domain.local")
INFO: Using 'Set Password' mode. This only works with admin privileges.
Enter NEW password: ***********
Craft tickets: We can start by showing how to craft a golden ticket:
>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.create_ticket()
User [User]: Administrator
Domain [DOM.LOCAL]: DOMAIN.LOCAL
Domain SID [S-1-5-21-1-2-3]: S-1-5-21-4239584752-1119503303-314831486
Group IDs [513, 512, 520, 518, 519]: 512, 520, 513, 519, 518
User ID [500]: 500
Primary Group ID [513]:
Extra SIDs [] :S-1-18-1
Expires in (h) [10]:
What key should we use (AES128-CTS-HMAC-SHA1-96/AES256-CTS-HMAC-SHA1-96/RC4-HMAC) ? [AES256-CTS-HMAC-SHA1-96]:
Enter the NT hash (AES-256) for this ticket (as hex): 6df5a9a90cb076f4d232a123d9c24f46ae11590a5430710bc1881dca337989ce
>>> t.show()
Tickets:
0. Administrator@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
>>> t.save(fname="blob.ccache")
Edit tickets with the GUI
Let’s assume you’ve acquired the KRBTGT of a KDC, plus you’ve used kinit
to get a ticket.
This ticket was saved to a .ccache
file, that we’ll know try to open.
Note
You can get the demo ccache file using the following
cat <<EOF | base64 -d > krb.ccache
BQQADAABAAj/////AAAAAAAAAAEAAAABAAAADERPTUFJTi5MT0NBTAAAAA1BZG1pbmlzdHJhdG9y
AAAAAQAAAAEAAAAMRE9NQUlOLkxPQ0FMAAAADUFkbWluaXN0cmF0b3IAAAACAAAAAgAAAAxET01B
SU4uTE9DQUwAAAAGa3JidGd0AAAADERPTUFJTi5MT0NBTAASAAAAIItCJqGQhmy+NFrl5miCPt1T
WcsAvUeaZCi8j+sbpVdSYzMy+mMzMvpjM7+aYzSEdwBQ4QAAAAAAAAAAAAAAAARIYYIERDCCBECg
AwIBBaEOGwxET01BSU4uTE9DQUyiITAfoAMCAQKhGDAWGwZrcmJ0Z3QbDERPTUFJTi5MT0NBTKOC
BAQwggQAoAMCARKhAwIBAqKCA/IEggPuZiwq78yj+MeN444a8dY7GN4BHYZNm+wS88EeILC73Ebm
9cgxGzMbHMJ7Ixk+kPpHunqmpn+6WCah9HVOpQUO6rLgfQej7BApsqEeBYzjHkj03ivOAX6cKRXu
QP+g9xCVlwiChvopD+bKd3RlFixXV6Z8xTqOMgSEakypz/MMgHPR6ec1tesicX+Xd8Lzj7E9IElS
2xXk8WDiZTX1lvPOZPmo2WARcY0EBWUNf3xyj4fdLQ4iDkYQNH+qikUJm2OjUfWtz8z2adm2ES4x
iBr4aVYSlKIetuKxZLjObGx7AyfsbHHCN4SwbBkDCj+BEZ83fLbwOVtUd7/7xcGiJk7Er3b0s5pO
L3Aw1IyOu8ryEgNuoKWr3V2pH83D+5cA1TefA/vJ/jpHB42uMLBaQY9G7p6iX1IOt+Z7U9lvf0hu
WHiyLqj0IVE3p9z39Lb1BGNxXZ08VE8pRCDtD3QmlV+gpSfvzoYmT3wpvfws7iw+sifrS3ZR64AI
4OsmlEakVIgpawQn+CuVmtBwFGzYqa7Z7yNoFb0hSfP4bXMidYTylNyGz0p35O6r+Y9PNC2/xL60
bYNLDDED2MWWTK1IUu7TZcqOUJN+IZdhItXN4Yxatt1VKMOmgMCiGXEXZt1bajwQOuZa1fVzoxVD
oOvO/eF0kGKVEDD2OQfN4JIBDCLJB2MkjJ9s0DpvCny5p7dEG8feTEDB10k3Ov7ll6Usnb51M9e6
JKOibfKUdLk2Q+7Zf2uP/ROXaGmESEG902TyRU1uPOGuZ37AHFksJbUOEgMDJA3arILfqdY7HELC
ObeKbE67orZFi5JJMcUrIjucnP1s8PCD5iOeMHR/EwLei96U/odWteARj17WHczDhi3byT8QPDFg
rBWFjL4zBCDW4H4snyQsLK+PBNg/PNcfQEwdVoFMniqnh3Y6vClTNCmUh/RU5LTrXw58PPXjdzdK
z4J8n+JV4cfNsTEp7wfHMRZO5O7VA/c1gpqLfMLjcY2yPYWDj796Q4YaHI+JDkwzQ3tldJlGtG9s
/xdnFY9WhLA18uoIb3tWT2pXBQcUtMrVFltyvm96aCCy6fiTZQYUfmSnei+c+cE/5P1ZuDGRiYEB
BooAPm9/kYAGYWIE/0sYqb9JVJe6DfDfy7iaXmQ8YGN2ZzV/zx2XtCQkDqdfzw0muxWQVRB/gNG8
aCyQV/IqPvX7D1CtswupdbJQadOTv36yUi8jCRKsHmS7qTyRqnYKuxIJuxMT443d68rDJdJ775nW
YEXAl5m3ECCkT2S7tZxAVEkwT9lbjWvcbRfkdsuhiPMK0Eu2yR2RsCiwlTmGkpqftCsh9zAoyLof
QWxwYwAAAAAAAAABAAAAAQAAAAxET01BSU4uTE9DQUwAAAANQWRtaW5pc3RyYXRvcgAAAAAAAAAD
AAAADFgtQ0FDSEVDT05GOgAAABVrcmI1X2NjYWNoZV9jb25mX2RhdGEAAAAHcGFfdHlwZQAAACBr
cmJ0Z3QvRE9NQUlOLkxPQ0FMQERPTUFJTi5MT0NBTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAATIAAAAA
EOF
>>> load_module("ticketer")
>>> t = Ticketer()
>>> t.open_ccache("krb.ccache")
>>> t.show()
Tickets:
1. Administrator@DOMAIN.LOCAL -> krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL
>>> t.edit_ticket(0)
Enter the NT hash (AES-256) for this ticket (as hex): 6df5a9a90cb076f4d232a123d9c24f46ae11590a5430710bc1881dca337989ce
>>> t.resign_ticket(0)
>>> t.save()
1660
>>> # Other stuff you can do
>>> tkt = t.dec_ticket(0)
>>> tkt
<EncTicketPart flags=forwardable, proxiable, renewable, .........>
>>> t.update_ticket(0, tkt)

Note
Remember to call resign_ticket
to update the Server and KDC checksums in the PAC.
Cheat sheet
Command |
Description |
---|---|
|
Load ticketer++ |
|
Create a Ticketer object |
|
Open a ccache file |
|
Save a ccache file |
|
List the tickets |
|
Forge a ticket |
|
Decipher a ticket |
|
Re-inject a deciphered ticket |
|
Edit a ticket (GUI) |
|
Resign a ticket |
|
Request a TGT |
|
Request a ST using ticket i |
|
Renew a TGT/ST |
Other useful commands
To change your own password, you can use the plain kpasswd
command from scapy.layers.kerberos
.
>>> kpasswd("User1@domain.local")
Enter password: **********
Enter NEW password: *********
To change the password of someone else, you can also the following. You need to have the rights to do so. You can also use the method from Scapy’s Ticketer.
>>> kpasswd("Administrator@domain.local", "User1@domain.local")
Enter password: **********
Enter NEW password: *********
Inner-workings
Behind the scenes, Scapy includes a (tiny) kerberos client, that has basic functionalities such as:
AS-REQ
Note
Full doc at krb_as_req()
. krb_as_req
actually calls a Scapy automaton that has the following behavior:

>>> res = krb_as_req("user1@DOMAIN.LOCAL", password="Password1")
This is what it looks like with wireshark:

The result is a named tuple with both the full AP-REP and the decrypted session key:
>>> res.asrep.show()
###[ KRB_AS_REP ]###
pvno = 0x5 <ASN1_INTEGER[5]>
msgType = 'AS-REP' 0xb <ASN1_INTEGER[11]>
\padata \
|###[ PADATA ]###
| padataType= 'PA-ETYPE-INFO2' 0x13 <ASN1_INTEGER[19]>
| \padataValue\
| |###[ ETYPE_INFO2 ]###
| | \seq \
| | |###[ ETYPE_INFO_ENTRY2 ]###
| | | etype = 'AES-256' 0x12 <ASN1_INTEGER[18]>
| | | salt = <ASN1_GENERAL_STRING[b'DOMAIN.LOCALuser1']>
| | | s2kparams = None
crealm = <ASN1_GENERAL_STRING[b'DOMAIN.LOCAL']>
[...]
>>> res.sessionkey.toKey()
<Key 18 (32 octets)>
Some more examples:
Enforce RC4:
>>> from scapy.libs.rfc3961 import EncryptionType
>>> res = krb_as_req("user1@DOMAIN.LOCAL", etypes=[EncryptionType.RC4_HMAC])
Ask for a DES_CBC_MD5 sessionkey:
>>> from scapy.libs.rfc3961 import EncryptionType
>>> res = krb_as_req("user1@DOMAIN.LOCAL", etypes=[EncryptionType.DES_CBC_MD5, EncryptionType.RC4_HMAC])
TGS-REQ
Note
Full doc at krb_tgs_req()
. krb_tgs_req
actually calls a Scapy automaton.
Ask for a ST:
Let’s reuse the TGT and session key we got in the AS-REQ:
>>> krb_tgs_req("user1@DOMAIN.LOCAL", "host/DC1", sessionkey=res.sessionkey, ticket=res.asrep.ticket)
Note
There is also a krb_as_and_tgs()
function that does an AS-REQ then a TGS-REQ:
>>> krb_as_and_tgs("user1@DOMAIN.LOCAL", "host/DC1", password="Password1")
Other things you can do:
Renew a TGT:
>>> krb_tgs_req("user1@DOMAIN.LOCAL", "krbtgt/DOMAIN.LOCAL", sessionkey=res.sessionkey, ticket=res.asrep.ticket, renew=True)
Renew a ST:
Note
For some mysterious reason, this is rarely implemented in other tools.
>>> res2 = krb_tgs_req("user1@DOMAIN.LOCAL", "host/DC1", sessionkey=res.sessionkey, ticket=res.asrep.ticket)
>>> krb_tgs_req("user1@DOMAIN.LOCAL", "host/DC1", sessionkey=res2.sessionkey, ticket=res2.tgsrep.ticket, renew=True)
KerberosSSP
For Kerberos, the Scapy SSP is implemented in KerberosSSP
.
You can typically use it in SMB_Client
, SMB_Server
, DCERPC_Client
or DCERPC_Server
.
Note
Remember that you can wrap it in a SPNEGOSSP
Low-level
Decrypt kerberos packets
Kerberos packets contain encrypted content, let’s take the following packet:
>>> pkt = Ether(b"RT\x00iX\x13RT\x00!l+\x08\x00E\x00\x01]\xa7\x18@\x00\x80\x06\xdc\x83\xc0\xa8z\x9c\xc0\xa8z\x11\xc2\t\x00XT\xf6\xab#\x92\xc2[\xd6P\x18 \x14\xb6\xe0\x00\x00\x00\x00\x011j\x82\x01-0\x82\x01)\xa1\x03\x02\x01\x05\xa2\x03\x02\x01\n\xa3c0a0L\xa1\x03\x02\x01\x02\xa2E\x04C0A\xa0\x03\x02\x01\x12\xa2:\x048HHM\xec\xb0\x1c\x9bb\xa1\xca\xbf\xbc?-\x1e\xd8Z\xa5\xe0\x93\xba\x83X\xa8\xce\xa3MC\x93\xaf\x93\xbf!\x1e'O\xa5\x8e\x81Hx\xdb\x9f\rz(\xd9Ns'f\r\xb4\xf3pK0\x11\xa1\x04\x02\x02\x00\x80\xa2\t\x04\x070\x05\xa0\x03\x01\x01\xff\xa4\x81\xb70\x81\xb4\xa0\x07\x03\x05\x00@\x81\x00\x10\xa1\x120\x10\xa0\x03\x02\x01\x01\xa1\t0\x07\x1b\x05win1$\xa2\x0e\x1b\x0cDOMAIN.LOCAL\xa3!0\x1f\xa0\x03\x02\x01\x02\xa1\x180\x16\x1b\x06krbtgt\x1b\x0cDOMAIN.LOCAL\xa5\x11\x18\x0f20370913024805Z\xa6\x11\x18\x0f20370913024805Z\xa7\x06\x02\x04p\x1c\xc5\xd1\xa8\x150\x13\x02\x01\x12\x02\x01\x11\x02\x01\x17\x02\x01\x18\x02\x02\xffy\x02\x01\x03\xa9\x1d0\x1b0\x19\xa0\x03\x02\x01\x14\xa1\x12\x04\x10WIN1 ")
>>> pkt[TCP].payload.show()
###[ KerberosTCPHeader ]###
len = 305
###[ Kerberos ]###
\root \
|###[ KRB_AS_REQ ]###
| pvno = 0x5 <ASN1_INTEGER[5]>
| msgType = 'AS-REQ' 0xa <ASN1_INTEGER[10]>
| \padata \
| |###[ PADATA ]###
| | padataType= 'PA-ENC-TIMESTAMP' 0x2 <ASN1_INTEGER[2]>
| | \padataValue\
| | |###[ EncryptedData ]###
| | | etype = 'AES-256' 0x12 <ASN1_INTEGER[18]>
| | | kvno = None
| | | cipher = <ASN1_STRING[b"HHM\xec\xb0\x1c\x9bb\xa1\xca\xbf\xbc?-\x1e\xd8Z\xa5\xe0\x93\xba\x83X\xa8\xce\xa3MC\x93\xaf\x93\xbf!\x1e'O\xa5\x8e\x81Hx\xdb\x9f\rz(\xd9Ns'f\r\xb4\xf3pK"]>
| |###[ PADATA ]###
| | padataType= 'PA-PAC-REQUEST' 0x80 <ASN1_INTEGER[128]>
| | \padataValue\
| | |###[ PA_PAC_REQUEST ]###
| | | includePac= True <ASN1_BOOLEAN[-1]>
| \reqBody \
| |###[ KRB_KDC_REQ_BODY ]###
| | kdcOptions= forwardable, renewable, canonicalize, renewable-ok <ASN1_BIT_STRING[0100000010...0000010000]=b'@\x81\x00\x10' (0 unused bit)>
| | \cname \
| | |###[ PrincipalName ]###
| | | nameType = 'NT-PRINCIPAL' 0x1 <ASN1_INTEGER[1]>
| | | nameString= [<ASN1_GENERAL_STRING[b'win1$']>]
| | realm = <ASN1_GENERAL_STRING[b'DOMAIN.LOCAL']>
| | \sname \
| | |###[ PrincipalName ]###
| | | nameType = 'NT-SRV-INST' 0x2 <ASN1_INTEGER[2]>
| | | nameString= [<ASN1_GENERAL_STRING[b'krbtgt']>, <ASN1_GENERAL_STRING[b'DOMAIN.LOCAL']>]
| | from = None
| | till = 2037-09-13 02:48:05 UTC <ASN1_GENERALIZED_TIME['20370913024805Z']>
| | rtime = 2037-09-13 02:48:05 UTC <ASN1_GENERALIZED_TIME['20370913024805Z']>
| | nonce = 0x701cc5d1 <ASN1_INTEGER[1880933841]>
| | etype = [0x12 <ASN1_INTEGER[18]>, 0x11 <ASN1_INTEGER[17]>, 0x17 <ASN1_INTEGER[23]>, 0x18 <ASN1_INTEGER[24]>, -0x87 <ASN1_INTEGER[-135]>, 0x3 <ASN1_INTEGER[3]>]
| | \addresses \
| | |###[ HostAddress ]###
| | | addrType = 'NetBios' 0x14 <ASN1_INTEGER[20]>
| | | address = <ASN1_STRING[b'WIN1 ']>
| | encAuthorizationData= None
| | additionalTickets= None
You likely want to decrypt pkt.root.padata[0].padataValue
which is an EncryptedData
packet. To do so, we need the Key
class.
>>> from scapy.libs.rfc3961 import Key, EncryptionType
>>> enc = pkt[Kerberos].root.padata[0].padataValue
>>> k = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=bytes.fromhex("7fada4e566ae4fb270e2800a23ae87127a819d42e69b5e22de0ddc63da80096d"))
The first parameter of the Key
constructor is a value from EncryptionType
, in this case EncryptionType.AES256_CTS_HMAC_SHA1_96
. This is the same value than enc.etype.val
, which allows to know which key to use.
We can then proceed to perform the decryption:
>>> enc.decrypt(k)
<PA_ENC_TS_ENC patimestamp=2022-07-15 17:18:47 UTC <ASN1_GENERALIZED_TIME['20220715171847Z']> pausec=0x9a4db <ASN1_INTEGER[632027]> |>
Compute Kerberos keys
Note
Encryption for Kerberos 5 is defined in RFC3961
You may want to compute a Kerberos key from a password + salt. There is an API for that described in RFC3961 as “string-to-key”. Our implementation is a class method as follow:
- Key.string_to_key(etype, string, salt, params=None)
Compute the kerberos key for a certain encryption type.
- Parameters:
etype (int) – The EncryptionType to use. May be any value from
EncryptionType
string (bytes) – The “string” bytes to use. This is the user password in almost all well-used cases. They must be passed as bytes.
salt (bytes) – The salt bytes to use. What value to use depends if you are considering a MACHINE account or a USER account, for the latter, it’s just
the concatenation of the principal's realm and name components, in order, with no separators.
(RFC4120 sect 4)params (bytes) – The opaque “parameter” used by string-to-key. The RFC defines this field in a very general manner but it is basically only used in AES, in which it is the iteration count as a big-endian int (
struct.pack(">L", 4096)
by default)
Let’s run a few examples:
>>> # Get the AES256 key for User1@DOMAIN.LOCAL with "Password1"
>>> from scapy.libs.rfc3961 import Key, EncryptionType
>>> Key.string_to_key(EncryptionType.AES256_CTS_HMAC_SHA1_96, b"Password1", b"DOMAIN.LOCALUser1")
>>> print(_.key)
b'm\x07H\xc5F\xf4\xe9\x92\x05\xe7\x8f\x8d\xa7h\x1dN\xc5R\n\xe4\x81UCr\x0c*d|\x1a\xe8\x14\xc9'
Note
The following example is from https://datatracker.ietf.org/doc/html/rfc3962#appendix-B
>>> # Get the AES128 key for raeburn@ATHENA.MIT.EDU with "password", with an iteration count of 1200
>>> k = Key.string_to_key(EncryptionType.AES128_CTS_HMAC_SHA1_96, b"password", b"ATHENA.MIT.EDUraeburn", struct.pack(">L", 1200))
>>> print(k.key.hex())
'4c01cd46d632d01e6dbe230a01ed642a'
Decrypt FAST
Note
Have a look at RFC6113 for Kerberos FAST
Let’s take a Kerberos AS-REQ packet with FAST armoring (RFC6113):

FAST armoring in AS-REQ. Credit to this paper by A. Bordes.
>>> pkt = Ether(bytes.fromhex(b'52540013d0835254003ea3be08004502089636a1400080063ad3c0a87fd2c0a87fc8fecc0058eea93069573b278e50180402897400000000086a6a82086630820862a103020105a20302010aa38207a23082079e3082079aa10402020088a28207900482078ca082078830820784a082064a30820646a003020101a182063d048206396e82063530820631a003020105a10302010ea20703050000000000a38205796182057530820571a003020105a10c1b0a444f4d312e4c4f43414ca21f301da003020102a11630141b066b72627467741b0a444f4d312e4c4f43414ca382053930820535a003020112a103020102a282052704820523acc8b7671c0d50522f1a8d8452ce450aceb40fff0229e8ee546bccf1512e4877ef93dde465595260a6a5a8e85ea38600ce8dff7d510f3c744e2c43eb9d3187d638f716c29b6e7aa9eb407de28d0161f49013966eda0a161ff174dad42e7aa500cfe298541215448013ffe4883b6b1166f908f50de129487fe77fff874fd4102cdcce8db8dbeb8da02f08cc88b3790cdad5ec499959c7e79d6fef107d1e17ce80cc3df050b7e7a1c31f278e4fd4ea9523c950876f174be363234f8495b9550de1560ba17daeafbf133f78991053d929ad3fd668327d42288e6581671daaef908682ee282e17c31d8f8bb55d27fce155ee2e84a2ff8bc9600891be15e6ede3e1bbd2742a7af8b0a32c48973c9e3776a69647bab11592756c5a15b9101c392efa35d000abb3dabccd97e64426e3fd8d47e0e369c83b5391f38947d536d351c061081d654eef1a3861cdb2ea2bc48222b450d1b7d09c0670493bccc60dfcaa5cfe46fd50adf8e388204a4691dc5f0c3dbae0b4da6ac2dd781f149a444840aaa3a3c3befb5a5c04ee0405baed66afcf9b988d10ea14a955f43df79465e6fc02a12bce3870988950f1ab48e1a4f876f351671c5061e6399a63cb0479f7bd017dfd9bc5be192faf6d4f11e6ee6003933eeaf632f0056c4c1ccd183d7977cfca85419fe5b039674419d802068e792c9576ae2a88bfbeb1f59273226782c6efb288717d8f7a4bc3bf4c697fcac1adc1829f0a914f2559b278ccadd108eb87a11dacc88e4302e9af627474e57171192b94c6b358f8f98e308596215d2fb9d9c2b49c4cbedcb43fc231b86f0493d56b82962cf3383a84f8922c2b99f8fa8fdd85797b09a6e60f72007c0379988be2ff1cfc16f21300c1b4b784174005a9185f760e68ef94b9384eb24decee31b63d1b92278cd75b85d4d80c4e83306533a9d95aa6207cbfbeb0970a41c44aba59839f007923ecd8ff0de8314990a435dbea4dedbee16faf5ab2be9f96d691cfa983a6c843bd183f84c1b4998a3eaa907cae6b82b0ae8363f3edd8cb03d3c9c60ff55a84d8a292ea20555fbd6ce5ad4ad7a6b4bc5bff2e02c477a7a8a98d5a387d389caa172c400b151d95871b2aa16a040dc71a9be5f0774b06a5ca87674ccb4109a2c41db9e3160704218ad495d0751194fbef4becae4d7be24b9d968da592256a2b22cf724e989e71a60d0603b59bebd475285f793794b7a18af49a2b68670e3a6247c453274e35c863a16b5023c6c94659e25abb27c760f989ac0bbf9a5b125d0ea34fb03225cc93d5b8b6829e906883ee76cf8ee61dfacc488e8dc5cbc8ba9705a9e915a68f838232394f97fb1aac4a2a90fe17d46f9c51946a2bf9598df7f5b5e7ee692a78860eea3cef748a5be36529228e40b4aec83ebc8bb14176a4c565b06500e9517229b8340c55812101dbbc6bee693c35873082a5a1a53b35cf3509193d4dc5175c9360a00da71692ba205b3264aecc9ecc8bca31fec43efc8701423bb484f6f21699439dd30f71228f16eaab96b7de3547721d1635bbfe50678900ac378a4958b6c34964f3e0dc843880dbde57fb4a76ab85eba2b190bfdaefc7ba17e109f839493b0f2d6fc7ea17403bebe06f2809314ca514606f54668082364ed6752019f27e1df74f93fcf1c25630a29713a89d4a998c444bc91279c6fc66e0aa5dec72be316e1160cf9f90d5915c464b6bfec5216e901be4726db596a15745511c63736a69ac9ecb9e86601c631b4992653c320e6983562fa613134560cb606621e9661ac5961313ee70868ab48d6010173d8a96fffdb2baf4afe18c846d3fed6f30b9a809d72e647735fc536edec543abc232480d28660395a4819e30819ba003020112a281930481901273d5af61ad426d51d0757e897917caeb6fc1b6950554e8d750f95d27f444e3aaf7ae0bf4595b5e906d9682dbdeedcf6eb42a84ab8092997b783f57710127228165deeb2ce5e09e2ddc71555dc31970a8312d888b8ae766382098276d62b4bd76f34cbc889e24ad5405ec037ceb724fdb71fe247fe2a414a037ed33c796f4475fcfb5993eed147b6d63d740d58da5b0a1173015a003020110a10e040c75f02d8d2954e0ae1a9e0653a282011930820115a003020112a282010c04820108ae9bbc4629c80f4a383a69c4583824295c75f34b000b3fdbdaab073a042935e32c29e0ee2b2b446e4a6a2592362d0d593cddd74dacc24f16353776e1b5d192ad1cf5e63f66f40a134ecb87c077c30922bc0cab00ae23d187d56090d9098f843c54fabe7c012ff87e317dfe339c40911264609d489b041a4e9b52c0eb03ee88a393d17da92786bd1716b92eb0d7a5a24a64ade0870dea8a7e138acdf209ee277cb3fadeedab173fd64cc10a1004010774658b94852639bda10a5e8aff29174e3d2c7032c32631b074afdac0e6832bae74de9be19e522f63bc8499753a209291fee1861c29096cc8ee3cfda5be235b0aa95635916edcfcdaf90b896e2eaa5a57d5e4da0b00408f4201a481af3081aca00703050040810010a11a3018a003020101a111300f1b0d61646d2d302d66617374656e62a2061b04444f4d31a3193017a003020102a110300e1b066b72627467741b04444f4d31a511180f32303337303931333032343830355aa611180f32303337303931333032343830355aa70602043f58a7a0a81530130201120201110201170201180202ff79020103a91d301b3019a003020114a112041053525620202020202020202020202020'))
>>> pkt[TCP].payload.show()
###[ KerberosTCPHeader ]###
len = 2154
###[ Kerberos ]###
\root \
|###[ KRB_AS_REQ ]###
| pvno = 0x5 <ASN1_INTEGER[5]>
| msgType = 'AS-REQ' 0xa <ASN1_INTEGER[10]>
| \padata \
| |###[ PADATA ]###
| | padataType= 'PA-FX-FAST' 0x88 <ASN1_INTEGER[136]>
| | \padataValue\
| | |###[ PA_FX_FAST_REQUEST ]###
| | | \armoredData\
| | | |###[ KrbFastArmoredReq ]###
| | | | \armor \
| | | | |###[ KrbFastArmor ]###
| | | | | armorType = 'FX_FAST_ARMOR_AP_REQUEST' 0x1 <ASN1_INTEGER[1]>
| | | | | \armorValue\
| | | | | |###[ KRB_AP_REQ ]###
| | | | | | pvno = 0x5 <ASN1_INTEGER[5]>
| | | | | | msgType = 'AP-REQ' 0xe <ASN1_INTEGER[14]>
| | | | | | apOptions = <ASN1_BIT_STRING[0000000000...0000000000]=b'\x00\x00\x00\x00' (0 unused bit)>
| | | | | | \ticket \
| | | | | | |###[ KRB_Ticket ]###
| | | | | | | tktVno = 0x5 <ASN1_INTEGER[5]>
| | | | | | | realm = <ASN1_GENERAL_STRING[b'DOM1.LOCAL']>
| | | | | | | \sname \
| | | | | | | |###[ PrincipalName ]###
| | | | | | | | nameType = 'NT-SRV-INST' 0x2 <ASN1_INTEGER[2]>
| | | | | | | | nameString= [<ASN1_GENERAL_STRING[b'krbtgt']>, <ASN1_GENERAL_STRING[b'DOM1.LOCAL']>]
| | | | | | | \encPart \
| | | | | | | |###[ EncryptedData ]###
| | | | | | | | etype = 'AES-256' 0x12 <ASN1_INTEGER[18]>
| | | | | | | | kvno = 0x2 <ASN1_INTEGER[2]>
| | | | | | | | cipher = <ASN1_STRING[b'\xac\xc8\xb7g\x1c\rPR/\x1a\x8d\x84R\xceE\n\xce\xb4\x0f\xff\x02)\xe8\xeeTk\xcc\xf1Q.Hw\xef\x93\xdd\xe4eYR`\xa6\xa5\xa8\xe8^\xa3\x86\x00\xce\x8d\xff}Q\x0f<tN,C\xeb\x9d1\x87\xd68\xf7\x16\xc2\x9bnz\xa9\xeb@}\xe2\x8d\x01a\xf4\x90\x13\x96n\xda\n\x16\x1f\xf1t\xda\xd4.z\xa5\x00\xcf\xe2\x98T\x12\x15D\x80\x13\xff\xe4\x88;k\x11f\xf9\x08\xf5\r\xe1)H\x7f\xe7\x7f\xff\x87O\xd4\x10,\xdc\xce\x8d\xb8\xdb\xeb\x8d\xa0/\x08\xcc\x88\xb3y\x0c\xda\xd5\xecI\x99Y\xc7\xe7\x9do\xef\x10}\x1e\x17\xce\x80\xcc=\xf0P\xb7\xe7\xa1\xc3\x1f\'\x8eO\xd4\xea\x95#\xc9P\x87o\x17K\xe3c#O\x84\x95\xb9U\r\xe1V\x0b\xa1}\xae\xaf\xbf\x13?x\x99\x10S\xd9)\xad?\xd6h2}B(\x8ee\x81g\x1d\xaa\xef\x90\x86\x82\xee(.\x17\xc3\x1d\x8f\x8b\xb5]\'\xfc\xe1U\xee.\x84\xa2\xff\x8b\xc9`\x08\x91\xbe\x15\xe6\xed\xe3\xe1\xbb\xd2t*z\xf8\xb0\xa3,H\x97<\x9e7v\xa6\x96G\xba\xb1\x15\x92ulZ\x15\xb9\x10\x1c9.\xfa5\xd0\x00\xab\xb3\xda\xbc\xcd\x97\xe6D&\xe3\xfd\x8dG\xe0\xe3i\xc8;S\x91\xf3\x89G\xd56\xd3Q\xc0a\x08\x1deN\xef\x1a8a\xcd\xb2\xea+\xc4\x82"\xb4P\xd1\xb7\xd0\x9c\x06pI;\xcc\xc6\r\xfc\xaa\\\xfeF\xfdP\xad\xf8\xe3\x88 JF\x91\xdc_\x0c=\xba\xe0\xb4\xdaj\xc2\xddx\x1f\x14\x9aDH@\xaa\xa3\xa3\xc3\xbe\xfbZ\\\x04\xee\x04\x05\xba\xedf\xaf\xcf\x9b\x98\x8d\x10\xea\x14\xa9U\xf4=\xf7\x94e\xe6\xfc\x02\xa1+\xce8p\x98\x89P\xf1\xabH\xe1\xa4\xf8v\xf3Qg\x1cPa\xe69\x9ac\xcb\x04y\xf7\xbd\x01}\xfd\x9b\xc5\xbe\x19/\xafmO\x11\xe6\xee`\x03\x93>\xea\xf62\xf0\x05lL\x1c\xcd\x18=yw\xcf\xca\x85A\x9f\xe5\xb09gD\x19\xd8\x02\x06\x8ey,\x95v\xae*\x88\xbf\xbe\xb1\xf5\x92s"g\x82\xc6\xef\xb2\x88q}\x8fzK\xc3\xbfLi\x7f\xca\xc1\xad\xc1\x82\x9f\n\x91O%Y\xb2x\xcc\xad\xd1\x08\xeb\x87\xa1\x1d\xac\xc8\x8eC\x02\xe9\xafbtt\xe5qq\x19+\x94\xc6\xb3X\xf8\xf9\x8e0\x85\x96!]/\xb9\xd9\xc2\xb4\x9cL\xbe\xdc\xb4?\xc21\xb8o\x04\x93\xd5k\x82\x96,\xf38:\x84\xf8\x92,+\x99\xf8\xfa\x8f\xdd\x85y{\t\xa6\xe6\x0fr\x00|\x03y\x98\x8b\xe2\xff\x1c\xfc\x16\xf2\x13\x00\xc1\xb4\xb7\x84\x17@\x05\xa9\x18_v\x0eh\xef\x94\xb98N\xb2M\xec\xee1\xb6=\x1b\x92\'\x8c\xd7[\x85\xd4\xd8\x0cN\x830e3\xa9\xd9Z\xa6 |\xbf\xbe\xb0\x97\nA\xc4J\xbaY\x83\x9f\x00y#\xec\xd8\xff\r\xe81I\x90\xa45\xdb\xeaM\xed\xbe\xe1o\xafZ\xb2\xbe\x9f\x96\xd6\x91\xcf\xa9\x83\xa6\xc8C\xbd\x18?\x84\xc1\xb4\x99\x8a>\xaa\x90|\xaek\x82\xb0\xae\x83c\xf3\xed\xd8\xcb\x03\xd3\xc9\xc6\x0f\xf5Z\x84\xd8\xa2\x92\xea U_\xbdl\xe5\xadJ\xd7\xa6\xb4\xbc[\xff.\x02\xc4w\xa7\xa8\xa9\x8dZ8}8\x9c\xaa\x17,@\x0b\x15\x1d\x95\x87\x1b*\xa1j\x04\r\xc7\x1a\x9b\xe5\xf0wK\x06\xa5\xca\x87gL\xcbA\t\xa2\xc4\x1d\xb9\xe3\x16\x07\x04!\x8a\xd4\x95\xd0u\x11\x94\xfb\xefK\xec\xaeM{\xe2K\x9d\x96\x8d\xa5\x92%j+"\xcfrN\x98\x9eq\xa6\r\x06\x03\xb5\x9b\xeb\xd4u(_y7\x94\xb7\xa1\x8a\xf4\x9a+hg\x0e:bG\xc4S\'N5\xc8c\xa1kP#\xc6\xc9FY\xe2Z\xbb\'\xc7`\xf9\x89\xac\x0b\xbf\x9a[\x12]\x0e\xa3O\xb02%\xcc\x93\xd5\xb8\xb6\x82\x9e\x90h\x83\xeev\xcf\x8e\xe6\x1d\xfa\xccH\x8e\x8d\xc5\xcb\xc8\xba\x97\x05\xa9\xe9\x15\xa6\x8f\x83\x8229O\x97\xfb\x1a\xacJ*\x90\xfe\x17\xd4o\x9cQ\x94j+\xf9Y\x8d\xf7\xf5\xb5\xe7\xeei*x\x86\x0e\xea<\xeft\x8a[\xe3e)"\x8e@\xb4\xae\xc8>\xbc\x8b\xb1Av\xa4\xc5e\xb0e\x00\xe9Qr)\xb84\x0cU\x81!\x01\xdb\xbck\xeei<5\x870\x82\xa5\xa1\xa5;5\xcf5\t\x19=M\xc5\x17\\\x93`\xa0\r\xa7\x16\x92\xba [2d\xae\xcc\x9e\xcc\x8b\xca1\xfe\xc4>\xfc\x87\x01B;\xb4\x84\xf6\xf2\x16\x99C\x9d\xd3\x0fq"\x8f\x16\xea\xab\x96\xb7\xde5Gr\x1d\x165\xbb\xfePg\x89\x00\xac7\x8aIX\xb6\xc3Id\xf3\xe0\xdc\x848\x80\xdb\xdeW\xfbJv\xab\x85\xeb\xa2\xb1\x90\xbf\xda\xef\xc7\xba\x17\xe1\t\xf89I;\x0f-o\xc7\xea\x17@;\xeb\xe0o(\t1L\xa5\x14`oTf\x80\x826N\xd6u \x19\xf2~\x1d\xf7O\x93\xfc\xf1\xc2V0\xa2\x97\x13\xa8\x9dJ\x99\x8cDK\xc9\x12y\xc6\xfcf\xe0\xaa]\xecr\xbe1n\x11`\xcf\x9f\x90\xd5\x91\\FKk\xfe\xc5!n\x90\x1b\xe4rm\xb5\x96\xa1WEQ\x1ccsji\xac\x9e\xcb\x9e\x86`\x1cc\x1bI\x92e<2\x0ei\x83V/\xa6\x13\x13E`\xcb`f!\xe9f\x1a\xc5\x96\x13\x13\xeep\x86\x8a\xb4\x8d`\x10\x17=\x8a\x96\xff\xfd\xb2\xba\xf4\xaf\xe1\x8c\x84m?\xedo0\xb9\xa8\t\xd7.dw5\xfcSn\xde\xc5C\xab\xc22H\r(f\x03\x95']>
| | | | | | \authenticator\
| | | | | | |###[ EncryptedData ]###
| | | | | | | etype = 'AES-256' 0x12 <ASN1_INTEGER[18]>
| | | | | | | kvno = None
| | | | | | | cipher = <ASN1_STRING[b'\x12s\xd5\xafa\xadBmQ\xd0u~\x89y\x17\xca\xebo\xc1\xb6\x95\x05T\xe8\xd7P\xf9]\'\xf4D\xe3\xaa\xf7\xae\x0b\xf4Y[^\x90m\x96\x82\xdb\xde\xed\xcfn\xb4*\x84\xab\x80\x92\x99{x?Wq\x01\'"\x81e\xde\xeb,\xe5\xe0\x9e-\xdcqU]\xc3\x19p\xa81-\x88\x8b\x8a\xe7f8 \x98\'mb\xb4\xbdv\xf3L\xbc\x88\x9e$\xadT\x05\xec\x03|\xebrO\xdbq\xfe$\x7f\xe2\xa4\x14\xa07\xed3\xc7\x96\xf4G_\xcf\xb5\x99>\xed\x14{mc\xd7@\xd5\x8d\xa5\xb0']>
| | | | checksumtype= 'HMAC-SHA1-96-AES256' 0x10 <ASN1_INTEGER[16]>
| | | | checksum = <ASN1_STRING[b'u\xf0-\x8d)T\xe0\xae\x1a\x9e\x06S']>
| | | | \encFastReq\
| | | | |###[ EncryptedData ]###
| | | | | etype = 'AES-256' 0x12 <ASN1_INTEGER[18]>
| | | | | kvno = None
| | | | | cipher = <ASN1_STRING[b'<\xaf4\xec\xef\xd8Lxg\x03\xc2\x009\xdea\xbc\x01\xeb\xed\x9b\xe7\xe5\x1c\x90\xa5\x82\xfe\xc8Rik\xf9/\xd1e\xcd[^\xf0\xf9\xb8\xed\xb6f\xc9\xcc\xa5i\r6N\\j\xd6\x9e}[\xc7\xe0Uuz\xaab\x06B\x8a0%$\x14M]\x97\xcc\x0bd\xdb\x133PE\x03\x91q\xed\x1f\r\x11\x1c\xa1\xbdFQ\xeb\xca=t\xdb\x02\x9e\\m<\x7f\x86\x00\xc4NU\xb1L\xd3\xc7\xf6\xa1\\\x913@\x0eBU\xd7\x1f#{\xf2\x88\xc1\x86\x13|\xd0J_,\xab\xba1f\xde[\xf1\x11\x90\xa2\xe5\x96.M\xbb\xfb\x98\x01\xe3\xbes\xed\xe5\xa56\xeb\'\xa0\x86\xb6D\xf1"E\x19\x84Y\xc0c\xb8\xec\xba"\x8e\x1f\x92\t\xe0Z[\xcb\xb3\x9a\x12e\x1e\x1048\xeey\x98\xe6f\xd8b\x88\x12\xfa4\xbc\x07\xf4\xc4\xd0\xa4\xd8o\xe2\x07\x12\x8d\xe3~\x1f\xfd\x16\x9aL\xb8y\xcb[\x9d\xb8\xf9\xc3\xe8aC\xbf\xd44\t\xcaG\xe9\x0f;\xc8H\xa1\x83\x8f\xcer\t\xf5r\x96\xe4Ic\xa2\xd1\xe3\xd4']>
| \reqBody \
| |###[ KRB_KDC_REQ_BODY ]###
| | kdcOptions= forwardable, renewable, canonicalize, renewable-ok <ASN1_BIT_STRING[0100000010...0000010000]=b'@\x81\x00\x10' (0 unused bit)>
| | \cname \
| | |###[ PrincipalName ]###
| | | nameType = 'NT-PRINCIPAL' 0x1 <ASN1_INTEGER[1]>
| | | nameString= [<ASN1_GENERAL_STRING[b'adm-0-fastenb']>]
| | realm = <ASN1_GENERAL_STRING[b'DOM1']>
| | \sname \
| | |###[ PrincipalName ]###
| | | nameType = 'NT-SRV-INST' 0x2 <ASN1_INTEGER[2]>
| | | nameString= [<ASN1_GENERAL_STRING[b'krbtgt']>, <ASN1_GENERAL_STRING[b'DOM1']>]
| | from = None
| | till = 2037-09-13 02:48:05 UTC <ASN1_GENERALIZED_TIME['20370913024805Z']>
| | rtime = 2037-09-13 02:48:05 UTC <ASN1_GENERALIZED_TIME['20370913024805Z']>
| | nonce = 0x3f58a7a0 <ASN1_INTEGER[1062774688]>
| | etype = [0x12 <ASN1_INTEGER[18]>, 0x11 <ASN1_INTEGER[17]>, 0x17 <ASN1_INTEGER[23]>, 0x18 <ASN1_INTEGER[24]>, -0x87 <ASN1_INTEGER[-135]>, 0x3 <ASN1_INTEGER[3]>]
| | \addresses \
| | |###[ HostAddress ]###
| | | addrType = 'NetBios' 0x14 <ASN1_INTEGER[20]>
| | | address = <ASN1_STRING[b'SRV ']>
| | encAuthorizationData= None
| | additionalTickets= None
There are 3 encrypted payloads:
pkt.root.padata[0].padataValue.armoredData.armor.armorValue.ticket.encPart
, encrypted using the KRBTGTpkt.root.padata[0].padataValue.armoredData.armor.armorValue.authenticator
, encrypted using the ticket session key (that the clients gets from the first AS-REQ, and that that is also included in tickets for the server to use)pkt.root.padata[0].padataValue.armoredData.encFastReq
, encrypted using using the armor key
We have the krbtgt for this demo:
>>> from scapy.libs.rfc3961 import Key, EncryptionType
>>> krbtgt_hex = "ac67a63d7155791fe31dace230ab516e818c453dfdbd44cbe691b240725c4907"
>>> krbtgt = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=bytes.fromhex(krbtgt_hex))
We can therefore decrypt the first payload:
>>> enc = pkt.root.padata[0].padataValue.armoredData.armor.armorValue.ticket.encPart
>>> encticketpart = enc.decrypt(krbtgt)
>>> encticketpart.show()
###[ EncTicketPart ]###
flags = forwardable, renewable, initial, pre-authent <ASN1_BIT_STRING[0100000011...0000000000]=b'@\xe1\x00\x00' (0 unused bit)>
\key \
|###[ EncryptionKey ]###
| keytype = 'AES-256' 0x12 <ASN1_INTEGER[18]>
| keyvalue = <ASN1_STRING[b'\xe3\xa2\x0f\x8e\xb2\xe1*\xe0\x7f\x86\xcc\x88\xe6,\x08>B\xd8)m/G\x82B;\x9f+\x86\xcd\xcd\xf4\x05']>
crealm = <ASN1_GENERAL_STRING[b'DOM1.LOCAL']>
\cname \
|###[ PrincipalName ]###
| nameType = 'NT-PRINCIPAL' 0x1 <ASN1_INTEGER[1]>
| nameString= [<ASN1_GENERAL_STRING[b'SRV$']>]
\transited \
|###[ TransitedEncoding ]###
| trType = 0x0 <ASN1_INTEGER[0]>
| contents = <ASN1_STRING[b'']>
authtime = 2022-07-12 23:02:25 UTC <ASN1_GENERALIZED_TIME['20220712230225Z']>
starttime = 2022-07-12 23:02:25 UTC <ASN1_GENERALIZED_TIME['20220712230225Z']>
endtime = 2022-07-13 09:02:25 UTC <ASN1_GENERALIZED_TIME['20220713090225Z']>
renewTill = 2022-07-19 23:02:25 UTC <ASN1_GENERALIZED_TIME['20220719230225Z']>
addresses = None
[...]
We can see the ticket session key in there, let’s retrieve it and build a Key
object:
Note
We use the .toKey()
function in the EncryptedKey
type which is a shorthand for Key(<keytype>, key=<keyvalue>)
>>> ticket_session_key = encticketpart.key.toKey()
>>> ticket_session_key.key
b'\xe3\xa2\x0f\x8e\xb2\xe1*\xe0\x7f\x86\xcc\x88\xe6,\x08>B\xd8)m/G\x82B;\x9f+\x86\xcd\xcd\xf4\x05'
We can now decrypt the second payload:
>>> enc = pkt.root.padata[0].padataValue.armoredData.armor.armorValue.authenticator
>>> authenticator = enc.decrypt(ticket_session_key)
>>> authenticator.show()
###[ KRB_Authenticator ]###
authenticatorPvno= 0x5 <ASN1_INTEGER[5]>
crealm = <ASN1_GENERAL_STRING[b'DOM1.LOCAL']>
\cname \
|###[ PrincipalName ]###
| nameType = 'NT-PRINCIPAL' 0x1 <ASN1_INTEGER[1]>
| nameString= [<ASN1_GENERAL_STRING[b'SRV$']>]
checksumtype= 0x0 <ASN1_INTEGER[0]>
checksum = <ASN1_STRING['']>
cusec = 0x3c <ASN1_INTEGER[60]>
ctime = 2022-07-12 23:54:37 UTC <ASN1_GENERALIZED_TIME['20220712235437Z']>
\subkey \
|###[ EncryptionKey ]###
| keytype = 'AES-256' 0x12 <ASN1_INTEGER[18]>
| keyvalue = <ASN1_STRING[b'%\xa4n\xe1\xd0\xf5\x8d\xc4\x8d\xecv\xe8\x9c\xd3\xc9\xee\x1bu\xc9\xa5\xa6\xf8\x83f\x98\xa1\xd9\xe7*I\x9b\xf8']>
seqNumber = 0x0 <ASN1_INTEGER[0]>
encAuthorizationData= None
Again, we see inside this the subkey that is used to compute the armor key. We get it:
>>> subkey = authenticator.subkey.toKey()
>>> subkey.key
b'%\xa4n\xe1\xd0\xf5\x8d\xc4\x8d\xecv\xe8\x9c\xd3\xc9\xee\x1bu\xc9\xa5\xa6\xf8\x83f\x98\xa1\xd9\xe7*I\x9b\xf8'
Following RFC6113 sect 5.4.1.1, we can now compute the armor key using:
>>> from scapy.libs.rfc3961 import KRB_FX_CF2
>>> armorkey = KRB_FX_CF2(subkey, ticket_session_key, b"subkeyarmor", b"ticketarmor")
>>> print(armorkey.key)
b'\x9f\x18L]I\x16\xd0\xe5\xa6\xd9\x92+\xbf\xbc\xe0\n\xd1\xcb6\xf3\xd1.C\xc2\xdcp\xf0H(\x99\x14\x80'
That we can now use to decrypt the last payload:
>>> enc = pkt.root.padata[0].padataValue.armoredData.encFastReq
>>> krbfastreq = enc.decrypt(armorkey)
>>> krbfastreq.show()
###[ KrbFastReq ]###
fastOptions= <ASN1_BIT_STRING[0000000000...0000000000]=b'\x00\x00\x00\x00' (0 unused bit)>
\padata \
|###[ PADATA ]###
| padataType= 'PA-PAC-REQUEST' 0x80 <ASN1_INTEGER[128]>
| \padataValue\
| |###[ PA_PAC_REQUEST ]###
| | includePac= True <ASN1_BOOLEAN[-1]>
|###[ PADATA ]###
| padataType= 'PA-PAC-OPTIONS' 0xa7 <ASN1_INTEGER[167]>
| \padataValue\
| |###[ PA_PAC_OPTIONS ]###
| | options = Claims <ASN1_BIT_STRING[1000000000...0000000000]=b'\x80\x00\x00\x00' (0 unused bit)>
\reqBody \
|###[ KRB_KDC_REQ_BODY ]###
| kdcOptions= forwardable, renewable, canonicalize, renewable-ok <ASN1_BIT_STRING[0100000010...0000010000]=b'@\x81\x00\x10' (0 unused bit)>
| \cname \
| |###[ PrincipalName ]###
| | nameType = 'NT-PRINCIPAL' 0x1 <ASN1_INTEGER[1]>
| | nameString= [<ASN1_GENERAL_STRING[b'adm-0-fastenb']>]
| realm = <ASN1_GENERAL_STRING[b'DOM1']>
| \sname \
| |###[ PrincipalName ]###
| | nameType = 'NT-SRV-INST' 0x2 <ASN1_INTEGER[2]>
| | nameString= [<ASN1_GENERAL_STRING[b'krbtgt']>, <ASN1_GENERAL_STRING[b'DOM1']>]
| from = None
| till = 2037-09-13 02:48:05 UTC <ASN1_GENERALIZED_TIME['20370913024805Z']>
| rtime = 2037-09-13 02:48:05 UTC <ASN1_GENERALIZED_TIME['20370913024805Z']>
| nonce = 0x3f58a7a0 <ASN1_INTEGER[1062774688]>
| etype = [0x12 <ASN1_INTEGER[18]>, 0x11 <ASN1_INTEGER[17]>, 0x17 <ASN1_INTEGER[23]>, 0x18 <ASN1_INTEGER[24]>, -0x87 <ASN1_INTEGER[-135]>, 0x3 <ASN1_INTEGER[3]>]
| \addresses \
| |###[ HostAddress ]###
| | addrType = 'NetBios' 0x14 <ASN1_INTEGER[20]>
| | address = <ASN1_STRING[b'SRV ']>
| encAuthorizationData= None
| additionalTickets= None
Encryption
A encrypt()
function exists in the Key
object in order to do the opposite of decrypt()
.
For instance, during pre-authentication, encode PA-ENC-TIMESTAMP
:
>>> from datetime import datetime
>>> from scapy.libs.rfc3961 import Key, EncryptionType
>>> # Create the PADATA layer with its EncryptedValue
>>> pkt = PADATA(padataType=0x2, padataValue=EncryptedData())
>>> # Compute the key
>>> key = Key.string_to_key(EncryptionType.AES256_CTS_HMAC_SHA1_96, b"Password1", b"DOMAIN.LOCALUser1")
>>> now_time = datetime.now(timezone.utc).replace(microsecond=0) # Current time with no milliseconds
>>> # Encrypt
>>> pkt.padataValue.encrypt(key, PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)))
>>> pkt.show()
###[ PADATA ]###
padataType= 2
\padataValue\
|###[ EncryptedData ]###
| etype = 18
| kvno = 0x0 <ASN1_INTEGER[0]>
| cipher = b"\xc1\x9a\xaf\x89V\x16\x82\xb6\x9a\xcb\x15[\xaf\xed\xd9\xfc\x04\xbf\x18\xd4&\x91\xb3\xcf~tEk,\x98m\xee\xa4O\x05=\x11b\xe05\xca\x92+80\x99\xb1'~\x8d\xdbtz\xa8"