1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Gabriel Potter
5
6r"""
7Kerberos V5
8
9Implements parts of:
10
11- Kerberos Network Authentication Service (V5): RFC4120
12- Kerberos Version 5 GSS-API: RFC1964, RFC4121
13- Kerberos Pre-Authentication: RFC6113 (FAST)
14- Kerberos Principal Name Canonicalization and Cross-Realm Referrals: RFC6806
15- Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols: RFC3244
16- User to User Kerberos Authentication: draft-ietf-cat-user2user-03
17- Public Key Cryptography Based User-to-User Authentication (PKU2U): draft-zhu-pku2u-09
18- Initial and Pass Through Authentication Using Kerberos V5 (IAKERB):
19 draft-ietf-kitten-iakerb-03
20- Kerberos Protocol Extensions: [MS-KILE]
21- Kerberos Protocol Extensions: Service for User: [MS-SFU]
22
23
24.. note::
25 You will find more complete documentation for this layer over at
26 `Kerberos <https://scapy.readthedocs.io/en/latest/layers/kerberos.html>`_
27
28Example decryption::
29
30 >>> from scapy.libs.rfc3961 import Key, EncryptionType
31 >>> pkt = Ether(hex_bytes("525400695813525400216c2b08004500015da71840008006dc\
32 83c0a87a9cc0a87a11c209005854f6ab2392c25bd650182014b6e00000000001316a8201\
33 2d30820129a103020105a20302010aa3633061304ca103020102a24504433041a0030201\
34 12a23a043848484decb01c9b62a1cabfbc3f2d1ed85aa5e093ba8358a8cea34d4393af93\
35 bf211e274fa58e814878db9f0d7a28d94e7327660db4f3704b3011a10402020080a20904\
36 073005a0030101ffa481b73081b4a00703050040810010a1123010a003020101a1093007\
37 1b0577696e3124a20e1b0c444f4d41494e2e4c4f43414ca321301fa003020102a1183016\
38 1b066b72627467741b0c444f4d41494e2e4c4f43414ca511180f32303337303931333032\
39 343830355aa611180f32303337303931333032343830355aa7060204701cc5d1a8153013\
40 0201120201110201170201180202ff79020103a91d301b3019a003020114a11204105749\
41 4e31202020202020202020202020"))
42 >>> enc = pkt[Kerberos].root.padata[0].padataValue
43 >>> k = Key(enc.etype.val, key=hex_bytes("7fada4e566ae4fb270e2800a23a\
44 e87127a819d42e69b5e22de0ddc63da80096d"))
45 >>> enc.decrypt(k)
46"""
47
48from collections import namedtuple
49from datetime import datetime, timedelta, timezone
50from enum import IntEnum
51
52import os
53import re
54import socket
55import struct
56
57from scapy.error import warning
58import scapy.asn1.mib # noqa: F401
59from scapy.asn1.ber import BER_id_dec, BER_Decoding_Error
60from scapy.asn1.asn1 import (
61 ASN1_BIT_STRING,
62 ASN1_BOOLEAN,
63 ASN1_Class,
64 ASN1_GENERAL_STRING,
65 ASN1_GENERALIZED_TIME,
66 ASN1_INTEGER,
67 ASN1_STRING,
68 ASN1_Codecs,
69)
70from scapy.asn1fields import (
71 ASN1F_BOOLEAN,
72 ASN1F_CHOICE,
73 ASN1F_FLAGS,
74 ASN1F_GENERAL_STRING,
75 ASN1F_GENERALIZED_TIME,
76 ASN1F_INTEGER,
77 ASN1F_OID,
78 ASN1F_PACKET,
79 ASN1F_SEQUENCE,
80 ASN1F_SEQUENCE_OF,
81 ASN1F_STRING,
82 ASN1F_enum_INTEGER,
83 ASN1F_optional,
84)
85from scapy.asn1packet import ASN1_Packet
86from scapy.automaton import Automaton, ATMT
87from scapy.compat import bytes_encode
88from scapy.error import log_runtime
89from scapy.fields import (
90 ConditionalField,
91 FieldLenField,
92 FlagsField,
93 IntEnumField,
94 LEIntEnumField,
95 LenField,
96 LEShortEnumField,
97 LEShortField,
98 LongField,
99 MultipleTypeField,
100 PacketField,
101 PacketLenField,
102 PacketListField,
103 PadField,
104 ShortEnumField,
105 ShortField,
106 StrField,
107 StrFieldUtf16,
108 StrFixedLenEnumField,
109 XByteField,
110 XLEIntField,
111 XLEShortField,
112 XStrFixedLenField,
113 XStrLenField,
114 XStrField,
115)
116from scapy.packet import Packet, bind_bottom_up, bind_top_down, bind_layers
117from scapy.supersocket import StreamSocket
118from scapy.utils import strrot, strxor
119from scapy.volatile import GeneralizedTime, RandNum, RandBin
120
121from scapy.layers.gssapi import (
122 GSSAPI_BLOB,
123 GSS_C_FLAGS,
124 GSS_S_BAD_MECH,
125 GSS_S_COMPLETE,
126 GSS_S_CONTINUE_NEEDED,
127 GSS_S_DEFECTIVE_TOKEN,
128 GSS_S_FAILURE,
129 GssChannelBindings,
130 SSP,
131 _GSSAPI_OIDS,
132 _GSSAPI_SIGNATURE_OIDS,
133)
134from scapy.layers.inet import TCP, UDP
135
136# Typing imports
137from typing import (
138 Optional,
139)
140
141
142# kerberos APPLICATION
143
144
145class ASN1_Class_KRB(ASN1_Class):
146 name = "Kerberos"
147 # APPLICATION + CONSTRUCTED = 0x40 | 0x20
148 Token = 0x60 | 0 # GSSAPI
149 Ticket = 0x60 | 1
150 Authenticator = 0x60 | 2
151 EncTicketPart = 0x60 | 3
152 AS_REQ = 0x60 | 10
153 AS_REP = 0x60 | 11
154 TGS_REQ = 0x60 | 12
155 TGS_REP = 0x60 | 13
156 AP_REQ = 0x60 | 14
157 AP_REP = 0x60 | 15
158 PRIV = 0x60 | 21
159 CRED = 0x60 | 22
160 EncASRepPart = 0x60 | 25
161 EncTGSRepPart = 0x60 | 26
162 EncAPRepPart = 0x60 | 27
163 EncKrbPrivPart = 0x60 | 28
164 EncKrbCredPart = 0x60 | 29
165 ERROR = 0x60 | 30
166
167
168# RFC4120 sect 5.2
169
170
171KerberosString = ASN1F_GENERAL_STRING
172Realm = KerberosString
173Int32 = ASN1F_INTEGER
174UInt32 = ASN1F_INTEGER
175
176_PRINCIPAL_NAME_TYPES = {
177 0: "NT-UNKNOWN",
178 1: "NT-PRINCIPAL",
179 2: "NT-SRV-INST",
180 3: "NT-SRV-HST",
181 4: "NT-SRV-XHST",
182 5: "NT-UID",
183 6: "NT-X500-PRINCIPAL",
184 7: "NT-SMTP-NAME",
185 10: "NT-ENTERPRISE",
186}
187
188
189class PrincipalName(ASN1_Packet):
190 ASN1_codec = ASN1_Codecs.BER
191 ASN1_root = ASN1F_SEQUENCE(
192 ASN1F_enum_INTEGER(
193 "nameType",
194 0,
195 _PRINCIPAL_NAME_TYPES,
196 explicit_tag=0xA0,
197 ),
198 ASN1F_SEQUENCE_OF("nameString", [], KerberosString, explicit_tag=0xA1),
199 )
200
201 @staticmethod
202 def fromUPN(upn: str):
203 user, _ = _parse_upn(upn)
204 return PrincipalName(
205 nameString=[ASN1_GENERAL_STRING(user)],
206 nameType=ASN1_INTEGER(1), # NT-PRINCIPAL
207 )
208
209 @staticmethod
210 def fromSPN(spn: bytes):
211 spn, _ = _parse_spn(spn)
212 if spn.startswith("krbtgt"):
213 return PrincipalName(
214 nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")],
215 nameType=ASN1_INTEGER(2), # NT-SRV-INST
216 )
217 else:
218 return PrincipalName(
219 nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")],
220 nameType=ASN1_INTEGER(3), # NT-SRV-HST
221 )
222
223
224KerberosTime = ASN1F_GENERALIZED_TIME
225Microseconds = ASN1F_INTEGER
226
227
228# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1
229
230_KRB_E_TYPES = {
231 1: "DES-CBC-CRC",
232 2: "DES-CBC-MD4",
233 3: "DES-CBC-MD5",
234 5: "DES3-CBC-MD5",
235 7: "DES3-CBC-SHA1",
236 9: "DSAWITHSHA1-CMSOID",
237 10: "MD5WITHRSAENCRYPTION-CMSOID",
238 11: "SHA1WITHRSAENCRYPTION-CMSOID",
239 12: "RC2CBC-ENVOID",
240 13: "RSAENCRYPTION-ENVOID",
241 14: "RSAES-OAEP-ENV-OID",
242 15: "DES-EDE3-CBC-ENV-OID",
243 16: "DES3-CBC-SHA1-KD",
244 17: "AES128-CTS-HMAC-SHA1-96",
245 18: "AES256-CTS-HMAC-SHA1-96",
246 19: "AES128-CTS-HMAC-SHA256-128",
247 20: "AES256-CTS-HMAC-SHA384-192",
248 23: "RC4-HMAC",
249 24: "RC4-HMAC-EXP",
250 25: "CAMELLIA128-CTS-CMAC",
251 26: "CAMELLIA256-CTS-CMAC",
252}
253
254# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-2
255
256_KRB_S_TYPES = {
257 1: "CRC32",
258 2: "RSA-MD4",
259 3: "RSA-MD4-DES",
260 4: "DES-MAC",
261 5: "DES-MAC-K",
262 6: "RSA-MD4-DES-K",
263 7: "RSA-MD5",
264 8: "RSA-MD5-DES",
265 9: "RSA-MD5-DES3",
266 10: "SHA1",
267 12: "HMAC-SHA1-DES3-KD",
268 13: "HMAC-SHA1-DES3",
269 14: "SHA1",
270 15: "HMAC-SHA1-96-AES128",
271 16: "HMAC-SHA1-96-AES256",
272 17: "CMAC-CAMELLIA128",
273 18: "CMAC-CAMELLIA256",
274 19: "HMAC-SHA256-128-AES128",
275 20: "HMAC-SHA384-192-AES256",
276 # RFC 4121
277 0x8003: "KRB-AUTHENTICATOR",
278 # [MS-KILE]
279 0xFFFFFF76: "MD5",
280}
281
282
283class EncryptedData(ASN1_Packet):
284 ASN1_codec = ASN1_Codecs.BER
285 ASN1_root = ASN1F_SEQUENCE(
286 ASN1F_enum_INTEGER("etype", 0x17, _KRB_E_TYPES, explicit_tag=0xA0),
287 ASN1F_optional(UInt32("kvno", None, explicit_tag=0xA1)),
288 ASN1F_STRING("cipher", "", explicit_tag=0xA2),
289 )
290
291 def get_usage(self):
292 """
293 Get current key usage number and encrypted class
294 """
295 # RFC 4120 sect 7.5.1
296 if self.underlayer:
297 if isinstance(self.underlayer, PADATA):
298 patype = self.underlayer.padataType
299 if patype == 2:
300 # AS-REQ PA-ENC-TIMESTAMP padata timestamp
301 return 1, PA_ENC_TS_ENC
302 elif isinstance(self.underlayer, KRB_Ticket):
303 # AS-REP Ticket and TGS-REP Ticket
304 return 2, EncTicketPart
305 elif isinstance(self.underlayer, KRB_AS_REP):
306 # AS-REP encrypted part
307 return 3, EncASRepPart
308 elif isinstance(self.underlayer, KRB_AP_REQ) and isinstance(
309 self.underlayer.underlayer, PADATA
310 ):
311 # TGS-REQ PA-TGS-REQ Authenticator
312 return 7, KRB_Authenticator
313 elif isinstance(self.underlayer, KRB_TGS_REP):
314 # TGS-REP encrypted part
315 return 8, EncTGSRepPart
316 elif isinstance(self.underlayer, KRB_AP_REQ):
317 # AP-REQ Authenticator
318 return 11, KRB_Authenticator
319 elif isinstance(self.underlayer, KRB_AP_REP):
320 # AP-REP encrypted part
321 return 12, EncAPRepPart
322 elif isinstance(self.underlayer, KRB_PRIV):
323 # KRB-PRIV encrypted part
324 return 13, EncKrbPrivPart
325 elif isinstance(self.underlayer, KRB_CRED):
326 # KRB-CRED encrypted part
327 return 14, EncKrbCredPart
328 elif isinstance(self.underlayer, KrbFastArmoredReq):
329 # KEY_USAGE_FAST_ENC
330 return 51, KrbFastReq
331 raise ValueError(
332 "Could not guess key usage number. Please specify key_usage_number"
333 )
334
335 def decrypt(self, key, key_usage_number=None, cls=None):
336 """
337 Decrypt and return the data contained in cipher.
338
339 :param key: the key to use for decryption
340 :param key_usage_number: (optional) specify the key usage number.
341 Guessed otherwise
342 :param cls: (optional) the class of the decrypted payload
343 Guessed otherwise (or bytes)
344 """
345 if key_usage_number is None:
346 key_usage_number, cls = self.get_usage()
347 d = key.decrypt(key_usage_number, self.cipher.val)
348 if cls:
349 try:
350 return cls(d)
351 except BER_Decoding_Error:
352 if cls == EncASRepPart:
353 # https://datatracker.ietf.org/doc/html/rfc4120#section-5.4.2
354 # "Compatibility note: Some implementations unconditionally send an
355 # encrypted EncTGSRepPart (application tag number 26) in this field
356 # regardless of whether the reply is a AS-REP or a TGS-REP. In the
357 # interest of compatibility, implementors MAY relax the check on the
358 # tag number of the decrypted ENC-PART."
359 try:
360 res = EncTGSRepPart(d)
361 # https://github.com/krb5/krb5/blob/48ccd81656381522d1f9ccb8705c13f0266a46ab/src/lib/krb5/asn.1/asn1_k_encode.c#L1128
362 # This is a bug because as the RFC clearly says above, we're
363 # perfectly in our right to be strict on this. (MAY)
364 log_runtime.warning(
365 "Implementation bug detected. This looks like MIT Kerberos."
366 )
367 return res
368 except BER_Decoding_Error:
369 pass
370 raise
371 return d
372
373 def encrypt(self, key, text, confounder=None, key_usage_number=None):
374 """
375 Encrypt text and set it into cipher.
376
377 :param key: the key to use for encryption
378 :param text: the bytes value to encode
379 :param confounder: (optional) specify the confounder bytes. Random otherwise
380 :param key_usage_number: (optional) specify the key usage number.
381 Guessed otherwise
382 """
383 if key_usage_number is None:
384 key_usage_number = self.get_usage()[0]
385 self.etype = key.etype
386 self.cipher = ASN1_STRING(
387 key.encrypt(key_usage_number, text, confounder=confounder)
388 )
389
390
391class EncryptionKey(ASN1_Packet):
392 ASN1_codec = ASN1_Codecs.BER
393 ASN1_root = ASN1F_SEQUENCE(
394 ASN1F_enum_INTEGER("keytype", 0, _KRB_E_TYPES, explicit_tag=0xA0),
395 ASN1F_STRING("keyvalue", "", explicit_tag=0xA1),
396 )
397
398 def toKey(self):
399 from scapy.libs.rfc3961 import Key
400
401 return Key(
402 etype=self.keytype.val,
403 key=self.keyvalue.val,
404 )
405
406 @classmethod
407 def fromKey(self, key):
408 return EncryptionKey(
409 keytype=key.etype,
410 keyvalue=key.key,
411 )
412
413
414class _ASN1FString_PacketField(ASN1F_STRING):
415 holds_packets = 1
416
417 def i2m(self, pkt, val):
418 if isinstance(val, ASN1_Packet):
419 val = ASN1_STRING(bytes(val))
420 return super(_ASN1FString_PacketField, self).i2m(pkt, val)
421
422 def any2i(self, pkt, x):
423 if hasattr(x, "add_underlayer"):
424 x.add_underlayer(pkt)
425 return super(_ASN1FString_PacketField, self).any2i(pkt, x)
426
427
428class _Checksum_Field(_ASN1FString_PacketField):
429 def m2i(self, pkt, s):
430 val = super(_Checksum_Field, self).m2i(pkt, s)
431 if not val[0].val:
432 return val
433 if pkt.cksumtype.val == 0x8003:
434 # Special case per RFC 4121
435 return KRB_AuthenticatorChecksum(val[0].val, _underlayer=pkt), val[1]
436 return val
437
438
439class Checksum(ASN1_Packet):
440 ASN1_codec = ASN1_Codecs.BER
441 ASN1_root = ASN1F_SEQUENCE(
442 ASN1F_enum_INTEGER(
443 "cksumtype",
444 0,
445 _KRB_S_TYPES,
446 explicit_tag=0xA0,
447 ),
448 _Checksum_Field("checksum", "", explicit_tag=0xA1),
449 )
450
451 def get_usage(self):
452 """
453 Get current key usage number
454 """
455 # RFC 4120 sect 7.5.1
456 if self.underlayer:
457 if isinstance(self.underlayer, KRB_Authenticator):
458 # TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum
459 # (n°10 should never happen as we use RFC4121)
460 return 6
461 elif isinstance(self.underlayer, PA_FOR_USER):
462 # [MS-SFU] sect 2.2.1
463 return 17
464 elif isinstance(self.underlayer, PA_S4U_X509_USER):
465 # [MS-SFU] sect 2.2.1
466 return 17
467 elif isinstance(self.underlayer, AD_KDCIssued):
468 # AD-KDC-ISSUED checksum
469 return 19
470 elif isinstance(self.underlayer, KrbFastArmoredReq):
471 # KEY_USAGE_FAST_REQ_CHKSUM
472 return 50
473 raise ValueError(
474 "Could not guess key usage number. Please specify key_usage_number"
475 )
476
477 def verify(self, key, text, key_usage_number=None):
478 """
479 Decrypt and return the data contained in cipher.
480
481 :param key: the key to use to check the checksum
482 :param text: the bytes to verify
483 :param key_usage_number: (optional) specify the key usage number.
484 Guessed otherwise
485 """
486 if key_usage_number is None:
487 key_usage_number = self.get_usage()
488 key.verify_checksum(key_usage_number, text, self.checksum.val)
489
490 def make(self, key, text, key_usage_number=None, cksumtype=None):
491 """
492 Encrypt text and set it into cipher.
493
494 :param key: the key to use to make the checksum
495 :param text: the bytes to make a checksum of
496 :param key_usage_number: (optional) specify the key usage number.
497 Guessed otherwise
498 """
499 if key_usage_number is None:
500 key_usage_number = self.get_usage()
501 self.cksumtype = cksumtype or key.cksumtype
502 self.checksum = ASN1_STRING(
503 key.make_checksum(
504 keyusage=key_usage_number,
505 text=text,
506 cksumtype=self.cksumtype,
507 )
508 )
509
510
511KerberosFlags = ASN1F_FLAGS
512
513_ADDR_TYPES = {
514 # RFC4120 sect 7.5.3
515 0x02: "IPv4",
516 0x03: "Directional",
517 0x05: "ChaosNet",
518 0x06: "XNS",
519 0x07: "ISO",
520 0x0C: "DECNET Phase IV",
521 0x10: "AppleTalk DDP",
522 0x14: "NetBios",
523 0x18: "IPv6",
524}
525
526
527class HostAddress(ASN1_Packet):
528 ASN1_codec = ASN1_Codecs.BER
529 ASN1_root = ASN1F_SEQUENCE(
530 ASN1F_enum_INTEGER(
531 "addrType",
532 0,
533 _ADDR_TYPES,
534 explicit_tag=0xA0,
535 ),
536 ASN1F_STRING("address", "", explicit_tag=0xA1),
537 )
538
539
540HostAddresses = lambda name, **kwargs: ASN1F_SEQUENCE_OF(
541 name, [], HostAddress, **kwargs
542)
543
544
545_AUTHORIZATIONDATA_VALUES = {
546 # Filled below
547}
548
549
550class _AuthorizationData_value_Field(_ASN1FString_PacketField):
551 def m2i(self, pkt, s):
552 val = super(_AuthorizationData_value_Field, self).m2i(pkt, s)
553 if not val[0].val:
554 return val
555 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES:
556 return (
557 _AUTHORIZATIONDATA_VALUES[pkt.adType.val](val[0].val, _underlayer=pkt),
558 val[1],
559 )
560 return val
561
562
563_AD_TYPES = {
564 # RFC4120 sect 7.5.4
565 1: "AD-IF-RELEVANT",
566 2: "AD-INTENDED-FOR-SERVER",
567 3: "AD-INTENDED-FOR-APPLICATION-CLASS",
568 4: "AD-KDC-ISSUED",
569 5: "AD-AND-OR",
570 6: "AD-MANDATORY-TICKET-EXTENSIONS",
571 7: "AD-IN-TICKET-EXTENSIONS",
572 8: "AD-MANDATORY-FOR-KDC",
573 64: "OSF-DCE",
574 65: "SESAME",
575 66: "AD-OSD-DCE-PKI-CERTID",
576 128: "AD-WIN2K-PAC",
577 129: "AD-ETYPE-NEGOTIATION",
578 # [MS-KILE] additions
579 141: "KERB-AUTH-DATA-TOKEN-RESTRICTIONS",
580 142: "KERB-LOCAL",
581 143: "AD-AUTH-DATA-AP-OPTIONS",
582 144: "AD-TARGET-PRINCIPAL", # not an official name
583}
584
585
586class AuthorizationDataItem(ASN1_Packet):
587 ASN1_codec = ASN1_Codecs.BER
588 ASN1_root = ASN1F_SEQUENCE(
589 ASN1F_enum_INTEGER(
590 "adType",
591 0,
592 _AD_TYPES,
593 explicit_tag=0xA0,
594 ),
595 _AuthorizationData_value_Field("adData", "", explicit_tag=0xA1),
596 )
597
598
599class AuthorizationData(ASN1_Packet):
600 ASN1_codec = ASN1_Codecs.BER
601 ASN1_root = ASN1F_SEQUENCE_OF(
602 "seq", [AuthorizationDataItem()], AuthorizationDataItem
603 )
604
605
606AD_IF_RELEVANT = AuthorizationData
607_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT
608
609
610class AD_KDCIssued(ASN1_Packet):
611 ASN1_codec = ASN1_Codecs.BER
612 ASN1_root = ASN1F_SEQUENCE(
613 ASN1F_PACKET("adChecksum", Checksum(), Checksum, explicit_tag=0xA0),
614 ASN1F_optional(
615 Realm("iRealm", "", explicit_tag=0xA1),
616 ),
617 ASN1F_optional(ASN1F_PACKET("iSname", None, PrincipalName, explicit_tag=0xA2)),
618 ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA3),
619 )
620
621
622_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued
623
624
625class AD_AND_OR(ASN1_Packet):
626 ASN1_codec = ASN1_Codecs.BER
627 ASN1_root = ASN1F_SEQUENCE(
628 Int32("conditionCount", 0, explicit_tag=0xA0),
629 ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA1),
630 )
631
632
633_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR
634
635ADMANDATORYFORKDC = AuthorizationData
636_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC
637
638
639# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xml
640_PADATA_TYPES = {
641 1: "PA-TGS-REQ",
642 2: "PA-ENC-TIMESTAMP",
643 3: "PA-PW-SALT",
644 11: "PA-ETYPE-INFO",
645 14: "PA-PK-AS-REQ-OLD",
646 15: "PA-PK-AS-REP-OLD",
647 16: "PA-PK-AS-REQ",
648 17: "PA-PK-AS-REP",
649 19: "PA-ETYPE-INFO2",
650 20: "PA-SVR-REFERRAL-INFO",
651 128: "PA-PAC-REQUEST",
652 129: "PA-FOR-USER",
653 130: "PA-FOR-X509-USER",
654 131: "PA-FOR-CHECK_DUPS",
655 132: "PA-AS-CHECKSUM",
656 133: "PA-FX-COOKIE",
657 134: "PA-AUTHENTICATION-SET",
658 135: "PA-AUTH-SET-SELECTED",
659 136: "PA-FX-FAST",
660 137: "PA-FX-ERROR",
661 138: "PA-ENCRYPTED-CHALLENGE",
662 141: "PA-OTP-CHALLENGE",
663 142: "PA-OTP-REQUEST",
664 143: "PA-OTP-CONFIRM",
665 144: "PA-OTP-PIN-CHANGE",
666 145: "PA-EPAK-AS-REQ",
667 146: "PA-EPAK-AS-REP",
668 147: "PA_PKINIT_KX",
669 148: "PA_PKU2U_NAME",
670 149: "PA-REQ-ENC-PA-REP",
671 150: "PA_AS_FRESHNESS",
672 151: "PA-SPAKE",
673 165: "PA-SUPPORTED-ENCTYPES",
674 166: "PA-EXTENDED-ERROR",
675 167: "PA-PAC-OPTIONS",
676}
677
678_PADATA_CLASSES = {
679 # Filled elsewhere in this file
680}
681
682
683# RFC4120
684
685
686class _PADATA_value_Field(_ASN1FString_PacketField):
687 """
688 A special field that properly dispatches PA-DATA values according to
689 padata-type and if the paquet is a request or a response.
690 """
691
692 def m2i(self, pkt, s):
693 val = super(_PADATA_value_Field, self).m2i(pkt, s)
694 if pkt.padataType.val in _PADATA_CLASSES:
695 cls = _PADATA_CLASSES[pkt.padataType.val]
696 if isinstance(cls, tuple):
697 is_reply = (
698 pkt.underlayer.underlayer is not None
699 and isinstance(pkt.underlayer.underlayer, KRB_ERROR)
700 ) or isinstance(pkt.underlayer, (KRB_AS_REP, KRB_TGS_REP))
701 cls = cls[is_reply]
702 if not val[0].val:
703 return val
704 return cls(val[0].val, _underlayer=pkt), val[1]
705 return val
706
707
708class PADATA(ASN1_Packet):
709 ASN1_codec = ASN1_Codecs.BER
710 ASN1_root = ASN1F_SEQUENCE(
711 ASN1F_enum_INTEGER("padataType", 0, _PADATA_TYPES, explicit_tag=0xA1),
712 _PADATA_value_Field(
713 "padataValue",
714 "",
715 explicit_tag=0xA2,
716 ),
717 )
718
719
720# RFC 4120 sect 5.2.7.2
721
722
723class PA_ENC_TS_ENC(ASN1_Packet):
724 ASN1_codec = ASN1_Codecs.BER
725 ASN1_root = ASN1F_SEQUENCE(
726 KerberosTime("patimestamp", GeneralizedTime(), explicit_tag=0xA0),
727 ASN1F_optional(Microseconds("pausec", 0, explicit_tag=0xA1)),
728 )
729
730
731_PADATA_CLASSES[2] = EncryptedData
732
733
734# RFC 4120 sect 5.2.7.4
735
736
737class ETYPE_INFO_ENTRY(ASN1_Packet):
738 ASN1_codec = ASN1_Codecs.BER
739 ASN1_root = ASN1F_SEQUENCE(
740 ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0),
741 ASN1F_optional(
742 ASN1F_STRING("salt", "", explicit_tag=0xA1),
743 ),
744 )
745
746
747class ETYPE_INFO(ASN1_Packet):
748 ASN1_codec = ASN1_Codecs.BER
749 ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY()], ETYPE_INFO_ENTRY)
750
751
752_PADATA_CLASSES[11] = ETYPE_INFO
753
754# RFC 4120 sect 5.2.7.5
755
756
757class ETYPE_INFO_ENTRY2(ASN1_Packet):
758 ASN1_codec = ASN1_Codecs.BER
759 ASN1_root = ASN1F_SEQUENCE(
760 ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0),
761 ASN1F_optional(
762 KerberosString("salt", "", explicit_tag=0xA1),
763 ),
764 ASN1F_optional(
765 ASN1F_STRING("s2kparams", "", explicit_tag=0xA2),
766 ),
767 )
768
769
770class ETYPE_INFO2(ASN1_Packet):
771 ASN1_codec = ASN1_Codecs.BER
772 ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY2()], ETYPE_INFO_ENTRY2)
773
774
775_PADATA_CLASSES[19] = ETYPE_INFO2
776
777# PADATA Extended with RFC6113
778
779
780class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet):
781 ASN1_codec = ASN1_Codecs.BER
782 ASN1_root = ASN1F_SEQUENCE(
783 Int32("paType", 0, explicit_tag=0xA0),
784 ASN1F_optional(
785 ASN1F_STRING("paHint", "", explicit_tag=0xA1),
786 ),
787 ASN1F_optional(
788 ASN1F_STRING("paValue", "", explicit_tag=0xA2),
789 ),
790 )
791
792
793class PA_AUTHENTICATION_SET(ASN1_Packet):
794 ASN1_codec = ASN1_Codecs.BER
795 ASN1_root = ASN1F_SEQUENCE_OF(
796 "elems", [PA_AUTHENTICATION_SET_ELEM()], PA_AUTHENTICATION_SET_ELEM
797 )
798
799
800_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET
801
802
803# [MS-KILE] sect 2.2.3
804
805
806class PA_PAC_REQUEST(ASN1_Packet):
807 ASN1_codec = ASN1_Codecs.BER
808 ASN1_root = ASN1F_SEQUENCE(
809 ASN1F_BOOLEAN("includePac", True, explicit_tag=0xA0),
810 )
811
812
813_PADATA_CLASSES[128] = PA_PAC_REQUEST
814
815
816# [MS-KILE] sect 2.2.5
817
818
819class LSAP_TOKEN_INFO_INTEGRITY(Packet):
820 fields_desc = [
821 FlagsField(
822 "Flags",
823 0,
824 -32,
825 {
826 0x00000001: "UAC-Restricted",
827 },
828 ),
829 LEIntEnumField(
830 "TokenIL",
831 0x00002000,
832 {
833 0x00000000: "Untrusted",
834 0x00001000: "Low",
835 0x00002000: "Medium",
836 0x00003000: "High",
837 0x00004000: "System",
838 0x00005000: "Protected process",
839 },
840 ),
841 XStrFixedLenField("MachineID", b"", length=32),
842 ]
843
844
845# [MS-KILE] sect 2.2.6
846
847
848class _KerbAdRestrictionEntry_Field(_ASN1FString_PacketField):
849 def m2i(self, pkt, s):
850 val = super(_KerbAdRestrictionEntry_Field, self).m2i(pkt, s)
851 if not val[0].val:
852 return val
853 if pkt.restrictionType.val == 0x0000: # LSAP_TOKEN_INFO_INTEGRITY
854 return LSAP_TOKEN_INFO_INTEGRITY(val[0].val, _underlayer=pkt), val[1]
855 return val
856
857
858class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet):
859 name = "KERB-AD-RESTRICTION-ENTRY"
860 ASN1_codec = ASN1_Codecs.BER
861 ASN1_root = ASN1F_SEQUENCE(
862 ASN1F_SEQUENCE(
863 ASN1F_enum_INTEGER(
864 "restrictionType",
865 0,
866 {0: "LSAP_TOKEN_INFO_INTEGRITY"},
867 explicit_tag=0xA0,
868 ),
869 _KerbAdRestrictionEntry_Field("restriction", b"", explicit_tag=0xA1),
870 )
871 )
872
873
874_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY
875
876
877# [MS-KILE] sect 3.2.5.8
878
879
880class KERB_AUTH_DATA_AP_OPTIONS(Packet):
881 name = "KERB-AUTH-DATA-AP-OPTIONS"
882 fields_desc = [
883 LEIntEnumField(
884 "apOptions",
885 0x4000,
886 {
887 0x4000: "KERB_AP_OPTIONS_CBT",
888 },
889 ),
890 ]
891
892
893_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS
894
895
896# This has no doc..? not in [MS-KILE] at least.
897# We use the name wireshark/samba gave it
898
899
900class KERB_AD_TARGET_PRINCIPAL(Packet):
901 name = "KERB-AD-TARGET-PRINCIPAL"
902 fields_desc = [
903 StrFieldUtf16("spn", ""),
904 ]
905
906
907_AUTHORIZATIONDATA_VALUES[144] = KERB_AD_TARGET_PRINCIPAL
908
909
910# RFC6806 sect 6
911
912
913class KERB_AD_LOGIN_ALIAS(ASN1_Packet):
914 ASN1_codec = ASN1_Codecs.BER
915 ASN1_root = ASN1F_SEQUENCE(ASN1F_SEQUENCE_OF("loginAliases", [], PrincipalName))
916
917
918_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS
919
920
921# [MS-KILE] sect 2.2.8
922
923
924class PA_SUPPORTED_ENCTYPES(Packet):
925 fields_desc = [
926 FlagsField(
927 "flags",
928 0,
929 -32,
930 [
931 "DES-CBC-CRC",
932 "DES-CBC-MD5",
933 "RC4-HMAC",
934 "AES128-CTS-HMAC-SHA1-96",
935 "AES256-CTS-HMAC-SHA1-96",
936 ]
937 + ["bit_%d" % i for i in range(11)]
938 + [
939 "FAST-supported",
940 "Compount-identity-supported",
941 "Claims-supported",
942 "Resource-SID-compression-disabled",
943 ],
944 )
945 ]
946
947
948_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES
949
950# [MS-KILE] sect 2.2.10
951
952
953class PA_PAC_OPTIONS(ASN1_Packet):
954 ASN1_codec = ASN1_Codecs.BER
955 ASN1_root = ASN1F_SEQUENCE(
956 KerberosFlags(
957 "options",
958 "",
959 [
960 "Claims",
961 "Branch-Aware",
962 "Forward-to-Full-DC",
963 "Resource-based-constrained-delegation", # [MS-SFU] 2.2.5
964 ],
965 explicit_tag=0xA0,
966 )
967 )
968
969
970_PADATA_CLASSES[167] = PA_PAC_OPTIONS
971
972
973# RFC6113 sect 5.4.1
974
975
976class _KrbFastArmor_value_Field(_ASN1FString_PacketField):
977 def m2i(self, pkt, s):
978 val = super(_KrbFastArmor_value_Field, self).m2i(pkt, s)
979 if not val[0].val:
980 return val
981 if pkt.armorType.val == 1: # FX_FAST_ARMOR_AP_REQUEST
982 return KRB_AP_REQ(val[0].val, _underlayer=pkt), val[1]
983 return val
984
985
986class KrbFastArmor(ASN1_Packet):
987 ASN1_codec = ASN1_Codecs.BER
988 ASN1_root = ASN1F_SEQUENCE(
989 ASN1F_enum_INTEGER(
990 "armorType", 1, {1: "FX_FAST_ARMOR_AP_REQUEST"}, explicit_tag=0xA0
991 ),
992 _KrbFastArmor_value_Field("armorValue", "", explicit_tag=0xA1),
993 )
994
995
996# RFC6113 sect 5.4.2
997
998
999class KrbFastArmoredReq(ASN1_Packet):
1000 ASN1_codec = ASN1_Codecs.BER
1001 ASN1_root = ASN1F_SEQUENCE(
1002 ASN1F_SEQUENCE(
1003 ASN1F_optional(
1004 ASN1F_PACKET("armor", KrbFastArmor(), KrbFastArmor, explicit_tag=0xA0)
1005 ),
1006 ASN1F_PACKET("reqChecksum", Checksum(), Checksum, explicit_tag=0xA1),
1007 ASN1F_PACKET("encFastReq", None, EncryptedData, explicit_tag=0xA2),
1008 )
1009 )
1010
1011
1012class PA_FX_FAST_REQUEST(ASN1_Packet):
1013 ASN1_codec = ASN1_Codecs.BER
1014 ASN1_root = ASN1F_CHOICE(
1015 "armoredData",
1016 ASN1_STRING(""),
1017 ASN1F_PACKET("req", KrbFastArmoredReq, KrbFastArmoredReq, implicit_tag=0xA0),
1018 )
1019
1020
1021# RFC6113 sect 5.4.3
1022
1023
1024class KrbFastArmoredRep(ASN1_Packet):
1025 ASN1_codec = ASN1_Codecs.BER
1026 ASN1_root = ASN1F_SEQUENCE(
1027 ASN1F_SEQUENCE(
1028 ASN1F_PACKET("encFastRep", None, EncryptedData, explicit_tag=0xA0),
1029 )
1030 )
1031
1032
1033class PA_FX_FAST_REPLY(ASN1_Packet):
1034 ASN1_codec = ASN1_Codecs.BER
1035 ASN1_root = ASN1F_CHOICE(
1036 "armoredData",
1037 ASN1_STRING(""),
1038 ASN1F_PACKET("req", KrbFastArmoredRep, KrbFastArmoredRep, implicit_tag=0xA0),
1039 )
1040
1041
1042class KrbFastFinished(ASN1_Packet):
1043 ASN1_codec = ASN1_Codecs.BER
1044 ASN1_root = ASN1F_SEQUENCE(
1045 KerberosTime("timestamp", GeneralizedTime(), explicit_tag=0xA0),
1046 Microseconds("usec", 0, explicit_tag=0xA1),
1047 Realm("crealm", "", explicit_tag=0xA2),
1048 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA3),
1049 ASN1F_PACKET("ticketChecksum", Checksum(), Checksum, explicit_tag=0xA4),
1050 )
1051
1052
1053class KrbFastResponse(ASN1_Packet):
1054 ASN1_codec = ASN1_Codecs.BER
1055 ASN1_root = ASN1F_SEQUENCE(
1056 ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA0),
1057 ASN1F_optional(
1058 ASN1F_PACKET("stengthenKey", None, EncryptionKey, explicit_tag=0xA1)
1059 ),
1060 ASN1F_optional(
1061 ASN1F_PACKET(
1062 "finished", KrbFastFinished(), KrbFastFinished, explicit_tag=0xA2
1063 )
1064 ),
1065 UInt32("nonce", 0, explicit_tag=0xA3),
1066 )
1067
1068
1069_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY)
1070
1071# RFC 4556
1072
1073
1074# sect 3.2.1
1075
1076
1077class ExternalPrincipalIdentifier(ASN1_Packet):
1078 ASN1_codec = ASN1_Codecs.BER
1079 ASN1_root = ASN1F_SEQUENCE(
1080 ASN1F_optional(
1081 ASN1F_STRING("subjectName", "", implicit_tag=0xA0),
1082 ),
1083 ASN1F_optional(
1084 ASN1F_STRING("issuerAndSerialNumber", "", implicit_tag=0xA1),
1085 ),
1086 ASN1F_optional(
1087 ASN1F_STRING("subjectKeyIdentifier", "", implicit_tag=0xA2),
1088 ),
1089 )
1090
1091
1092class PA_PK_AS_REQ(ASN1_Packet):
1093 ASN1_codec = ASN1_Codecs.BER
1094 ASN1_root = ASN1F_SEQUENCE(
1095 ASN1F_STRING("signedAuthpack", "", implicit_tag=0xA0),
1096 ASN1F_optional(
1097 ASN1F_SEQUENCE_OF(
1098 "trustedCertifiers",
1099 [ExternalPrincipalIdentifier()],
1100 ExternalPrincipalIdentifier,
1101 explicit_tag=0xA1,
1102 ),
1103 ),
1104 ASN1F_optional(
1105 ASN1F_STRING("kdcPkId", "", implicit_tag=0xA2),
1106 ),
1107 )
1108
1109
1110_PADATA_CLASSES[16] = PA_PK_AS_REQ
1111
1112# sect 3.2.3
1113
1114
1115class DHRepInfo(ASN1_Packet):
1116 ASN1_codec = ASN1_Codecs.BER
1117 ASN1_root = ASN1F_SEQUENCE(
1118 ASN1F_STRING("dhSignedData", "", implicit_tag=0xA0),
1119 ASN1F_optional(
1120 ASN1F_STRING("serverDHNonce", "", explicit_tag=0xA1),
1121 ),
1122 )
1123
1124
1125class EncKeyPack(ASN1_Packet):
1126 ASN1_codec = ASN1_Codecs.BER
1127 ASN1_root = ASN1F_STRING("encKeyPack", "")
1128
1129
1130class PA_PK_AS_REP(ASN1_Packet):
1131 ASN1_codec = ASN1_Codecs.BER
1132 ASN1_root = ASN1F_CHOICE(
1133 "rep",
1134 ASN1_STRING(""),
1135 ASN1F_PACKET("dhInfo", DHRepInfo(), DHRepInfo, explicit_tag=0xA0),
1136 ASN1F_PACKET("encKeyPack", EncKeyPack(), EncKeyPack, explicit_tag=0xA1),
1137 )
1138
1139
1140_PADATA_CLASSES[17] = PA_PK_AS_REP
1141
1142# [MS-SFU]
1143
1144
1145# sect 2.2.1
1146class PA_FOR_USER(ASN1_Packet):
1147 ASN1_codec = ASN1_Codecs.BER
1148 ASN1_root = ASN1F_SEQUENCE(
1149 ASN1F_PACKET("userName", PrincipalName(), PrincipalName, explicit_tag=0xA0),
1150 Realm("userRealm", "", explicit_tag=0xA1),
1151 ASN1F_PACKET("cksum", Checksum(), Checksum, explicit_tag=0xA2),
1152 KerberosString("authPackage", "Kerberos", explicit_tag=0xA3),
1153 )
1154
1155
1156_PADATA_CLASSES[129] = PA_FOR_USER
1157
1158
1159# sect 2.2.2
1160
1161
1162class S4UUserID(ASN1_Packet):
1163 ASN1_codec = ASN1_Codecs.BER
1164 ASN1_root = ASN1F_SEQUENCE(
1165 UInt32("nonce", 0, explicit_tag=0xA0),
1166 ASN1F_optional(
1167 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1),
1168 ),
1169 Realm("crealm", "", explicit_tag=0xA2),
1170 ASN1F_optional(
1171 ASN1F_STRING("subjectCertificate", None, explicit_tag=0xA3),
1172 ),
1173 ASN1F_optional(
1174 ASN1F_FLAGS(
1175 "options",
1176 "",
1177 [
1178 "reserved",
1179 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS",
1180 "KDC_KEY_USAGE_27",
1181 ],
1182 explicit_tag=0xA4,
1183 )
1184 ),
1185 )
1186
1187
1188class PA_S4U_X509_USER(ASN1_Packet):
1189 ASN1_codec = ASN1_Codecs.BER
1190 ASN1_root = ASN1F_SEQUENCE(
1191 ASN1F_PACKET("userId", S4UUserID(), S4UUserID, explicit_tag=0xA0),
1192 ASN1F_PACKET("checksum", Checksum(), Checksum, explicit_tag=0xA1),
1193 )
1194
1195
1196_PADATA_CLASSES[130] = PA_S4U_X509_USER
1197
1198
1199# Back to RFC4120
1200
1201# sect 5.10
1202KRB_MSG_TYPES = {
1203 1: "Ticket",
1204 2: "Authenticator",
1205 3: "EncTicketPart",
1206 10: "AS-REQ",
1207 11: "AS-REP",
1208 12: "TGS-REQ",
1209 13: "TGS-REP",
1210 14: "AP-REQ",
1211 15: "AP-REP",
1212 16: "KRB-TGT-REQ", # U2U
1213 17: "KRB-TGT-REP", # U2U
1214 20: "KRB-SAFE",
1215 21: "KRB-PRIV",
1216 22: "KRB-CRED",
1217 25: "EncASRepPart",
1218 26: "EncTGSRepPart",
1219 27: "EncAPRepPart",
1220 28: "EncKrbPrivPart",
1221 29: "EnvKrbCredPart",
1222 30: "KRB-ERROR",
1223}
1224
1225# sect 5.3
1226
1227
1228class KRB_Ticket(ASN1_Packet):
1229 ASN1_codec = ASN1_Codecs.BER
1230 ASN1_root = ASN1F_SEQUENCE(
1231 ASN1F_SEQUENCE(
1232 ASN1F_INTEGER("tktVno", 5, explicit_tag=0xA0),
1233 Realm("realm", "", explicit_tag=0xA1),
1234 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xA2),
1235 ASN1F_PACKET("encPart", EncryptedData(), EncryptedData, explicit_tag=0xA3),
1236 ),
1237 implicit_tag=ASN1_Class_KRB.Ticket,
1238 )
1239
1240 def getSPN(self):
1241 return "%s@%s" % (
1242 "/".join(x.val.decode() for x in self.sname.nameString),
1243 self.realm.val.decode(),
1244 )
1245
1246
1247class TransitedEncoding(ASN1_Packet):
1248 ASN1_codec = ASN1_Codecs.BER
1249 ASN1_root = ASN1F_SEQUENCE(
1250 Int32("trType", 0, explicit_tag=0xA0),
1251 ASN1F_STRING("contents", "", explicit_tag=0xA1),
1252 )
1253
1254
1255_TICKET_FLAGS = [
1256 "reserved",
1257 "forwardable",
1258 "forwarded",
1259 "proxiable",
1260 "proxy",
1261 "may-postdate",
1262 "postdated",
1263 "invalid",
1264 "renewable",
1265 "initial",
1266 "pre-authent",
1267 "hw-authent",
1268 "transited-since-policy-checked",
1269 "ok-as-delegate",
1270 "unused",
1271 "canonicalize", # RFC6806
1272 "anonymous", # RFC6112 + RFC8129
1273]
1274
1275
1276class EncTicketPart(ASN1_Packet):
1277 ASN1_codec = ASN1_Codecs.BER
1278 ASN1_root = ASN1F_SEQUENCE(
1279 ASN1F_SEQUENCE(
1280 KerberosFlags(
1281 "flags",
1282 "",
1283 _TICKET_FLAGS,
1284 explicit_tag=0xA0,
1285 ),
1286 ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA1),
1287 Realm("crealm", "", explicit_tag=0xA2),
1288 ASN1F_PACKET("cname", PrincipalName(), PrincipalName, explicit_tag=0xA3),
1289 ASN1F_PACKET(
1290 "transited", TransitedEncoding(), TransitedEncoding, explicit_tag=0xA4
1291 ),
1292 KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5),
1293 ASN1F_optional(
1294 KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6)
1295 ),
1296 KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7),
1297 ASN1F_optional(
1298 KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8),
1299 ),
1300 ASN1F_optional(
1301 HostAddresses("addresses", explicit_tag=0xA9),
1302 ),
1303 ASN1F_optional(
1304 ASN1F_PACKET(
1305 "authorizationData", None, AuthorizationData, explicit_tag=0xAA
1306 ),
1307 ),
1308 ),
1309 implicit_tag=ASN1_Class_KRB.EncTicketPart,
1310 )
1311
1312
1313# sect 5.4.1
1314
1315
1316class KRB_KDC_REQ_BODY(ASN1_Packet):
1317 ASN1_codec = ASN1_Codecs.BER
1318 ASN1_root = ASN1F_SEQUENCE(
1319 KerberosFlags(
1320 "kdcOptions",
1321 "",
1322 [
1323 "reserved",
1324 "forwardable",
1325 "forwarded",
1326 "proxiable",
1327 "proxy",
1328 "allow-postdate",
1329 "postdated",
1330 "unused7",
1331 "renewable",
1332 "unused9",
1333 "unused10",
1334 "opt-hardware-auth",
1335 "unused12",
1336 "unused13",
1337 "cname-in-addl-tkt", # [MS-SFU] sect 2.2.3
1338 "canonicalize", # RFC6806
1339 "request-anonymous", # RFC6112 + RFC8129
1340 ]
1341 + ["unused%d" % i for i in range(17, 26)]
1342 + [
1343 "disable-transited-check",
1344 "renewable-ok",
1345 "enc-tkt-in-skey",
1346 "unused29",
1347 "renew",
1348 "validate",
1349 ],
1350 explicit_tag=0xA0,
1351 ),
1352 ASN1F_optional(ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1)),
1353 Realm("realm", "", explicit_tag=0xA2),
1354 ASN1F_optional(
1355 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA3),
1356 ),
1357 ASN1F_optional(KerberosTime("from_", None, explicit_tag=0xA4)),
1358 KerberosTime("till", GeneralizedTime(), explicit_tag=0xA5),
1359 ASN1F_optional(KerberosTime("rtime", GeneralizedTime(), explicit_tag=0xA6)),
1360 UInt32("nonce", 0, explicit_tag=0xA7),
1361 ASN1F_SEQUENCE_OF("etype", [], Int32, explicit_tag=0xA8),
1362 ASN1F_optional(
1363 HostAddresses("addresses", explicit_tag=0xA9),
1364 ),
1365 ASN1F_optional(
1366 ASN1F_PACKET(
1367 "encAuthorizationData", None, EncryptedData, explicit_tag=0xAA
1368 ),
1369 ),
1370 ASN1F_optional(
1371 ASN1F_SEQUENCE_OF("additionalTickets", [], KRB_Ticket, explicit_tag=0xAB)
1372 ),
1373 )
1374
1375
1376KRB_KDC_REQ = ASN1F_SEQUENCE(
1377 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA1),
1378 ASN1F_enum_INTEGER("msgType", 10, KRB_MSG_TYPES, explicit_tag=0xA2),
1379 ASN1F_optional(ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA3)),
1380 ASN1F_PACKET("reqBody", KRB_KDC_REQ_BODY(), KRB_KDC_REQ_BODY, explicit_tag=0xA4),
1381)
1382
1383
1384class KrbFastReq(ASN1_Packet):
1385 # RFC6113 sect 5.4.2
1386 ASN1_codec = ASN1_Codecs.BER
1387 ASN1_root = ASN1F_SEQUENCE(
1388 KerberosFlags(
1389 "fastOptions",
1390 "",
1391 [
1392 "RESERVED",
1393 "hide-client-names",
1394 ]
1395 + ["res%d" % i for i in range(2, 16)]
1396 + ["kdc-follow-referrals"],
1397 explicit_tag=0xA0,
1398 ),
1399 ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA1),
1400 ASN1F_PACKET("reqBody", None, KRB_KDC_REQ_BODY, explicit_tag=0xA2),
1401 )
1402
1403
1404class KRB_AS_REQ(ASN1_Packet):
1405 ASN1_codec = ASN1_Codecs.BER
1406 ASN1_root = ASN1F_SEQUENCE(
1407 KRB_KDC_REQ,
1408 implicit_tag=ASN1_Class_KRB.AS_REQ,
1409 )
1410
1411
1412class KRB_TGS_REQ(ASN1_Packet):
1413 ASN1_codec = ASN1_Codecs.BER
1414 ASN1_root = ASN1F_SEQUENCE(
1415 KRB_KDC_REQ,
1416 implicit_tag=ASN1_Class_KRB.TGS_REQ,
1417 )
1418 msgType = ASN1_INTEGER(12)
1419
1420
1421# sect 5.4.2
1422
1423KRB_KDC_REP = ASN1F_SEQUENCE(
1424 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1425 ASN1F_enum_INTEGER("msgType", 11, KRB_MSG_TYPES, explicit_tag=0xA1),
1426 ASN1F_optional(
1427 ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA2),
1428 ),
1429 Realm("crealm", "", explicit_tag=0xA3),
1430 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA4),
1431 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA5),
1432 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA6),
1433)
1434
1435
1436class KRB_AS_REP(ASN1_Packet):
1437 ASN1_codec = ASN1_Codecs.BER
1438 ASN1_root = ASN1F_SEQUENCE(
1439 KRB_KDC_REP,
1440 implicit_tag=ASN1_Class_KRB.AS_REP,
1441 )
1442
1443
1444class KRB_TGS_REP(ASN1_Packet):
1445 ASN1_codec = ASN1_Codecs.BER
1446 ASN1_root = ASN1F_SEQUENCE(
1447 KRB_KDC_REP,
1448 implicit_tag=ASN1_Class_KRB.TGS_REP,
1449 )
1450
1451
1452class LastReqItem(ASN1_Packet):
1453 ASN1_codec = ASN1_Codecs.BER
1454 ASN1_root = ASN1F_SEQUENCE(
1455 Int32("lrType", 0, explicit_tag=0xA0),
1456 KerberosTime("lrValue", GeneralizedTime(), explicit_tag=0xA1),
1457 )
1458
1459
1460EncKDCRepPart = ASN1F_SEQUENCE(
1461 ASN1F_PACKET("key", None, EncryptionKey, explicit_tag=0xA0),
1462 ASN1F_SEQUENCE_OF("lastReq", [], LastReqItem, explicit_tag=0xA1),
1463 UInt32("nonce", 0, explicit_tag=0xA2),
1464 ASN1F_optional(
1465 KerberosTime("keyExpiration", GeneralizedTime(), explicit_tag=0xA3),
1466 ),
1467 KerberosFlags(
1468 "flags",
1469 "",
1470 _TICKET_FLAGS,
1471 explicit_tag=0xA4,
1472 ),
1473 KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5),
1474 ASN1F_optional(
1475 KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6),
1476 ),
1477 KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7),
1478 ASN1F_optional(
1479 KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8),
1480 ),
1481 Realm("srealm", "", explicit_tag=0xA9),
1482 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA),
1483 ASN1F_optional(
1484 HostAddresses("caddr", explicit_tag=0xAB),
1485 ),
1486 # RFC6806 sect 11
1487 ASN1F_optional(
1488 ASN1F_SEQUENCE_OF("encryptedPaData", [], PADATA, explicit_tag=0xAC),
1489 ),
1490)
1491
1492
1493class EncASRepPart(ASN1_Packet):
1494 ASN1_codec = ASN1_Codecs.BER
1495 ASN1_root = ASN1F_SEQUENCE(
1496 EncKDCRepPart,
1497 implicit_tag=ASN1_Class_KRB.EncASRepPart,
1498 )
1499
1500
1501class EncTGSRepPart(ASN1_Packet):
1502 ASN1_codec = ASN1_Codecs.BER
1503 ASN1_root = ASN1F_SEQUENCE(
1504 EncKDCRepPart,
1505 implicit_tag=ASN1_Class_KRB.EncTGSRepPart,
1506 )
1507
1508
1509# sect 5.5.1
1510
1511
1512class KRB_AP_REQ(ASN1_Packet):
1513 ASN1_codec = ASN1_Codecs.BER
1514 ASN1_root = ASN1F_SEQUENCE(
1515 ASN1F_SEQUENCE(
1516 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1517 ASN1F_enum_INTEGER("msgType", 14, KRB_MSG_TYPES, explicit_tag=0xA1),
1518 KerberosFlags(
1519 "apOptions",
1520 "",
1521 [
1522 "reserved",
1523 "use-session-key",
1524 "mutual-required",
1525 ],
1526 explicit_tag=0xA2,
1527 ),
1528 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA3),
1529 ASN1F_PACKET("authenticator", None, EncryptedData, explicit_tag=0xA4),
1530 ),
1531 implicit_tag=ASN1_Class_KRB.AP_REQ,
1532 )
1533
1534
1535_PADATA_CLASSES[1] = KRB_AP_REQ
1536
1537
1538class KRB_Authenticator(ASN1_Packet):
1539 ASN1_codec = ASN1_Codecs.BER
1540 ASN1_root = ASN1F_SEQUENCE(
1541 ASN1F_SEQUENCE(
1542 ASN1F_INTEGER("authenticatorPvno", 5, explicit_tag=0xA0),
1543 Realm("crealm", "", explicit_tag=0xA1),
1544 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA2),
1545 ASN1F_optional(
1546 ASN1F_PACKET("cksum", None, Checksum, explicit_tag=0xA3),
1547 ),
1548 Microseconds("cusec", 0, explicit_tag=0xA4),
1549 KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA5),
1550 ASN1F_optional(
1551 ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA6),
1552 ),
1553 ASN1F_optional(
1554 UInt32("seqNumber", 0, explicit_tag=0xA7),
1555 ),
1556 ASN1F_optional(
1557 ASN1F_PACKET(
1558 "encAuthorizationData", None, AuthorizationData, explicit_tag=0xA8
1559 ),
1560 ),
1561 ),
1562 implicit_tag=ASN1_Class_KRB.Authenticator,
1563 )
1564
1565
1566# sect 5.5.2
1567
1568
1569class KRB_AP_REP(ASN1_Packet):
1570 ASN1_codec = ASN1_Codecs.BER
1571 ASN1_root = ASN1F_SEQUENCE(
1572 ASN1F_SEQUENCE(
1573 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1574 ASN1F_enum_INTEGER("msgType", 15, KRB_MSG_TYPES, explicit_tag=0xA1),
1575 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA2),
1576 ),
1577 implicit_tag=ASN1_Class_KRB.AP_REP,
1578 )
1579
1580
1581class EncAPRepPart(ASN1_Packet):
1582 ASN1_codec = ASN1_Codecs.BER
1583 ASN1_root = ASN1F_SEQUENCE(
1584 ASN1F_SEQUENCE(
1585 KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA0),
1586 Microseconds("cusec", 0, explicit_tag=0xA1),
1587 ASN1F_optional(
1588 ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA2),
1589 ),
1590 ASN1F_optional(
1591 UInt32("seqNumber", 0, explicit_tag=0xA3),
1592 ),
1593 ),
1594 implicit_tag=ASN1_Class_KRB.EncAPRepPart,
1595 )
1596
1597
1598# sect 5.7
1599
1600
1601class KRB_PRIV(ASN1_Packet):
1602 ASN1_codec = ASN1_Codecs.BER
1603 ASN1_root = ASN1F_SEQUENCE(
1604 ASN1F_SEQUENCE(
1605 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1606 ASN1F_enum_INTEGER("msgType", 21, KRB_MSG_TYPES, explicit_tag=0xA1),
1607 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3),
1608 ),
1609 implicit_tag=ASN1_Class_KRB.PRIV,
1610 )
1611
1612
1613class EncKrbPrivPart(ASN1_Packet):
1614 ASN1_codec = ASN1_Codecs.BER
1615 ASN1_root = ASN1F_SEQUENCE(
1616 ASN1F_SEQUENCE(
1617 ASN1F_STRING("userData", ASN1_STRING(""), explicit_tag=0xA0),
1618 ASN1F_optional(
1619 KerberosTime("timestamp", None, explicit_tag=0xA1),
1620 ),
1621 ASN1F_optional(
1622 Microseconds("usec", None, explicit_tag=0xA2),
1623 ),
1624 ASN1F_optional(
1625 UInt32("seqNumber", None, explicit_tag=0xA3),
1626 ),
1627 ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4),
1628 ASN1F_optional(
1629 ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5),
1630 ),
1631 ),
1632 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart,
1633 )
1634
1635
1636# sect 5.8
1637
1638
1639class KRB_CRED(ASN1_Packet):
1640 ASN1_codec = ASN1_Codecs.BER
1641 ASN1_root = ASN1F_SEQUENCE(
1642 ASN1F_SEQUENCE(
1643 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1644 ASN1F_enum_INTEGER("msgType", 22, KRB_MSG_TYPES, explicit_tag=0xA1),
1645 ASN1F_SEQUENCE_OF("tickets", [KRB_Ticket()], KRB_Ticket, explicit_tag=0xA2),
1646 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3),
1647 ),
1648 implicit_tag=ASN1_Class_KRB.CRED,
1649 )
1650
1651
1652class KrbCredInfo(ASN1_Packet):
1653 ASN1_codec = ASN1_Codecs.BER
1654 ASN1_root = ASN1F_SEQUENCE(
1655 ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA0),
1656 ASN1F_optional(
1657 Realm("prealm", None, explicit_tag=0xA1),
1658 ),
1659 ASN1F_optional(
1660 ASN1F_PACKET("pname", None, PrincipalName, explicit_tag=0xA2),
1661 ),
1662 ASN1F_optional(
1663 KerberosFlags(
1664 "flags",
1665 None,
1666 _TICKET_FLAGS,
1667 explicit_tag=0xA3,
1668 ),
1669 ),
1670 ASN1F_optional(
1671 KerberosTime("authtime", None, explicit_tag=0xA4),
1672 ),
1673 ASN1F_optional(KerberosTime("starttime", None, explicit_tag=0xA5)),
1674 ASN1F_optional(
1675 KerberosTime("endtime", None, explicit_tag=0xA6),
1676 ),
1677 ASN1F_optional(
1678 KerberosTime("renewTill", None, explicit_tag=0xA7),
1679 ),
1680 ASN1F_optional(
1681 Realm("srealm", None, explicit_tag=0xA8),
1682 ),
1683 ASN1F_optional(
1684 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA9),
1685 ),
1686 ASN1F_optional(
1687 HostAddresses("caddr", explicit_tag=0xAA),
1688 ),
1689 )
1690
1691
1692class EncKrbCredPart(ASN1_Packet):
1693 ASN1_codec = ASN1_Codecs.BER
1694 ASN1_root = ASN1F_SEQUENCE(
1695 ASN1F_SEQUENCE(
1696 ASN1F_SEQUENCE_OF(
1697 "ticketInfo",
1698 [KrbCredInfo()],
1699 KrbCredInfo,
1700 explicit_tag=0xA0,
1701 ),
1702 ASN1F_optional(
1703 UInt32("nonce", None, explicit_tag=0xA1),
1704 ),
1705 ASN1F_optional(
1706 KerberosTime("timestamp", None, explicit_tag=0xA2),
1707 ),
1708 ASN1F_optional(
1709 Microseconds("usec", None, explicit_tag=0xA3),
1710 ),
1711 ASN1F_optional(
1712 ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4),
1713 ),
1714 ASN1F_optional(
1715 ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5),
1716 ),
1717 ),
1718 implicit_tag=ASN1_Class_KRB.EncKrbCredPart,
1719 )
1720
1721
1722# sect 5.9.1
1723
1724
1725class MethodData(ASN1_Packet):
1726 ASN1_codec = ASN1_Codecs.BER
1727 ASN1_root = ASN1F_SEQUENCE_OF("seq", [PADATA()], PADATA)
1728
1729
1730class _KRBERROR_data_Field(_ASN1FString_PacketField):
1731 def m2i(self, pkt, s):
1732 val = super(_KRBERROR_data_Field, self).m2i(pkt, s)
1733 if not val[0].val:
1734 return val
1735 if pkt.errorCode.val in [14, 24, 25]:
1736 # 14: KDC_ERR_ETYPE_NOSUPP
1737 # 24: KDC_ERR_PREAUTH_FAILED
1738 # 25: KDC_ERR_PREAUTH_REQUIRED
1739 return MethodData(val[0].val, _underlayer=pkt), val[1]
1740 elif pkt.errorCode.val in [18, 29, 41, 60]:
1741 # 18: KDC_ERR_CLIENT_REVOKED
1742 # 29: KDC_ERR_SVC_UNAVAILABLE
1743 # 41: KRB_AP_ERR_MODIFIED
1744 # 60: KRB_ERR_GENERIC
1745 return KERB_ERROR_DATA(val[0].val, _underlayer=pkt), val[1]
1746 elif pkt.errorCode.val == 69:
1747 # KRB_AP_ERR_USER_TO_USER_REQUIRED
1748 return KRB_TGT_REP(val[0].val, _underlayer=pkt), val[1]
1749 return val
1750
1751
1752class KRB_ERROR(ASN1_Packet):
1753 ASN1_codec = ASN1_Codecs.BER
1754 ASN1_root = ASN1F_SEQUENCE(
1755 ASN1F_SEQUENCE(
1756 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1757 ASN1F_enum_INTEGER("msgType", 30, KRB_MSG_TYPES, explicit_tag=0xA1),
1758 ASN1F_optional(
1759 KerberosTime("ctime", None, explicit_tag=0xA2),
1760 ),
1761 ASN1F_optional(
1762 Microseconds("cusec", None, explicit_tag=0xA3),
1763 ),
1764 KerberosTime("stime", GeneralizedTime(), explicit_tag=0xA4),
1765 Microseconds("susec", 0, explicit_tag=0xA5),
1766 ASN1F_enum_INTEGER(
1767 "errorCode",
1768 0,
1769 {
1770 # RFC4120 sect 7.5.9
1771 0: "KDC_ERR_NONE",
1772 1: "KDC_ERR_NAME_EXP",
1773 2: "KDC_ERR_SERVICE_EXP",
1774 3: "KDC_ERR_BAD_PVNO",
1775 4: "KDC_ERR_C_OLD_MAST_KVNO",
1776 5: "KDC_ERR_S_OLD_MAST_KVNO",
1777 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN",
1778 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN",
1779 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE",
1780 9: "KDC_ERR_NULL_KEY",
1781 10: "KDC_ERR_CANNOT_POSTDATE",
1782 11: "KDC_ERR_NEVER_VALID",
1783 12: "KDC_ERR_POLICY",
1784 13: "KDC_ERR_BADOPTION",
1785 14: "KDC_ERR_ETYPE_NOSUPP",
1786 15: "KDC_ERR_SUMTYPE_NOSUPP",
1787 16: "KDC_ERR_PADATA_TYPE_NOSUPP",
1788 17: "KDC_ERR_TRTYPE_NOSUPP",
1789 18: "KDC_ERR_CLIENT_REVOKED",
1790 19: "KDC_ERR_SERVICE_REVOKED",
1791 20: "KDC_ERR_TGT_REVOKED",
1792 21: "KDC_ERR_CLIENT_NOTYET",
1793 22: "KDC_ERR_SERVICE_NOTYET",
1794 23: "KDC_ERR_KEY_EXPIRED",
1795 24: "KDC_ERR_PREAUTH_FAILED",
1796 25: "KDC_ERR_PREAUTH_REQUIRED",
1797 26: "KDC_ERR_SERVER_NOMATCH",
1798 27: "KDC_ERR_MUST_USE_USER2USER",
1799 28: "KDC_ERR_PATH_NOT_ACCEPTED",
1800 29: "KDC_ERR_SVC_UNAVAILABLE",
1801 31: "KRB_AP_ERR_BAD_INTEGRITY",
1802 32: "KRB_AP_ERR_TKT_EXPIRED",
1803 33: "KRB_AP_ERR_TKT_NYV",
1804 34: "KRB_AP_ERR_REPEAT",
1805 35: "KRB_AP_ERR_NOT_US",
1806 36: "KRB_AP_ERR_BADMATCH",
1807 37: "KRB_AP_ERR_SKEW",
1808 38: "KRB_AP_ERR_BADADDR",
1809 39: "KRB_AP_ERR_BADVERSION",
1810 40: "KRB_AP_ERR_MSG_TYPE",
1811 41: "KRB_AP_ERR_MODIFIED",
1812 42: "KRB_AP_ERR_BADORDER",
1813 44: "KRB_AP_ERR_BADKEYVER",
1814 45: "KRB_AP_ERR_NOKEY",
1815 46: "KRB_AP_ERR_MUT_FAIL",
1816 47: "KRB_AP_ERR_BADDIRECTION",
1817 48: "KRB_AP_ERR_METHOD",
1818 49: "KRB_AP_ERR_BADSEQ",
1819 50: "KRB_AP_ERR_INAPP_CKSUM",
1820 51: "KRB_AP_PATH_NOT_ACCEPTED",
1821 52: "KRB_ERR_RESPONSE_TOO_BIG",
1822 60: "KRB_ERR_GENERIC",
1823 61: "KRB_ERR_FIELD_TOOLONG",
1824 62: "KDC_ERROR_CLIENT_NOT_TRUSTED",
1825 63: "KDC_ERROR_KDC_NOT_TRUSTED",
1826 64: "KDC_ERROR_INVALID_SIG",
1827 65: "KDC_ERR_KEY_TOO_WEAK",
1828 66: "KDC_ERR_CERTIFICATE_MISMATCH",
1829 67: "KRB_AP_ERR_NO_TGT",
1830 68: "KDC_ERR_WRONG_REALM",
1831 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED",
1832 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE",
1833 71: "KDC_ERR_INVALID_CERTIFICATE",
1834 72: "KDC_ERR_REVOKED_CERTIFICATE",
1835 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN",
1836 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE",
1837 75: "KDC_ERR_CLIENT_NAME_MISMATCH",
1838 76: "KDC_ERR_KDC_NAME_MISMATCH",
1839 # draft-ietf-kitten-iakerb
1840 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND",
1841 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE",
1842 # RFC6113
1843 90: "KDC_ERR_PREAUTH_EXPIRED",
1844 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED",
1845 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET",
1846 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS",
1847 },
1848 explicit_tag=0xA6,
1849 ),
1850 ASN1F_optional(Realm("crealm", None, explicit_tag=0xA7)),
1851 ASN1F_optional(
1852 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA8),
1853 ),
1854 Realm("realm", "", explicit_tag=0xA9),
1855 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA),
1856 ASN1F_optional(KerberosString("eText", "", explicit_tag=0xAB)),
1857 ASN1F_optional(_KRBERROR_data_Field("eData", "", explicit_tag=0xAC)),
1858 ),
1859 implicit_tag=ASN1_Class_KRB.ERROR,
1860 )
1861
1862
1863# [MS-KILE] sect 2.2.1
1864
1865
1866class KERB_EXT_ERROR(Packet):
1867 fields_desc = [
1868 XLEIntField("status", 0),
1869 XLEIntField("reserved", 0),
1870 XLEIntField("flags", 0x00000001),
1871 ]
1872
1873
1874# [MS-KILE] sect 2.2.2
1875
1876
1877class _Error_Field(_ASN1FString_PacketField):
1878 def m2i(self, pkt, s):
1879 val = super(_Error_Field, self).m2i(pkt, s)
1880 if not val[0].val:
1881 return val
1882 if pkt.dataType.val == 3: # KERB_ERR_TYPE_EXTENDED
1883 return KERB_EXT_ERROR(val[0].val, _underlayer=pkt), val[1]
1884 return val
1885
1886
1887class KERB_ERROR_DATA(ASN1_Packet):
1888 ASN1_codec = ASN1_Codecs.BER
1889 ASN1_root = ASN1F_SEQUENCE(
1890 ASN1F_enum_INTEGER(
1891 "dataType",
1892 2,
1893 {
1894 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk
1895 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY",
1896 3: "KERB_ERR_TYPE_EXTENDED",
1897 },
1898 explicit_tag=0xA1,
1899 ),
1900 ASN1F_optional(_Error_Field("dataValue", None, explicit_tag=0xA2)),
1901 )
1902
1903
1904# Kerberos U2U - draft-ietf-cat-user2user-03
1905
1906
1907class KRB_TGT_REQ(ASN1_Packet):
1908 ASN1_codec = ASN1_Codecs.BER
1909 ASN1_root = ASN1F_SEQUENCE(
1910 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1911 ASN1F_enum_INTEGER("msgType", 16, KRB_MSG_TYPES, explicit_tag=0xA1),
1912 ASN1F_optional(
1913 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA2),
1914 ),
1915 ASN1F_optional(
1916 Realm("realm", None, explicit_tag=0xA3),
1917 ),
1918 )
1919
1920
1921class KRB_TGT_REP(ASN1_Packet):
1922 ASN1_codec = ASN1_Codecs.BER
1923 ASN1_root = ASN1F_SEQUENCE(
1924 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1925 ASN1F_enum_INTEGER("msgType", 17, KRB_MSG_TYPES, explicit_tag=0xA1),
1926 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA2),
1927 )
1928
1929
1930# draft-ietf-kitten-iakerb-03 sect 4
1931
1932
1933class KRB_FINISHED(ASN1_Packet):
1934 ASN1_codec = ASN1_Codecs.BER
1935 ASN1_root = ASN1F_SEQUENCE(
1936 ASN1F_PACKET("gssMic", Checksum(), Checksum, explicit_tag=0xA1),
1937 )
1938
1939
1940# RFC 6542 sect 3.1
1941
1942
1943class KRB_GSS_EXT(Packet):
1944 fields_desc = [
1945 IntEnumField(
1946 "type",
1947 0,
1948 {
1949 # https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml
1950 0x00000000: "GSS_EXTS_CHANNEL_BINDING", # RFC 6542 sect 3.2
1951 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard
1952 0x00000002: "GSS_EXTS_FINISHED", # PKU2U / IAKERB
1953 },
1954 ),
1955 FieldLenField("length", None, length_of="data", fmt="!I"),
1956 MultipleTypeField(
1957 [
1958 (
1959 PacketField("data", KRB_FINISHED(), KRB_FINISHED),
1960 lambda pkt: pkt.type == 0x00000002,
1961 ),
1962 ],
1963 XStrLenField("data", b"", length_from=lambda pkt: pkt.length),
1964 ),
1965 ]
1966
1967
1968# RFC 4121 sect 4.1.1
1969
1970
1971class KRB_AuthenticatorChecksum(Packet):
1972 fields_desc = [
1973 FieldLenField("Lgth", None, length_of="Bnd", fmt="<I"),
1974 PacketLenField(
1975 "Bnd",
1976 GssChannelBindings(),
1977 GssChannelBindings,
1978 length_from=lambda pkt: pkt.Lgth,
1979 ),
1980 FlagsField(
1981 "Flags",
1982 0,
1983 -32,
1984 {
1985 0x01: "GSS_C_DELEG_FLAG",
1986 0x02: "GSS_C_MUTUAL_FLAG",
1987 0x04: "GSS_C_REPLAY_FLAG",
1988 0x08: "GSS_C_SEQUENCE_FLAG",
1989 0x10: "GSS_C_CONF_FLAG", # confidentiality
1990 0x20: "GSS_C_INTEG_FLAG", # integrity
1991 # RFC4757
1992 0x1000: "GSS_C_DCE_STYLE",
1993 0x2000: "GSS_C_IDENTIFY_FLAG",
1994 0x4000: "GSS_C_EXTENDED_ERROR_FLAG",
1995 },
1996 ),
1997 ConditionalField(
1998 LEShortField("DlgOpt", 0),
1999 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG,
2000 ),
2001 ConditionalField(
2002 FieldLenField("Dlgth", None, length_of="Deleg"),
2003 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG,
2004 ),
2005 ConditionalField(
2006 PacketLenField(
2007 "Deleg", KRB_CRED(), KRB_CRED, length_from=lambda pkt: pkt.Dlgth
2008 ),
2009 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG,
2010 ),
2011 # Extensions: RFC 6542 sect 3.1
2012 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT),
2013 ]
2014
2015
2016# Kerberos V5 GSS-API - RFC1964 and RFC4121
2017
2018_TOK_IDS = {
2019 # RFC 1964
2020 b"\x01\x00": "KRB-AP-REQ",
2021 b"\x02\x00": "KRB-AP-REP",
2022 b"\x03\x00": "KRB-ERROR",
2023 b"\x01\x01": "GSS_GetMIC-RFC1964",
2024 b"\x02\x01": "GSS_Wrap-RFC1964",
2025 b"\x01\x02": "GSS_Delete_sec_context-RFC1964",
2026 # U2U: [draft-ietf-cat-user2user-03]
2027 b"\x04\x00": "KRB-TGT-REQ",
2028 b"\x04\x01": "KRB-TGT-REP",
2029 # RFC 4121
2030 b"\x04\x04": "GSS_GetMIC",
2031 b"\x05\x04": "GSS_Wrap",
2032 # IAKERB: [draft-ietf-kitten-iakerb-03]
2033 b"\x05\x01": "IAKERB_PROXY",
2034}
2035_SGN_ALGS = {
2036 0x00: "DES MAC MD5",
2037 0x01: "MD2.5",
2038 0x02: "DES MAC",
2039 # RFC 4757
2040 0x11: "HMAC",
2041}
2042_SEAL_ALGS = {
2043 0: "DES",
2044 0xFFFF: "none",
2045 # RFC 4757
2046 0x10: "RC4",
2047}
2048
2049
2050# RFC 1964 - sect 1.1
2051
2052# See https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml
2053_InitialContextTokens = {} # filled below
2054
2055
2056class KRB_InnerToken(Packet):
2057 name = "Kerberos v5 InnerToken"
2058 fields_desc = [
2059 StrFixedLenEnumField("TOK_ID", b"\x01\x00", _TOK_IDS, length=2),
2060 PacketField(
2061 "root",
2062 KRB_AP_REQ(),
2063 lambda x, _parent: _InitialContextTokens[_parent.TOK_ID](x),
2064 ),
2065 ]
2066
2067 @classmethod
2068 def dispatch_hook(cls, _pkt=None, *args, **kargs):
2069 if _pkt and len(_pkt) >= 13:
2070 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper
2071 if _pkt[2:13] == b"\x06\t*\x86H\x86\xf7\x12\x01\x02\x02":
2072 return KRB_GSSAPI_Token
2073 return cls
2074
2075
2076# RFC 4121 - sect 4.1
2077
2078
2079class KRB_GSSAPI_Token(GSSAPI_BLOB):
2080 name = "Kerberos GSSAPI-Token"
2081 ASN1_codec = ASN1_Codecs.BER
2082 ASN1_root = ASN1F_SEQUENCE(
2083 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"),
2084 ASN1F_PACKET(
2085 "innerToken",
2086 KRB_InnerToken(),
2087 KRB_InnerToken,
2088 implicit_tag=0x0,
2089 ),
2090 implicit_tag=ASN1_Class_KRB.Token,
2091 )
2092
2093
2094# RFC 1964 - sect 1.2.1
2095
2096
2097class KRB_GSS_MIC_RFC1964(Packet):
2098 name = "Kerberos v5 MIC Token (RFC1964)"
2099 fields_desc = [
2100 LEShortEnumField("SGN_ALG", 0, _SGN_ALGS),
2101 XLEIntField("Filler", 0xFFFFFFFF),
2102 XStrFixedLenField("SND_SEQ", b"", length=8),
2103 PadField( # sect 1.2.2.3
2104 XStrFixedLenField("SGN_CKSUM", b"", length=8),
2105 align=8,
2106 padwith=b"\x04",
2107 ),
2108 ]
2109
2110
2111_InitialContextTokens[b"\x01\x01"] = KRB_GSS_MIC_RFC1964
2112
2113# RFC 1964 - sect 1.2.2
2114
2115
2116class KRB_GSS_Wrap_RFC1964(Packet):
2117 name = "Kerberos v5 GSS_Wrap (RFC1964)"
2118 fields_desc = [
2119 LEShortEnumField("SGN_ALG", 0, _SGN_ALGS),
2120 LEShortEnumField("SEAL_ALG", 0, _SEAL_ALGS),
2121 XLEShortField("Filler", 0xFFFF),
2122 XStrFixedLenField("SND_SEQ", b"", length=8),
2123 PadField( # sect 1.2.2.3
2124 XStrFixedLenField("SGN_CKSUM", b"", length=8),
2125 align=8,
2126 padwith=b"\x04",
2127 ),
2128 # sect 1.2.2.3
2129 XStrFixedLenField("CONFOUNDER", b"", length=8),
2130 ]
2131
2132
2133_InitialContextTokens[b"\x02\x01"] = KRB_GSS_Wrap_RFC1964
2134
2135
2136# RFC 1964 - sect 1.2.2
2137
2138
2139class KRB_GSS_Delete_sec_context_RFC1964(Packet):
2140 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)"
2141 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc
2142
2143
2144_InitialContextTokens[b"\x01\x02"] = KRB_GSS_Delete_sec_context_RFC1964
2145
2146
2147# RFC 4121 - sect 4.2.2
2148_KRB5_GSS_Flags = [
2149 "SentByAcceptor",
2150 "Sealed",
2151 "AcceptorSubkey",
2152]
2153
2154
2155# RFC 4121 - sect 4.2.6.1
2156
2157
2158class KRB_GSS_MIC(Packet):
2159 name = "Kerberos v5 MIC Token"
2160 fields_desc = [
2161 FlagsField("Flags", 0, 8, _KRB5_GSS_Flags),
2162 XStrFixedLenField("Filler", b"\xff\xff\xff\xff\xff", length=5),
2163 LongField("SND_SEQ", 0), # Big endian
2164 XStrField("SGN_CKSUM", b"\x00" * 12),
2165 ]
2166
2167
2168_InitialContextTokens[b"\x04\x04"] = KRB_GSS_MIC
2169
2170
2171# RFC 4121 - sect 4.2.6.2
2172
2173
2174class KRB_GSS_Wrap(Packet):
2175 name = "Kerberos v5 Wrap Token"
2176 fields_desc = [
2177 FlagsField("Flags", 0, 8, _KRB5_GSS_Flags),
2178 XByteField("Filler", 0xFF),
2179 ShortField("EC", 0), # Big endian
2180 ShortField("RRC", 0), # Big endian
2181 LongField("SND_SEQ", 0), # Big endian
2182 XStrField("Data", b""),
2183 ]
2184
2185
2186_InitialContextTokens[b"\x05\x04"] = KRB_GSS_Wrap
2187
2188
2189# Kerberos IAKERB - draft-ietf-kitten-iakerb-03
2190
2191
2192class IAKERB_HEADER(ASN1_Packet):
2193 ASN1_codec = ASN1_Codecs.BER
2194 ASN1_root = ASN1F_SEQUENCE(
2195 Realm("targetRealm", "", explicit_tag=0xA1),
2196 ASN1F_optional(
2197 ASN1F_STRING("cookie", None, explicit_tag=0xA2),
2198 ),
2199 )
2200
2201
2202_InitialContextTokens[b"\x05\x01"] = IAKERB_HEADER
2203
2204
2205# Register for GSSAPI
2206
2207# Kerberos 5
2208_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken
2209_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken
2210# Kerberos 5 - U2U
2211_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken
2212# Kerberos 5 - IAKERB
2213_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken
2214
2215
2216# Entry class
2217
2218# RFC4120 sect 5.10
2219
2220
2221class Kerberos(ASN1_Packet):
2222 ASN1_codec = ASN1_Codecs.BER
2223 ASN1_root = ASN1F_CHOICE(
2224 "root",
2225 None,
2226 # RFC4120
2227 KRB_GSSAPI_Token, # [APPLICATION 0]
2228 KRB_Ticket, # [APPLICATION 1]
2229 KRB_Authenticator, # [APPLICATION 2]
2230 KRB_AS_REQ, # [APPLICATION 10]
2231 KRB_AS_REP, # [APPLICATION 11]
2232 KRB_TGS_REQ, # [APPLICATION 12]
2233 KRB_TGS_REP, # [APPLICATION 13]
2234 KRB_AP_REQ, # [APPLICATION 14]
2235 KRB_AP_REP, # [APPLICATION 15]
2236 # RFC4120
2237 KRB_ERROR, # [APPLICATION 30]
2238 )
2239
2240 def mysummary(self):
2241 return self.root.summary()
2242
2243
2244bind_bottom_up(UDP, Kerberos, sport=88)
2245bind_bottom_up(UDP, Kerberos, dport=88)
2246bind_layers(UDP, Kerberos, sport=88, dport=88)
2247
2248_InitialContextTokens[b"\x01\x00"] = KRB_AP_REQ
2249_InitialContextTokens[b"\x02\x00"] = KRB_AP_REP
2250_InitialContextTokens[b"\x03\x00"] = KRB_ERROR
2251_InitialContextTokens[b"\x04\x00"] = KRB_TGT_REQ
2252_InitialContextTokens[b"\x04\x01"] = KRB_TGT_REP
2253
2254bind_layers(KRB_InnerToken, Kerberos)
2255
2256
2257# RFC4120 sect 7.2.2
2258
2259
2260class KerberosTCPHeader(Packet):
2261 # According to RFC 5021, first bit to 1 has a special meaning and
2262 # negotiates Kerberos TCP extensions... But apart from rfc6251 no one used that
2263 # https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-4
2264 fields_desc = [LenField("len", None, fmt="!I")]
2265
2266 @classmethod
2267 def tcp_reassemble(cls, data, *args, **kwargs):
2268 if len(data) < 4:
2269 return None
2270 length = struct.unpack("!I", data[:4])[0]
2271 if len(data) == length + 4:
2272 return cls(data)
2273
2274
2275bind_layers(KerberosTCPHeader, Kerberos)
2276
2277bind_bottom_up(TCP, KerberosTCPHeader, sport=88)
2278bind_layers(TCP, KerberosTCPHeader, dport=88)
2279
2280
2281# RFC3244 sect 2
2282
2283
2284class KPASSWD_REQ(Packet):
2285 fields_desc = [
2286 ShortField("len", None),
2287 ShortField("pvno", 0xFF80),
2288 ShortField("apreqlen", None),
2289 PacketLenField(
2290 "apreq", KRB_AP_REQ(), KRB_AP_REQ, length_from=lambda pkt: pkt.apreqlen
2291 ),
2292 ConditionalField(
2293 PacketLenField(
2294 "krbpriv",
2295 KRB_PRIV(),
2296 KRB_PRIV,
2297 length_from=lambda pkt: pkt.len - 6 - pkt.apreqlen,
2298 ),
2299 lambda pkt: pkt.apreqlen != 0,
2300 ),
2301 ConditionalField(
2302 PacketLenField(
2303 "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6
2304 ),
2305 lambda pkt: pkt.apreqlen == 0,
2306 ),
2307 ]
2308
2309 def post_build(self, p, pay):
2310 if self.len is None:
2311 p = struct.pack("!H", len(p)) + p[2:]
2312 if self.apreqlen is None and self.krbpriv is not None:
2313 p = p[:4] + struct.pack("!H", len(self.apreq)) + p[6:]
2314 return p + pay
2315
2316
2317class ChangePasswdData(ASN1_Packet):
2318 ASN1_codec = ASN1_Codecs.BER
2319 ASN1_root = ASN1F_SEQUENCE(
2320 ASN1F_STRING("newpasswd", ASN1_STRING(""), explicit_tag=0xA0),
2321 ASN1F_optional(
2322 ASN1F_PACKET("targname", None, PrincipalName, explicit_tag=0xA1)
2323 ),
2324 ASN1F_optional(Realm("targrealm", None, explicit_tag=0xA2)),
2325 )
2326
2327
2328class KPASSWD_REP(Packet):
2329 fields_desc = [
2330 ShortField("len", None),
2331 ShortField("pvno", 0x0001),
2332 ShortField("apreplen", None),
2333 PacketLenField(
2334 "aprep", KRB_AP_REP(), KRB_AP_REP, length_from=lambda pkt: pkt.apreplen
2335 ),
2336 ConditionalField(
2337 PacketLenField(
2338 "krbpriv",
2339 KRB_PRIV(),
2340 KRB_PRIV,
2341 length_from=lambda pkt: pkt.len - 6 - pkt.apreplen,
2342 ),
2343 lambda pkt: pkt.apreplen != 0,
2344 ),
2345 ConditionalField(
2346 PacketLenField(
2347 "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6
2348 ),
2349 lambda pkt: pkt.apreplen == 0,
2350 ),
2351 ]
2352
2353 def post_build(self, p, pay):
2354 if self.len is None:
2355 p = struct.pack("!H", len(p)) + p[2:]
2356 if self.apreplen is None and self.krbpriv is not None:
2357 p = p[:4] + struct.pack("!H", len(self.aprep)) + p[6:]
2358 return p + pay
2359
2360 def answers(self, other):
2361 return isinstance(other, KPASSWD_REQ)
2362
2363
2364KPASSWD_RESULTS = {
2365 0: "KRB5_KPASSWD_SUCCESS",
2366 1: "KRB5_KPASSWD_MALFORMED",
2367 2: "KRB5_KPASSWD_HARDERROR",
2368 3: "KRB5_KPASSWD_AUTHERROR",
2369 4: "KRB5_KPASSWD_SOFTERROR",
2370 5: "KRB5_KPASSWD_ACCESSDENIED",
2371 6: "KRB5_KPASSWD_BAD_VERSION",
2372 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED",
2373}
2374
2375
2376class KPasswdRepData(Packet):
2377 fields_desc = [
2378 ShortEnumField("resultCode", 0, KPASSWD_RESULTS),
2379 StrField("resultString", ""),
2380 ]
2381
2382
2383class Kpasswd(Packet):
2384 @classmethod
2385 def dispatch_hook(cls, _pkt=None, *args, **kargs):
2386 if _pkt and len(_pkt) >= 4:
2387 if _pkt[2:4] == b"\xff\x80":
2388 return KPASSWD_REQ
2389 elif _pkt[2:4] == b"\x00\x01":
2390 asn1_tag = BER_id_dec(_pkt[6:8])[0] & 0x1F
2391 if asn1_tag == 14:
2392 return KPASSWD_REQ
2393 elif asn1_tag == 15:
2394 return KPASSWD_REP
2395 return KPASSWD_REQ
2396
2397
2398bind_bottom_up(UDP, Kpasswd, sport=464)
2399bind_bottom_up(UDP, Kpasswd, dport=464)
2400bind_top_down(UDP, KPASSWD_REQ, sport=464, dport=464)
2401bind_top_down(UDP, KPASSWD_REP, sport=464, dport=464)
2402
2403
2404class KpasswdTCPHeader(Packet):
2405 fields_desc = [LenField("len", None, fmt="!I")]
2406
2407 @classmethod
2408 def tcp_reassemble(cls, data, *args, **kwargs):
2409 if len(data) < 4:
2410 return None
2411 length = struct.unpack("!I", data[:4])[0]
2412 if len(data) == length + 4:
2413 return cls(data)
2414
2415
2416bind_layers(KpasswdTCPHeader, Kpasswd)
2417
2418bind_bottom_up(TCP, KpasswdTCPHeader, sport=464)
2419bind_layers(TCP, KpasswdTCPHeader, dport=464)
2420
2421
2422# Util functions
2423
2424
2425class KerberosClient(Automaton):
2426 RES_AS_MODE = namedtuple("AS_Result", ["asrep", "sessionkey", "kdcrep"])
2427 RES_TGS_MODE = namedtuple("TGS_Result", ["tgsrep", "sessionkey", "kdcrep"])
2428
2429 class MODE(IntEnum):
2430 AS_REQ = 0
2431 TGS_REQ = 1
2432
2433 def __init__(
2434 self,
2435 mode=MODE.AS_REQ,
2436 ip=None,
2437 host=None,
2438 upn=None,
2439 password=None,
2440 realm=None,
2441 spn=None,
2442 ticket=None,
2443 renew=False,
2444 additional_tickets=[],
2445 u2u=False,
2446 for_user=None,
2447 etypes=None,
2448 key=None,
2449 port=88,
2450 timeout=5,
2451 **kwargs,
2452 ):
2453 import scapy.libs.rfc3961 # Trigger error if any # noqa: F401
2454 from scapy.layers.ldap import dclocator
2455
2456 if not upn:
2457 raise ValueError("Invalid upn")
2458 if not spn:
2459 raise ValueError("Invalid spn")
2460 if realm is None:
2461 if mode == self.MODE.AS_REQ:
2462 _, realm = _parse_upn(upn)
2463 elif mode == self.MODE.TGS_REQ:
2464 _, realm = _parse_spn(spn)
2465 if not realm and ticket:
2466 # if no realm is specified, but there's a ticket, take the realm
2467 # of the ticket.
2468 realm = ticket.realm.val.decode()
2469 else:
2470 raise ValueError("Invalid realm")
2471
2472 if mode == self.MODE.AS_REQ:
2473 if not host:
2474 raise ValueError("Invalid host")
2475 elif mode == self.MODE.TGS_REQ:
2476 if not ticket:
2477 raise ValueError("Invalid ticket")
2478
2479 if not ip:
2480 # No KDC IP provided. Find it by querying the DNS
2481 ip = dclocator(
2482 realm,
2483 timeout=timeout,
2484 # Use connect mode instead of ldap for compatibility
2485 # with MIT kerberos servers
2486 mode="connect",
2487 port=port,
2488 debug=kwargs.get("debug", 0),
2489 ).ip
2490
2491 if etypes is None:
2492 from scapy.libs.rfc3961 import EncryptionType
2493
2494 etypes = [
2495 EncryptionType.AES256_CTS_HMAC_SHA1_96,
2496 EncryptionType.AES128_CTS_HMAC_SHA1_96,
2497 EncryptionType.RC4_HMAC,
2498 EncryptionType.DES_CBC_MD5,
2499 ]
2500 self.etypes = etypes
2501
2502 self.mode = mode
2503
2504 self.result = None # Result
2505
2506 self._timeout = timeout
2507 self._ip = ip
2508 self._port = port
2509 sock = self._connect()
2510
2511 if self.mode == self.MODE.AS_REQ:
2512 self.host = host.upper()
2513 self.password = password and bytes_encode(password)
2514 self.spn = spn
2515 self.upn = upn
2516 self.realm = realm.upper()
2517 self.ticket = ticket
2518 self.renew = renew
2519 self.additional_tickets = additional_tickets # U2U + S4U2Proxy
2520 self.u2u = u2u # U2U
2521 self.for_user = for_user # FOR-USER
2522 self.key = key
2523 # See RFC4120 - sect 7.2.2
2524 # This marks whether we should follow-up after an EOF
2525 self.should_followup = False
2526 # Negotiated parameters
2527 self.pre_auth = False
2528 self.fxcookie = None
2529 super(KerberosClient, self).__init__(
2530 sock=sock,
2531 **kwargs,
2532 )
2533
2534 def _connect(self):
2535 sock = socket.socket()
2536 sock.settimeout(self._timeout)
2537 sock.connect((self._ip, self._port))
2538 sock = StreamSocket(sock, KerberosTCPHeader)
2539 return sock
2540
2541 def send(self, pkt):
2542 super(KerberosClient, self).send(KerberosTCPHeader() / pkt)
2543
2544 def _base_kdc_req(self, now_time):
2545 kdcreq = KRB_KDC_REQ_BODY(
2546 etype=[ASN1_INTEGER(x) for x in self.etypes],
2547 additionalTickets=None,
2548 # Windows default
2549 kdcOptions="forwardable+renewable+canonicalize",
2550 cname=None,
2551 realm=ASN1_GENERAL_STRING(self.realm),
2552 till=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)),
2553 rtime=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)),
2554 nonce=ASN1_INTEGER(RandNum(0, 0x7FFFFFFF)._fix()),
2555 )
2556 if self.renew:
2557 kdcreq.kdcOptions.set(30, 1) # set 'renew' (bit 30)
2558 return kdcreq
2559
2560 def as_req(self):
2561 now_time = datetime.utcnow().replace(microsecond=0, tzinfo=timezone.utc)
2562
2563 kdc_req = self._base_kdc_req(now_time=now_time)
2564 kdc_req.addresses = [
2565 HostAddress(
2566 addrType=ASN1_INTEGER(20), # Netbios
2567 address=ASN1_STRING(self.host.ljust(16, " ")),
2568 )
2569 ]
2570 kdc_req.cname = PrincipalName.fromUPN(self.upn)
2571 kdc_req.sname = PrincipalName.fromSPN(self.spn)
2572
2573 asreq = Kerberos(
2574 root=KRB_AS_REQ(
2575 padata=[
2576 PADATA(
2577 padataType=ASN1_INTEGER(128), # PA-PAC-REQUEST
2578 padataValue=PA_PAC_REQUEST(includePac=ASN1_BOOLEAN(-1)),
2579 )
2580 ],
2581 reqBody=kdc_req,
2582 )
2583 )
2584 # Pre-auth support
2585 if self.pre_auth:
2586 asreq.root.padata.insert(
2587 0,
2588 PADATA(
2589 padataType=0x2, # PA-ENC-TIMESTAMP
2590 padataValue=EncryptedData(),
2591 ),
2592 )
2593 asreq.root.padata[0].padataValue.encrypt(
2594 self.key, PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time))
2595 )
2596 # Cookie support
2597 if self.fxcookie:
2598 asreq.root.padata.insert(
2599 0,
2600 PADATA(
2601 padataType=133, # PA-FX-COOKIE
2602 padataValue=self.fxcookie,
2603 ),
2604 )
2605 return asreq
2606
2607 def tgs_req(self):
2608 now_time = datetime.utcnow().replace(microsecond=0, tzinfo=timezone.utc)
2609
2610 kdc_req = self._base_kdc_req(now_time=now_time)
2611
2612 _, crealm = _parse_upn(self.upn)
2613 authenticator = KRB_Authenticator(
2614 crealm=ASN1_GENERAL_STRING(crealm),
2615 cname=PrincipalName.fromUPN(self.upn),
2616 cksum=None,
2617 ctime=ASN1_GENERALIZED_TIME(now_time),
2618 cusec=ASN1_INTEGER(0),
2619 subkey=None,
2620 seqNumber=None,
2621 encAuthorizationData=None,
2622 )
2623
2624 apreq = KRB_AP_REQ(ticket=self.ticket, authenticator=EncryptedData())
2625
2626 # Additional tickets
2627 if self.additional_tickets:
2628 kdc_req.additionalTickets = self.additional_tickets
2629
2630 if self.u2u: # U2U
2631 kdc_req.kdcOptions.set(28, 1) # set 'enc-tkt-in-skey' (bit 28)
2632
2633 kdc_req.sname = PrincipalName.fromSPN(self.spn)
2634
2635 tgsreq = Kerberos(
2636 root=KRB_TGS_REQ(
2637 padata=[
2638 PADATA(
2639 padataType=ASN1_INTEGER(1), # PA-TGS-REQ
2640 padataValue=apreq,
2641 )
2642 ],
2643 reqBody=kdc_req,
2644 )
2645 )
2646
2647 # [MS-SFU] FOR-USER extension
2648 if self.for_user is not None:
2649 from scapy.libs.rfc3961 import ChecksumType
2650
2651 paforuser = PA_FOR_USER(
2652 userName=PrincipalName.fromUPN(self.for_user),
2653 userRealm=ASN1_GENERAL_STRING(_parse_upn(self.for_user)[1]),
2654 cksum=Checksum(),
2655 )
2656 S4UByteArray = struct.pack( # [MS-SFU] sect 2.2.1
2657 "<I", paforuser.userName.nameType.val
2658 ) + (
2659 (
2660 "".join(x.val for x in paforuser.userName.nameString)
2661 + paforuser.userRealm.val
2662 + paforuser.authPackage.val
2663 ).encode()
2664 )
2665 paforuser.cksum.make(
2666 self.key,
2667 S4UByteArray,
2668 cksumtype=ChecksumType.HMAC_MD5,
2669 )
2670 tgsreq.root.padata.append(
2671 PADATA(
2672 padataType=ASN1_INTEGER(129), # PA-FOR-USER
2673 padataValue=paforuser,
2674 )
2675 )
2676
2677 # Compute checksum
2678 if self.key.cksumtype:
2679 authenticator.cksum = Checksum()
2680 authenticator.cksum.make(
2681 self.key,
2682 bytes(kdc_req),
2683 )
2684 # Encrypt authenticator
2685 apreq.authenticator.encrypt(self.key, authenticator)
2686 return tgsreq
2687
2688 @ATMT.state(initial=1)
2689 def BEGIN(self):
2690 pass
2691
2692 @ATMT.condition(BEGIN)
2693 def should_send_as_req(self):
2694 if self.mode == self.MODE.AS_REQ:
2695 raise self.SENT_AP_REQ()
2696
2697 @ATMT.condition(BEGIN)
2698 def should_send_tgs_req(self):
2699 if self.mode == self.MODE.TGS_REQ:
2700 raise self.SENT_TGS_REQ()
2701
2702 @ATMT.action(should_send_as_req)
2703 def send_as_req(self):
2704 self.send(self.as_req())
2705
2706 @ATMT.action(should_send_tgs_req)
2707 def send_tgs_req(self):
2708 self.send(self.tgs_req())
2709
2710 @ATMT.state()
2711 def SENT_AP_REQ(self):
2712 pass
2713
2714 @ATMT.state()
2715 def SENT_TGS_REQ(self):
2716 pass
2717
2718 def _process_padatas_and_key(self, padatas):
2719 from scapy.libs.rfc3961 import EncryptionType, Key
2720
2721 etype = None
2722 salt = b""
2723 # Process pa-data
2724 if padatas is not None:
2725 for padata in padatas:
2726 if padata.padataType == 0x13 and etype is None: # PA-ETYPE-INFO2
2727 elt = padata.padataValue.seq[0]
2728 if elt.etype.val in self.etypes:
2729 etype = elt.etype.val
2730 if etype != EncryptionType.RC4_HMAC:
2731 salt = elt.salt.val
2732 elif padata.padataType == 133: # PA-FX-COOKIE
2733 self.fxcookie = padata.padataValue
2734
2735 etype = etype or self.etypes[0]
2736 # Compute key if not already provided
2737 if self.key is None:
2738 self.key = Key.string_to_key(
2739 etype,
2740 self.password,
2741 salt,
2742 )
2743
2744 @ATMT.receive_condition(SENT_AP_REQ)
2745 def receive_krb_error_as_req(self, pkt):
2746 if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR):
2747 if pkt.root.errorCode == 25: # KDC_ERR_PREAUTH_REQUIRED
2748 if not self.key and (not self.upn or not self.password):
2749 log_runtime.warning(
2750 "Got 'KDC_ERR_PREAUTH_REQUIRED', "
2751 "but no key, nor upn+pass was passed."
2752 )
2753 raise self.FINAL()
2754 self._process_padatas_and_key(pkt.root.eData.seq)
2755 self.should_followup = True
2756 self.pre_auth = True
2757 raise self.BEGIN()
2758 else:
2759 log_runtime.warning("Received KRB_ERROR")
2760 pkt.show()
2761 raise self.FINAL()
2762
2763 @ATMT.receive_condition(SENT_AP_REQ)
2764 def receive_as_rep(self, pkt):
2765 if Kerberos in pkt and isinstance(pkt.root, KRB_AS_REP):
2766 raise self.FINAL().action_parameters(pkt)
2767
2768 @ATMT.eof(SENT_AP_REQ)
2769 def retry_after_eof_in_apreq(self):
2770 if self.should_followup:
2771 # Reconnect and Restart
2772 self.should_followup = False
2773 self.update_sock(self._connect())
2774 raise self.BEGIN()
2775 else:
2776 log_runtime.warning("Socket was closed in an unexpected state")
2777 raise self.FINAL()
2778
2779 @ATMT.action(receive_as_rep)
2780 def decrypt_as_rep(self, pkt):
2781 self._process_padatas_and_key(pkt.root.padata)
2782 if not self.pre_auth:
2783 log_runtime.warning("Pre-authentication was disabled for this account !")
2784 # Decrypt
2785 enc = pkt.root.encPart
2786 res = enc.decrypt(self.key)
2787 self.result = self.RES_AS_MODE(pkt.root, res.key.toKey(), res)
2788
2789 @ATMT.receive_condition(SENT_TGS_REQ)
2790 def receive_krb_error_tgs_req(self, pkt):
2791 if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR):
2792 log_runtime.warning("Received KRB_ERROR")
2793 pkt.show()
2794 raise self.FINAL()
2795
2796 @ATMT.receive_condition(SENT_TGS_REQ)
2797 def receive_tgs_rep(self, pkt):
2798 if Kerberos in pkt and isinstance(pkt.root, KRB_TGS_REP):
2799 if not self.renew and pkt.root.ticket.sname.nameString[0].val == b"krbtgt":
2800 log_runtime.warning("Received a cross-realm referral ticket !")
2801 raise self.FINAL().action_parameters(pkt)
2802
2803 @ATMT.action(receive_tgs_rep)
2804 def decrypt_tgs_rep(self, pkt):
2805 # Decrypt
2806 enc = pkt.root.encPart
2807 res = enc.decrypt(self.key)
2808 self.result = self.RES_TGS_MODE(pkt.root, res.key.toKey(), res)
2809
2810 @ATMT.state(final=1)
2811 def FINAL(self):
2812 pass
2813
2814
2815def _parse_upn(upn):
2816 m = re.match(r"^([^@\\/]+)(@|\\|/)([^@\\/]+)$", upn)
2817 if not m:
2818 raise ValueError("Invalid UPN: '%s'" % upn)
2819 if m.group(2) == "@":
2820 user = m.group(1)
2821 domain = m.group(3)
2822 else:
2823 user = m.group(3)
2824 domain = m.group(1)
2825 return user, domain
2826
2827
2828def _parse_spn(spn):
2829 m = re.match(r"^((?:[^@\\/]+)/(?:[^@\\/]+))(?:@([^@\\/]+))?$", spn)
2830 if not m:
2831 raise ValueError("Invalid SPN: '%s'" % spn)
2832 return m.group(1), m.group(2)
2833
2834
2835def krb_as_req(
2836 upn, spn=None, ip=None, key=None, password=None, realm=None, host="WIN10", **kwargs
2837):
2838 r"""
2839 Kerberos AS-Req
2840
2841 :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user"
2842 or "user@DOMAIN"
2843 :param spn: (optional) the full service principal name.
2844 Defaults to "krbtgt/<realm>"
2845 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for
2846 _kerberos._tcp.dc._msdcs.domain.local).
2847 :param key: (optional) pass the Key object.
2848 :param password: (optional) otherwise, pass the user's password
2849 :param realm: (optional) the realm to use. Otherwise use the one from UPN.
2850 :param host: (optional) the host performing the AS-Req. WIN10 by default.
2851
2852 :return: returns a named tuple (asrep=<...>, sessionkey=<...>)
2853
2854 Example::
2855
2856 >>> # The KDC is on 192.168.122.17, we ask a TGT for user1
2857 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1")
2858
2859 Equivalent::
2860
2861 >>> from scapy.libs.rfc3961 import Key, EncryptionType
2862 >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546
2863 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9"))
2864 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key)
2865 """
2866 if realm is None:
2867 _, realm = _parse_upn(upn)
2868 if key is None:
2869 if password is None:
2870 try:
2871 from prompt_toolkit import prompt
2872
2873 password = prompt("Enter password: ", is_password=True)
2874 except ImportError:
2875 password = input("Enter password: ")
2876 cli = KerberosClient(
2877 mode=KerberosClient.MODE.AS_REQ,
2878 realm=realm,
2879 ip=ip,
2880 spn=spn or "krbtgt/" + realm,
2881 host=host,
2882 upn=upn,
2883 password=password,
2884 key=key,
2885 **kwargs,
2886 )
2887 cli.run()
2888 cli.stop()
2889 return cli.result
2890
2891
2892def krb_tgs_req(
2893 upn,
2894 spn,
2895 sessionkey,
2896 ticket,
2897 ip=None,
2898 renew=False,
2899 realm=None,
2900 additional_tickets=[],
2901 u2u=False,
2902 etypes=None,
2903 for_user=None,
2904 **kwargs,
2905):
2906 r"""
2907 Kerberos TGS-Req
2908
2909 :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user"
2910 or "user@DOMAIN"
2911 :param spn: the full service principal name (e.g. "cifs/srv1")
2912 :param sessionkey: the session key retrieved from the tgt
2913 :param ticket: the tgt ticket
2914 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for
2915 _kerberos._tcp.dc._msdcs.domain.local).
2916 :param renew: ask for renewal
2917 :param realm: (optional) the realm to use. Otherwise use the one from SPN.
2918 :param additional_tickets: (optional) a list of additional tickets to pass.
2919 :param u2u: (optional) if specified, enable U2U and request the ticket to be
2920 signed using the session key from the first additional ticket.
2921 :param etypes: array of EncryptionType values.
2922 By default: AES128, AES256, RC4, DES_MD5
2923 :param for_user: a user principal name to request the ticket for. This is the
2924 S4U2Self extension.
2925
2926 :return: returns a named tuple (tgsrep=<...>, sessionkey=<...>)
2927
2928 Example::
2929
2930 >>> # The KDC is on 192.168.122.17, we ask a TGT for user1
2931 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1")
2932
2933 Equivalent::
2934
2935 >>> from scapy.libs.rfc3961 import Key, EncryptionType
2936 >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546
2937 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9"))
2938 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key)
2939 """
2940 cli = KerberosClient(
2941 mode=KerberosClient.MODE.TGS_REQ,
2942 realm=realm,
2943 upn=upn,
2944 ip=ip,
2945 spn=spn,
2946 key=sessionkey,
2947 ticket=ticket,
2948 renew=renew,
2949 additional_tickets=additional_tickets,
2950 u2u=u2u,
2951 etypes=etypes,
2952 for_user=for_user,
2953 **kwargs,
2954 )
2955 cli.run()
2956 cli.stop()
2957 return cli.result
2958
2959
2960def krb_as_and_tgs(upn, spn, ip=None, key=None, password=None, **kwargs):
2961 """
2962 Kerberos AS-Req then TGS-Req
2963 """
2964 res = krb_as_req(upn=upn, ip=ip, key=key, password=password, **kwargs)
2965 if not res:
2966 return
2967 return krb_tgs_req(
2968 upn=upn,
2969 spn=spn,
2970 sessionkey=res.sessionkey,
2971 ticket=res.asrep.ticket,
2972 ip=ip,
2973 **kwargs,
2974 )
2975
2976
2977def kpasswd(
2978 upn,
2979 targetupn=None,
2980 ip=None,
2981 password=None,
2982 newpassword=None,
2983 key=None,
2984 ticket=None,
2985 realm=None,
2986 ssp=None,
2987 setpassword=None,
2988 timeout=3,
2989 port=464,
2990 debug=0,
2991 **kwargs,
2992):
2993 """
2994 Change a password using RFC3244's Kerberos Set / Change Password.
2995
2996 :param upn: the UPN to use for authentication
2997 :param targetupn: (optional) the UPN to change the password of. If not specified,
2998 same as upn.
2999 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for
3000 _kerberos._tcp.dc._msdcs.domain.local).
3001 :param key: (optional) pass the Key object.
3002 :param ticket: (optional) a ticket to use. Either a TGT or ST for kadmin/changepw.
3003 :param password: (optional) otherwise, pass the user's password
3004 :param realm: (optional) the realm to use. Otherwise use the one from UPN.
3005 :param setpassword: (optional) use "Set Password" mechanism.
3006 :param ssp: (optional) a Kerberos SSP for the service kadmin/changepw@REALM.
3007 If provided, you probably don't need anything else. Otherwise built.
3008 """
3009 from scapy.layers.ldap import dclocator
3010
3011 if not realm:
3012 _, realm = _parse_upn(upn)
3013 spn = "kadmin/changepw@%s" % realm
3014 if ip is None:
3015 ip = dclocator(
3016 realm,
3017 timeout=timeout,
3018 # Use connect mode instead of ldap for compatibility
3019 # with MIT kerberos servers
3020 mode="connect",
3021 port=port,
3022 debug=debug,
3023 ).ip
3024 if ssp is None and ticket is not None:
3025 tktspn = ticket.getSPN().split("/")[0]
3026 assert tktspn in ["krbtgt", "kadmin"], "Unexpected ticket type ! %s" % tktspn
3027 if tktspn == "krbtgt":
3028 log_runtime.info(
3029 "Using 'Set Password' mode. This only works with admin privileges."
3030 )
3031 setpassword = True
3032 resp = krb_tgs_req(
3033 upn=upn,
3034 spn=spn,
3035 ticket=ticket,
3036 sessionkey=key,
3037 ip=ip,
3038 debug=debug,
3039 )
3040 if resp is None:
3041 return
3042 ticket = resp.tgsrep.ticket
3043 key = resp.sessionkey
3044 if setpassword is None:
3045 setpassword = bool(targetupn)
3046 elif setpassword and targetupn is None:
3047 targetupn = upn
3048 assert setpassword or not targetupn, "Cannot use targetupn in changepassword mode !"
3049 # Get a ticket for kadmin/changepw
3050 if ssp is None:
3051 if ticket is None:
3052 # Get a ticket for kadmin/changepw through AS-REQ
3053 resp = krb_as_req(
3054 upn=upn,
3055 spn=spn,
3056 key=key,
3057 ip=ip,
3058 password=password,
3059 debug=debug,
3060 )
3061 if resp is None:
3062 return
3063 ticket = resp.asrep.ticket
3064 key = resp.sessionkey
3065 ssp = KerberosSSP(
3066 UPN=upn,
3067 SPN=spn,
3068 ST=ticket,
3069 KEY=key,
3070 DC_IP=ip,
3071 debug=debug,
3072 **kwargs,
3073 )
3074 Context, tok, negResult = ssp.GSS_Init_sec_context(
3075 None,
3076 req_flags=0, # No GSS_C_MUTUAL_FLAG
3077 )
3078 if negResult != GSS_S_CONTINUE_NEEDED:
3079 warning("SSP failed on initial GSS_Init_sec_context !")
3080 if tok:
3081 tok.show()
3082 return
3083 apreq = tok.innerToken.root
3084 # Connect
3085 sock = socket.socket()
3086 sock.settimeout(timeout)
3087 sock.connect((ip, port))
3088 sock = StreamSocket(sock, KpasswdTCPHeader)
3089 # Do KPASSWD request
3090 if newpassword is None:
3091 try:
3092 from prompt_toolkit import prompt
3093
3094 newpassword = prompt("Enter NEW password: ", is_password=True)
3095 except ImportError:
3096 newpassword = input("Enter NEW password: ")
3097 krbpriv = KRB_PRIV(encPart=EncryptedData())
3098 krbpriv.encPart.encrypt(
3099 Context.KrbSessionKey,
3100 EncKrbPrivPart(
3101 sAddress=HostAddress(
3102 addrType=ASN1_INTEGER(2), # IPv4
3103 address=ASN1_STRING(b"\xc0\xa8\x00e"),
3104 ),
3105 userData=ASN1_STRING(
3106 bytes(
3107 ChangePasswdData(
3108 newpasswd=newpassword,
3109 targname=PrincipalName.fromUPN(targetupn),
3110 targrealm=realm,
3111 )
3112 )
3113 if setpassword
3114 else newpassword
3115 ),
3116 timestamp=None,
3117 usec=None,
3118 seqNumber=Context.SendSeqNum,
3119 ),
3120 )
3121 resp = sock.sr1(
3122 KpasswdTCPHeader()
3123 / KPASSWD_REQ(
3124 pvno=0xFF80 if setpassword else 1,
3125 apreq=apreq,
3126 krbpriv=krbpriv,
3127 ),
3128 timeout=timeout,
3129 verbose=0,
3130 )
3131 # Verify KPASSWD response
3132 if not resp:
3133 raise TimeoutError("KPASSWD_REQ timed out !")
3134 if KPASSWD_REP not in resp:
3135 resp.show()
3136 raise ValueError("Invalid response to KPASSWD_REQ !")
3137 Context, tok, negResult = ssp.GSS_Init_sec_context(Context, resp.aprep)
3138 if negResult != GSS_S_COMPLETE:
3139 warning("SSP failed on subsequent GSS_Init_sec_context !")
3140 if tok:
3141 tok.show()
3142 return
3143 # Parse answer KRB_PRIV
3144 krbanswer = resp.krbpriv.encPart.decrypt(Context.KrbSessionKey)
3145 userRep = KPasswdRepData(krbanswer.userData.val)
3146 if userRep.resultCode != 0:
3147 warning(userRep.sprintf("KPASSWD failed !"))
3148 userRep.show()
3149 return
3150 print(userRep.sprintf("%resultCode%"))
3151
3152
3153# SSP
3154
3155
3156class KerberosSSP(SSP):
3157 """
3158 The KerberosSSP
3159
3160 Client settings:
3161
3162 :param ST: the service ticket to use for access.
3163 If not provided, will be retrieved
3164 :param SPN: the SPN of the service to use
3165 :param UPN: The client UPN
3166 :param DC_IP: (optional) is ST+KEY are not provided, will need to contact
3167 the KDC at this IP. If not provided, will perform dc locator.
3168 :param TGT: (optional) pass a TGT to use to get the ST.
3169 :param KEY: the session key associated with the ST if it is provided,
3170 OR the session key associated with the TGT
3171 OR the kerberos key associated with the UPN
3172 :param PASSWORD: (optional) if a UPN is provided and not a KEY, this is the
3173 password of the UPN.
3174 :param U2U: (optional) use U2U when requesting the ST.
3175
3176 Server settings:
3177
3178 :param SPN: the SPN of the service to use
3179 :param KEY: the kerberos key to use to decrypt the AP-req
3180 :param TGT: (optional) pass a TGT to use for U2U
3181 :param DC_IP: (optional) if TGT is not provided, request one on the KDC at
3182 this IP using using the KEY when using U2U.
3183 :param REQUIRE_U2U: (optional, default False) require U2U
3184 """
3185
3186 oid = "1.2.840.113554.1.2.2"
3187 auth_type = 0x10
3188
3189 class STATE(SSP.STATE):
3190 INIT = 1
3191 CLI_SENT_TGTREQ = 2
3192 CLI_SENT_APREQ = 3
3193 CLI_RCVD_APREP = 4
3194 SRV_SENT_APREP = 5
3195
3196 class CONTEXT(SSP.CONTEXT):
3197 __slots__ = [
3198 "SessionKey",
3199 "ServerHostname",
3200 "U2U",
3201 "KrbSessionKey", # raw Key object
3202 "STSessionKey", # raw ST Key object (for DCE_STYLE)
3203 "SeqNum", # for AP
3204 "SendSeqNum", # for MIC
3205 "RecvSeqNum", # for MIC
3206 "IsAcceptor",
3207 "SendSealKeyUsage",
3208 "SendSignKeyUsage",
3209 "RecvSealKeyUsage",
3210 "RecvSignKeyUsage",
3211 ]
3212
3213 def __init__(self, IsAcceptor, req_flags=None):
3214 self.state = KerberosSSP.STATE.INIT
3215 self.SessionKey = None
3216 self.ServerHostname = None
3217 self.U2U = False
3218 self.SendSeqNum = 0
3219 self.RecvSeqNum = 0
3220 self.KrbSessionKey = None
3221 self.STSessionKey = None
3222 self.IsAcceptor = IsAcceptor
3223 # [RFC 4121] sect 2
3224 if IsAcceptor:
3225 self.SendSealKeyUsage = 22
3226 self.SendSignKeyUsage = 23
3227 self.RecvSealKeyUsage = 24
3228 self.RecvSignKeyUsage = 25
3229 else:
3230 self.SendSealKeyUsage = 24
3231 self.SendSignKeyUsage = 25
3232 self.RecvSealKeyUsage = 22
3233 self.RecvSignKeyUsage = 23
3234 super(KerberosSSP.CONTEXT, self).__init__(req_flags=req_flags)
3235
3236 def clifailure(self):
3237 self.__init__(self.IsAcceptor, req_flags=self.flags)
3238
3239 def __repr__(self):
3240 if self.U2U:
3241 return "KerberosSSP-U2U"
3242 return "KerberosSSP"
3243
3244 def __init__(
3245 self,
3246 ST=None,
3247 UPN=None,
3248 PASSWORD=None,
3249 U2U=False,
3250 KEY=None,
3251 SPN=None,
3252 TGT=None,
3253 DC_IP=None,
3254 REQUIRE_U2U=False,
3255 SKEY_TYPE=None,
3256 debug=0,
3257 **kwargs,
3258 ):
3259 self.ST = ST
3260 self.UPN = UPN
3261 self.KEY = KEY
3262 self.SPN = SPN
3263 self.TGT = TGT
3264 self.PASSWORD = PASSWORD
3265 self.U2U = U2U
3266 self.DC_IP = DC_IP
3267 self.REQUIRE_U2U = REQUIRE_U2U
3268 self.debug = debug
3269 if SKEY_TYPE is None:
3270 from scapy.libs.rfc3961 import EncryptionType
3271
3272 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96
3273 self.SKEY_TYPE = SKEY_TYPE
3274 super(KerberosSSP, self).__init__(**kwargs)
3275
3276 def GSS_GetMICEx(self, Context, msgs, qop_req=0):
3277 """
3278 [MS-KILE] sect 3.4.5.6
3279
3280 - AES: RFC4121 sect 4.2.6.1
3281 """
3282 if Context.KrbSessionKey.etype in [17, 18]: # AES
3283 # Concatenate the ToSign
3284 ToSign = b"".join(x.data for x in msgs if x.sign)
3285 sig = KRB_InnerToken(
3286 TOK_ID=b"\x04\x04",
3287 root=KRB_GSS_MIC(
3288 Flags="AcceptorSubkey"
3289 + ("+SentByAcceptor" if Context.IsAcceptor else ""),
3290 SND_SEQ=Context.SendSeqNum,
3291 ),
3292 )
3293 ToSign += bytes(sig)[:16]
3294 sig.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum(
3295 keyusage=Context.SendSignKeyUsage,
3296 text=ToSign,
3297 )
3298 else:
3299 raise NotImplementedError
3300 Context.SendSeqNum += 1
3301 return sig
3302
3303 def GSS_VerifyMICEx(self, Context, msgs, signature):
3304 """
3305 [MS-KILE] sect 3.4.5.7
3306
3307 - AES: RFC4121 sect 4.2.6.1
3308 """
3309 Context.RecvSeqNum = signature.root.SND_SEQ
3310 if Context.KrbSessionKey.etype in [17, 18]: # AES
3311 # Concatenate the ToSign
3312 ToSign = b"".join(x.data for x in msgs if x.sign)
3313 ToSign += bytes(signature)[:16]
3314 sig = Context.KrbSessionKey.make_checksum(
3315 keyusage=Context.RecvSignKeyUsage,
3316 text=ToSign,
3317 )
3318 else:
3319 raise NotImplementedError
3320 if sig != signature.root.SGN_CKSUM:
3321 raise ValueError("ERROR: Checksums don't match")
3322
3323 def GSS_WrapEx(self, Context, msgs, qop_req=0):
3324 """
3325 [MS-KILE] sect 3.4.5.4
3326
3327 - AES: RFC4121 sect 4.2.6.2 and [MS-KILE] sect 3.4.5.4.1
3328 - HMAC-RC4: RFC4757 sect 7.3 and [MS-KILE] sect 3.4.5.4.1
3329 """
3330 confidentiality = Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG
3331 if Context.KrbSessionKey.etype in [17, 18]: # AES
3332 # Build token
3333 tok = KRB_InnerToken(
3334 TOK_ID=b"\x05\x04",
3335 root=KRB_GSS_Wrap(
3336 Flags="AcceptorSubkey"
3337 + ("+SentByAcceptor" if Context.IsAcceptor else "")
3338 + ("+Sealed" if confidentiality else ""),
3339 SND_SEQ=Context.SendSeqNum,
3340 RRC=0,
3341 ),
3342 )
3343 Context.SendSeqNum += 1
3344 # Real separation starts now: RFC4121 sect 4.2.4
3345 if confidentiality:
3346 # Confidentiality is requested (see RFC4121 sect 4.3)
3347 # {"header" | encrypt(plaintext-data | filler | "header")}
3348 # 0. Roll confounder
3349 Confounder = os.urandom(Context.KrbSessionKey.ep.blocksize)
3350 # 1. Concatenate the data to be encrypted
3351 Data = b"".join(x.data for x in msgs if x.conf_req_flag)
3352 DataLen = len(Data)
3353 # 2. Add filler
3354 tok.root.EC = ((-DataLen) % Context.KrbSessionKey.ep.blocksize) or 16
3355 Filler = b"\x00" * tok.root.EC
3356 Data += Filler
3357 # 3. Add first 16 octets of the Wrap token "header"
3358 PlainHeader = bytes(tok)[:16]
3359 Data += PlainHeader
3360 # 4. Build 'ToSign', exclusively used for checksum
3361 ToSign = Confounder
3362 ToSign += b"".join(x.data for x in msgs if x.sign)
3363 ToSign += Filler
3364 ToSign += PlainHeader
3365 # 5. Finalize token for signing
3366 # "The RRC field is [...] 28 if encryption is requested."
3367 tok.root.RRC = 28
3368 # 6. encrypt() is the encryption operation (which provides for
3369 # integrity protection)
3370 Data = Context.KrbSessionKey.encrypt(
3371 keyusage=Context.SendSealKeyUsage,
3372 plaintext=Data,
3373 confounder=Confounder,
3374 signtext=ToSign,
3375 )
3376 # 7. Rotate
3377 Data = strrot(Data, tok.root.RRC + tok.root.EC)
3378 # 8. Split (token and encrypted messages)
3379 toklen = len(Data) - DataLen
3380 tok.root.Data = Data[:toklen]
3381 offset = toklen
3382 for msg in msgs:
3383 msglen = len(msg.data)
3384 if msg.conf_req_flag:
3385 msg.data = Data[offset : offset + msglen]
3386 offset += msglen
3387 return msgs, tok
3388 else:
3389 # No confidentiality is requested
3390 # {"header" | plaintext-data | get_mic(plaintext-data | "header")}
3391 # 0. Concatenate the data
3392 Data = b"".join(x.data for x in msgs if x.sign)
3393 DataLen = len(Data)
3394 # 1. Add first 16 octets of the Wrap token "header"
3395 ToSign = Data
3396 ToSign += bytes(tok)[:16]
3397 # 2. get_mic() is the checksum operation for the required
3398 # checksum mechanism
3399 Mic = Context.KrbSessionKey.make_checksum(
3400 keyusage=Context.SendSealKeyUsage,
3401 text=ToSign,
3402 )
3403 # In Wrap tokens without confidentiality, the EC field SHALL be used
3404 # to encode the number of octets in the trailing checksum
3405 tok.root.EC = 12 # len(tok.root.Data) == 12 for AES
3406 # "The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption
3407 # is requested"
3408 tok.root.RRC = 12
3409 # 3. Concat and pack
3410 for msg in msgs:
3411 if msg.sign:
3412 msg.data = b""
3413 Data = Data + Mic
3414 # 4. Rotate
3415 tok.root.Data = strrot(Data, tok.root.RRC)
3416 return msgs, tok
3417 elif Context.KrbSessionKey.etype in [23, 24]: # RC4
3418 from scapy.libs.rfc3961 import Hmac_MD5, Cipher, algorithms, _rfc1964pad
3419
3420 # Build token
3421 seq = struct.pack(">I", Context.SendSeqNum)
3422 tok = KRB_InnerToken(
3423 TOK_ID=b"\x02\x01",
3424 root=KRB_GSS_Wrap_RFC1964(
3425 SGN_ALG="HMAC",
3426 SEAL_ALG="RC4" if confidentiality else "none",
3427 SND_SEQ=seq
3428 + (
3429 # See errata
3430 b"\xff\xff\xff\xff"
3431 if Context.IsAcceptor
3432 else b"\x00\x00\x00\x00"
3433 ),
3434 ),
3435 )
3436 Context.SendSeqNum += 1
3437 # 0. Concatenate data
3438 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign))
3439 ToEncrypt = b"".join(x.data for x in msgs if x.conf_req_flag)
3440 Kss = Context.KrbSessionKey.key
3441 # 1. Roll confounder
3442 Confounder = os.urandom(8)
3443 # 2. Compute the 'Kseq' key
3444 Klocal = strxor(Kss, len(Kss) * b"\xf0")
3445 if Context.KrbSessionKey.etype == 24: # EXP
3446 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3447 Kcrypt = Kcrypt[:7] + b"\xab" * 9
3448 else:
3449 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00")
3450 Kcrypt = Hmac_MD5(Kcrypt).digest(seq)
3451 # 3. Build SGN_CKSUM
3452 tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum(
3453 keyusage=13, # See errata
3454 text=bytes(tok)[:8] + Confounder + ToSign,
3455 )[:8]
3456 # 4. Populate token + encrypt
3457 if confidentiality:
3458 # 'encrypt' is requested
3459 rc4 = Cipher(algorithms.ARC4(Kcrypt), mode=None).encryptor()
3460 tok.root.CONFOUNDER = rc4.update(Confounder)
3461 Data = rc4.update(ToEncrypt)
3462 # Split encrypted data
3463 offset = 0
3464 for msg in msgs:
3465 msglen = len(msg.data)
3466 if msg.conf_req_flag:
3467 msg.data = Data[offset : offset + msglen]
3468 offset += msglen
3469 else:
3470 # 'encrypt' is not requested
3471 tok.root.CONFOUNDER = Confounder
3472 # 5. Compute the 'Kseq' key
3473 if Context.KrbSessionKey.etype == 24: # EXP
3474 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3475 Kseq = Kseq[:7] + b"\xab" * 9
3476 else:
3477 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00")
3478 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM)
3479 # 6. Encrypt 'SND_SEQ'
3480 rc4 = Cipher(algorithms.ARC4(Kseq), mode=None).encryptor()
3481 tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ)
3482 # 7. Include 'InitialContextToken pseudo ASN.1 header'
3483 tok = KRB_GSSAPI_Token(
3484 MechType="1.2.840.113554.1.2.2", # Kerberos 5
3485 innerToken=tok,
3486 )
3487 return msgs, tok
3488 else:
3489 raise NotImplementedError
3490
3491 def GSS_UnwrapEx(self, Context, msgs, signature):
3492 """
3493 [MS-KILE] sect 3.4.5.5
3494
3495 - AES: RFC4121 sect 4.2.6.2
3496 - HMAC-RC4: RFC4757 sect 7.3
3497 """
3498 confidentiality = Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG
3499 if Context.KrbSessionKey.etype in [17, 18]: # AES
3500 # Real separation starts now: RFC4121 sect 4.2.4
3501 if confidentiality:
3502 # 0. Concatenate the data
3503 Data = signature.root.Data
3504 Data += b"".join(x.data for x in msgs if x.conf_req_flag)
3505 # 1. Un-Rotate
3506 Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False)
3507
3508 # 2. Function to build 'ToSign', exclusively used for checksum
3509 def MakeToSign(Confounder, DecText):
3510 offset = 0
3511 # 2.a Confounder
3512 ToSign = Confounder
3513 # 2.b Messages
3514 for msg in msgs:
3515 msglen = len(msg.data)
3516 if msg.conf_req_flag:
3517 ToSign += DecText[offset : offset + msglen]
3518 offset += msglen
3519 elif msg.sign:
3520 ToSign += msg.data
3521 # 2.c Filler & Padding
3522 ToSign += DecText[offset:]
3523 return ToSign
3524
3525 # 3. Decrypt
3526 Data = Context.KrbSessionKey.decrypt(
3527 keyusage=Context.RecvSealKeyUsage,
3528 ciphertext=Data,
3529 presignfunc=MakeToSign,
3530 )
3531 # 4. Split
3532 Data, f16header = (
3533 Data[:-16],
3534 Data[-16:],
3535 )
3536 # 5. Check header
3537 hdr = signature.copy()
3538 hdr.root.RRC = 0
3539 if f16header != bytes(hdr)[:16]:
3540 raise ValueError("ERROR: Headers don't match")
3541 # 6. Split (and ignore filler)
3542 offset = 0
3543 for msg in msgs:
3544 msglen = len(msg.data)
3545 if msg.conf_req_flag:
3546 msg.data = Data[offset : offset + msglen]
3547 offset += msglen
3548 return msgs
3549 else:
3550 # No confidentiality is requested
3551 # 0. Concatenate the data
3552 Data = signature.root.Data
3553 Data += b"".join(x.data for x in msgs if x.sign)
3554 # 1. Un-Rotate
3555 Data = strrot(Data, signature.root.RRC, right=False)
3556 # 2. Split
3557 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :]
3558 # "Both the EC field and the RRC field in
3559 # the token header SHALL be filled with zeroes for the purpose of
3560 # calculating the checksum."
3561 ToSign = Data
3562 hdr = signature.copy()
3563 hdr.root.RRC = 0
3564 hdr.root.EC = 0
3565 # Concatenate the data
3566 ToSign += bytes(hdr)[:16]
3567 # 3. Calculate the signature
3568 sig = Context.KrbSessionKey.make_checksum(
3569 keyusage=Context.RecvSealKeyUsage,
3570 text=ToSign,
3571 )
3572 # 4. Compare
3573 if sig != Mic:
3574 raise ValueError("ERROR: Checksums don't match")
3575 # 5. Split
3576 for msg in msgs:
3577 if msg.sign:
3578 msg.data = Data
3579 return msgs
3580 elif Context.KrbSessionKey.etype in [23, 24]: # RC4
3581 from scapy.libs.rfc3961 import Hmac_MD5, Cipher, algorithms, _rfc1964pad
3582
3583 # Drop wrapping
3584 tok = signature.innerToken
3585
3586 # 0. Concatenate data
3587 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag)
3588 Kss = Context.KrbSessionKey.key
3589 # 1. Compute the 'Kseq' key
3590 if Context.KrbSessionKey.etype == 24: # EXP
3591 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3592 Kseq = Kseq[:7] + b"\xab" * 9
3593 else:
3594 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00")
3595 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM)
3596 # 2. Decrypt 'SND_SEQ'
3597 rc4 = Cipher(algorithms.ARC4(Kseq), mode=None).encryptor()
3598 seq = rc4.update(tok.root.SND_SEQ)[:4]
3599 # 3. Compute the 'Kcrypt' key
3600 Klocal = strxor(Kss, len(Kss) * b"\xf0")
3601 if Context.KrbSessionKey.etype == 24: # EXP
3602 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3603 Kcrypt = Kcrypt[:7] + b"\xab" * 9
3604 else:
3605 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00")
3606 Kcrypt = Hmac_MD5(Kcrypt).digest(seq)
3607 # 4. Decrypt
3608 if confidentiality:
3609 # 'encrypt' was requested
3610 rc4 = Cipher(algorithms.ARC4(Kcrypt), mode=None).encryptor()
3611 Confounder = rc4.update(tok.root.CONFOUNDER)
3612 Data = rc4.update(ToDecrypt)
3613 # Split encrypted data
3614 offset = 0
3615 for msg in msgs:
3616 msglen = len(msg.data)
3617 if msg.conf_req_flag:
3618 msg.data = Data[offset : offset + msglen]
3619 offset += msglen
3620 else:
3621 # 'encrypt' was not requested
3622 Confounder = tok.root.CONFOUNDER
3623 # 5. Verify SGN_CKSUM
3624 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign))
3625 Context.KrbSessionKey.verify_checksum(
3626 keyusage=13, # See errata
3627 text=bytes(tok)[:8] + Confounder + ToSign,
3628 cksum=tok.root.SGN_CKSUM,
3629 )
3630 return msgs
3631 else:
3632 raise NotImplementedError
3633
3634 def GSS_Init_sec_context(
3635 self, Context: CONTEXT, val=None, req_flags: Optional[GSS_C_FLAGS] = None
3636 ):
3637 if Context is None:
3638 # New context
3639 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags)
3640
3641 from scapy.libs.rfc3961 import Key
3642
3643 if Context.state == self.STATE.INIT and self.U2U:
3644 # U2U - Get TGT
3645 Context.state = self.STATE.CLI_SENT_TGTREQ
3646 return (
3647 Context,
3648 KRB_GSSAPI_Token(
3649 MechType="1.2.840.113554.1.2.2.3", # U2U
3650 innerToken=KRB_InnerToken(
3651 TOK_ID=b"\x04\x00",
3652 root=KRB_TGT_REQ(),
3653 ),
3654 ),
3655 GSS_S_CONTINUE_NEEDED,
3656 )
3657
3658 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]:
3659 if not self.UPN:
3660 raise ValueError("Missing UPN attribute")
3661 # Do we have a ST?
3662 if self.ST is None:
3663 # Client sends an AP-req
3664 if not self.SPN:
3665 raise ValueError("Missing SPN attribute")
3666 additional_tickets = []
3667 if self.U2U:
3668 try:
3669 # GSSAPI / Kerberos
3670 tgt_rep = val.root.innerToken.root
3671 except AttributeError:
3672 try:
3673 # Kerberos
3674 tgt_rep = val.innerToken.root
3675 except AttributeError:
3676 return Context, None, GSS_S_DEFECTIVE_TOKEN
3677 if not isinstance(tgt_rep, KRB_TGT_REP):
3678 tgt_rep.show()
3679 raise ValueError("KerberosSSP: Unexpected token !")
3680 additional_tickets = [tgt_rep.ticket]
3681 if self.TGT is not None:
3682 if not self.KEY:
3683 raise ValueError("Cannot use TGT without the KEY")
3684 # Use TGT
3685 res = krb_tgs_req(
3686 upn=self.UPN,
3687 spn=self.SPN,
3688 ip=self.DC_IP,
3689 sessionkey=self.KEY,
3690 ticket=self.TGT,
3691 additional_tickets=additional_tickets,
3692 u2u=self.U2U,
3693 debug=self.debug,
3694 )
3695 else:
3696 # Ask for TGT then ST
3697 res = krb_as_and_tgs(
3698 upn=self.UPN,
3699 spn=self.SPN,
3700 ip=self.DC_IP,
3701 key=self.KEY,
3702 password=self.PASSWORD,
3703 additional_tickets=additional_tickets,
3704 u2u=self.U2U,
3705 debug=self.debug,
3706 )
3707 if not res:
3708 # Failed to retrieve the ticket
3709 return Context, None, GSS_S_FAILURE
3710 self.ST, self.KEY = res.tgsrep.ticket, res.sessionkey
3711 elif not self.KEY:
3712 raise ValueError("Must provide KEY with ST")
3713 Context.STSessionKey = self.KEY
3714 # Save ServerHostname
3715 if len(self.ST.sname.nameString) == 2:
3716 Context.ServerHostname = self.ST.sname.nameString[1].val.decode()
3717 # Build the KRB-AP
3718 apOptions = ASN1_BIT_STRING("000")
3719 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG:
3720 apOptions.set(2, "1") # mutual-required
3721 if self.U2U:
3722 apOptions.set(1, "1") # use-session-key
3723 Context.U2U = True
3724 ap_req = KRB_AP_REQ(
3725 apOptions=apOptions,
3726 ticket=self.ST,
3727 authenticator=EncryptedData(),
3728 )
3729 # Build the authenticator
3730 now_time = datetime.utcnow().replace(microsecond=0, tzinfo=timezone.utc)
3731 Context.KrbSessionKey = Key.random_to_key(
3732 self.SKEY_TYPE,
3733 os.urandom(16),
3734 )
3735 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix()
3736 ap_req.authenticator.encrypt(
3737 Context.STSessionKey,
3738 KRB_Authenticator(
3739 crealm=self.ST.realm,
3740 cname=PrincipalName.fromUPN(self.UPN),
3741 # RFC 4121 checksum
3742 cksum=Checksum(
3743 cksumtype="KRB-AUTHENTICATOR",
3744 checksum=KRB_AuthenticatorChecksum(Flags=int(Context.flags)),
3745 ),
3746 ctime=ASN1_GENERALIZED_TIME(now_time),
3747 cusec=ASN1_INTEGER(0),
3748 subkey=EncryptionKey.fromKey(Context.KrbSessionKey),
3749 seqNumber=Context.SendSeqNum,
3750 encAuthorizationData=AuthorizationData(
3751 seq=[
3752 AuthorizationDataItem(
3753 adType="AD-IF-RELEVANT",
3754 adData=AuthorizationData(
3755 seq=[
3756 AuthorizationDataItem(
3757 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS",
3758 adData=KERB_AD_RESTRICTION_ENTRY(
3759 restriction=LSAP_TOKEN_INFO_INTEGRITY(
3760 MachineID=bytes(RandBin(32))
3761 )
3762 ),
3763 ),
3764 AuthorizationDataItem(
3765 adType="KERB-LOCAL",
3766 adData=b"\x00" * 16,
3767 ),
3768 ]
3769 ),
3770 )
3771 ]
3772 ),
3773 ),
3774 )
3775 Context.state = self.STATE.CLI_SENT_APREQ
3776 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE:
3777 # Raw kerberos DCE-STYLE
3778 return Context, ap_req, GSS_S_CONTINUE_NEEDED
3779 else:
3780 # Kerberos wrapper
3781 return (
3782 Context,
3783 KRB_GSSAPI_Token(
3784 innerToken=KRB_InnerToken(
3785 root=ap_req,
3786 )
3787 ),
3788 GSS_S_CONTINUE_NEEDED,
3789 )
3790
3791 elif Context.state == self.STATE.CLI_SENT_APREQ:
3792 if isinstance(val, KRB_AP_REP):
3793 # Raw AP_REP was passed
3794 ap_rep = val
3795 else:
3796 try:
3797 # GSSAPI / Kerberos
3798 ap_rep = val.root.innerToken.root
3799 except AttributeError:
3800 try:
3801 # Kerberos
3802 ap_rep = val.innerToken.root
3803 except AttributeError:
3804 try:
3805 # Raw kerberos DCE-STYLE
3806 ap_rep = val.root
3807 except AttributeError:
3808 return Context, None, GSS_S_DEFECTIVE_TOKEN
3809 if not isinstance(ap_rep, KRB_AP_REP):
3810 return Context, None, GSS_S_DEFECTIVE_TOKEN
3811 # Retrieve SessionKey
3812 repPart = ap_rep.encPart.decrypt(Context.STSessionKey)
3813 if repPart.subkey is not None:
3814 Context.SessionKey = repPart.subkey.keyvalue.val
3815 Context.KrbSessionKey = repPart.subkey.toKey()
3816 # OK !
3817 Context.state = self.STATE.CLI_RCVD_APREP
3818 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE:
3819 # [MS-KILE] sect 3.4.5.1
3820 # The client MUST generate an additional AP exchange reply message
3821 # exactly as the server would as the final message to send to the
3822 # server.
3823 now_time = datetime.utcnow().replace(microsecond=0, tzinfo=timezone.utc)
3824 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData())
3825 cli_ap_rep.encPart.encrypt(
3826 Context.STSessionKey,
3827 EncAPRepPart(
3828 ctime=ASN1_GENERALIZED_TIME(now_time),
3829 seqNumber=repPart.seqNumber,
3830 subkey=None,
3831 ),
3832 )
3833 return Context, cli_ap_rep, GSS_S_COMPLETE
3834 return Context, None, GSS_S_COMPLETE
3835 elif (
3836 Context.state == self.STATE.CLI_RCVD_APREP
3837 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE
3838 ):
3839 # DCE_STYLE with SPNEGOSSP
3840 return Context, None, GSS_S_COMPLETE
3841 else:
3842 raise ValueError("KerberosSSP: Unknown state")
3843
3844 def _setup_u2u(self):
3845 if not self.TGT:
3846 # Get a TGT for ourselves
3847 try:
3848 upn = "@".join(self.SPN.split("/")[1].split(".", 1))
3849 except KeyError:
3850 raise ValueError("Couldn't transform the SPN into a valid UPN")
3851 res = krb_as_req(upn, self.DC_IP, key=self.KEY)
3852 self.TGT, self.KEY = res.asrep.ticket, res.sessionkey
3853
3854 def GSS_Accept_sec_context(self, Context: CONTEXT, val=None):
3855 if Context is None:
3856 # New context
3857 Context = self.CONTEXT(IsAcceptor=True, req_flags=0)
3858
3859 from scapy.libs.rfc3961 import Key
3860
3861 if Context.state == self.STATE.INIT:
3862 if not self.SPN:
3863 raise ValueError("Missing SPN attribute")
3864 # Server receives AP-req, sends AP-rep
3865 if isinstance(val, KRB_AP_REQ):
3866 # Raw AP_REQ was passed
3867 ap_req = val
3868 else:
3869 try:
3870 # GSSAPI/Kerberos
3871 ap_req = val.root.innerToken.root
3872 except AttributeError:
3873 try:
3874 # Raw Kerberos
3875 ap_req = val.root
3876 except AttributeError:
3877 return Context, None, GSS_S_DEFECTIVE_TOKEN
3878 if isinstance(ap_req, KRB_TGT_REQ):
3879 # Special U2U case
3880 self._setup_u2u()
3881 Context.U2U = True
3882 return (
3883 None,
3884 KRB_GSSAPI_Token(
3885 MechType="1.2.840.113554.1.2.2.3", # U2U
3886 innerToken=KRB_InnerToken(
3887 TOK_ID=b"\x04\x01",
3888 root=KRB_TGT_REP(
3889 ticket=self.TGT,
3890 ),
3891 ),
3892 ),
3893 GSS_S_CONTINUE_NEEDED,
3894 )
3895 elif not isinstance(ap_req, KRB_AP_REQ):
3896 ap_req.show()
3897 raise ValueError("Unexpected type in KerberosSSP")
3898 if not self.KEY:
3899 raise ValueError("Missing KEY attribute")
3900 # Validate SPN
3901 tkt_spn = "/".join(
3902 x.val.decode() for x in ap_req.ticket.sname.nameString[:2]
3903 ).lower()
3904 if tkt_spn not in [self.SPN.lower(), self.SPN.lower().split(".", 1)[0]]:
3905 warning("KerberosSSP: bad SPN: %s != %s" % (tkt_spn, self.SPN))
3906 return Context, None, GSS_S_BAD_MECH
3907 # Enforce U2U if required
3908 if self.REQUIRE_U2U and ap_req.apOptions.val[1] != "1": # use-session-key
3909 # Required but not provided. Return an error
3910 self._setup_u2u()
3911 Context.U2U = True
3912 now_time = datetime.utcnow().replace(microsecond=0, tzinfo=timezone.utc)
3913 err = KRB_GSSAPI_Token(
3914 innerToken=KRB_InnerToken(
3915 TOK_ID=b"\x03\x00",
3916 root=KRB_ERROR(
3917 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED",
3918 stime=ASN1_GENERALIZED_TIME(now_time),
3919 realm=ap_req.ticket.realm,
3920 sname=ap_req.ticket.sname,
3921 eData=KRB_TGT_REP(
3922 ticket=self.TGT,
3923 ),
3924 ),
3925 )
3926 )
3927 return Context, err, GSS_S_CONTINUE_NEEDED
3928 # Decrypt the ticket
3929 try:
3930 tkt = ap_req.ticket.encPart.decrypt(self.KEY)
3931 except ValueError as ex:
3932 warning("KerberosSSP: %s (bad KEY?)" % ex)
3933 now_time = datetime.utcnow().replace(microsecond=0, tzinfo=timezone.utc)
3934 err = KRB_GSSAPI_Token(
3935 innerToken=KRB_InnerToken(
3936 TOK_ID=b"\x03\x00",
3937 root=KRB_ERROR(
3938 errorCode="KRB_AP_ERR_MODIFIED",
3939 stime=ASN1_GENERALIZED_TIME(now_time),
3940 realm=ap_req.ticket.realm,
3941 sname=ap_req.ticket.sname,
3942 eData=None,
3943 ),
3944 )
3945 )
3946 return Context, err, GSS_S_DEFECTIVE_TOKEN
3947 # Get AP-REP session key
3948 Context.STSessionKey = tkt.key.toKey()
3949 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey)
3950 # Compute an application session key ([MS-KILE] sect 3.1.1.2)
3951 subkey = None
3952 if ap_req.apOptions.val[2] == "1": # mutual-required
3953 appkey = Key.random_to_key(
3954 self.SKEY_TYPE,
3955 os.urandom(16),
3956 )
3957 Context.KrbSessionKey = appkey
3958 Context.SessionKey = appkey.key
3959 subkey = EncryptionKey.fromKey(appkey)
3960 else:
3961 Context.KrbSessionKey = self.KEY
3962 Context.SessionKey = self.KEY.key
3963 # Eventually process the "checksum"
3964 if authenticator.cksum:
3965 if authenticator.cksum.cksumtype == 0x8003:
3966 # KRB-Authenticator
3967 Context.flags = GSS_C_FLAGS(int(authenticator.cksum.checksum.Flags))
3968 # Build response (RFC4120 sect 3.2.4)
3969 ap_rep = KRB_AP_REP(encPart=EncryptedData())
3970 ap_rep.encPart.encrypt(
3971 Context.STSessionKey,
3972 EncAPRepPart(
3973 ctime=authenticator.ctime,
3974 cusec=authenticator.cusec,
3975 seqNumber=None,
3976 subkey=subkey,
3977 ),
3978 )
3979 Context.state = self.STATE.SRV_SENT_APREP
3980 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE:
3981 # [MS-KILE] sect 3.4.5.1
3982 return Context, ap_rep, GSS_S_CONTINUE_NEEDED
3983 return Context, ap_rep, GSS_S_COMPLETE # success
3984 elif (
3985 Context.state == self.STATE.SRV_SENT_APREP
3986 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE
3987 ):
3988 # [MS-KILE] sect 3.4.5.1
3989 # The server MUST receive the additional AP exchange reply message and
3990 # verify that the message is constructed correctly.
3991 if not val:
3992 return Context, None, GSS_S_DEFECTIVE_TOKEN
3993 # Server receives AP-req, sends AP-rep
3994 if isinstance(val, KRB_AP_REP):
3995 # Raw AP_REP was passed
3996 ap_rep = val
3997 else:
3998 try:
3999 # GSSAPI/Kerberos
4000 ap_rep = val.root.innerToken.root
4001 except AttributeError:
4002 try:
4003 # Raw Kerberos
4004 ap_rep = val.root
4005 except AttributeError:
4006 return Context, None, GSS_S_DEFECTIVE_TOKEN
4007 # Decrypt the AP-REP
4008 try:
4009 ap_rep.encPart.decrypt(Context.STSessionKey)
4010 except ValueError as ex:
4011 warning("KerberosSSP: %s (bad KEY?)" % ex)
4012 return Context, None, GSS_S_DEFECTIVE_TOKEN
4013 return Context, None, GSS_S_COMPLETE # success
4014 else:
4015 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state))
4016
4017 def GSS_Passive(self, Context: CONTEXT, val=None):
4018 if Context is None:
4019 Context = self.CONTEXT(True)
4020 Context.passive = True
4021
4022 if Context.state == self.STATE.INIT:
4023 Context, _, status = self.GSS_Accept_sec_context(Context, val)
4024 Context.state = self.STATE.CLI_SENT_APREQ
4025 return Context, status
4026 elif Context.state == self.STATE.CLI_SENT_APREQ:
4027 Context, _, status = self.GSS_Init_sec_context(Context, val)
4028 return Context, status
4029
4030 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False):
4031 if Context.IsAcceptor is not IsAcceptor:
4032 return
4033 # Swap everything
4034 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = (
4035 Context.RecvSealKeyUsage,
4036 Context.SendSealKeyUsage,
4037 )
4038 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = (
4039 Context.RecvSignKeyUsage,
4040 Context.SendSignKeyUsage,
4041 )
4042 Context.IsAcceptor = not Context.IsAcceptor
4043
4044 def MaximumSignatureLength(self, Context: CONTEXT):
4045 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG:
4046 # TODO: support DES
4047 if Context.KrbSessionKey.etype in [17, 18]: # AES
4048 return 76
4049 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC
4050 return 45
4051 else:
4052 raise NotImplementedError
4053 else:
4054 return 28
4055
4056 def canMechListMIC(self, Context: CONTEXT):
4057 return bool(Context.KrbSessionKey)