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