Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/layers/kerberos.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1597 statements  

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# Typing imports 

147from typing import ( 

148 Optional, 

149) 

150 

151 

152# kerberos APPLICATION 

153 

154 

155class ASN1_Class_KRB(ASN1_Class): 

156 name = "Kerberos" 

157 # APPLICATION + CONSTRUCTED = 0x40 | 0x20 

158 Token = 0x60 | 0 # GSSAPI 

159 Ticket = 0x60 | 1 

160 Authenticator = 0x60 | 2 

161 EncTicketPart = 0x60 | 3 

162 AS_REQ = 0x60 | 10 

163 AS_REP = 0x60 | 11 

164 TGS_REQ = 0x60 | 12 

165 TGS_REP = 0x60 | 13 

166 AP_REQ = 0x60 | 14 

167 AP_REP = 0x60 | 15 

168 PRIV = 0x60 | 21 

169 CRED = 0x60 | 22 

170 EncASRepPart = 0x60 | 25 

171 EncTGSRepPart = 0x60 | 26 

172 EncAPRepPart = 0x60 | 27 

173 EncKrbPrivPart = 0x60 | 28 

174 EncKrbCredPart = 0x60 | 29 

175 ERROR = 0x60 | 30 

176 

177 

178# RFC4120 sect 5.2 

179 

180 

181KerberosString = ASN1F_GENERAL_STRING 

182Realm = KerberosString 

183Int32 = ASN1F_INTEGER 

184UInt32 = ASN1F_INTEGER 

185 

186_PRINCIPAL_NAME_TYPES = { 

187 0: "NT-UNKNOWN", 

188 1: "NT-PRINCIPAL", 

189 2: "NT-SRV-INST", 

190 3: "NT-SRV-HST", 

191 4: "NT-SRV-XHST", 

192 5: "NT-UID", 

193 6: "NT-X500-PRINCIPAL", 

194 7: "NT-SMTP-NAME", 

195 10: "NT-ENTERPRISE", 

196} 

197 

198 

199class PrincipalName(ASN1_Packet): 

200 ASN1_codec = ASN1_Codecs.BER 

201 ASN1_root = ASN1F_SEQUENCE( 

202 ASN1F_enum_INTEGER( 

203 "nameType", 

204 0, 

205 _PRINCIPAL_NAME_TYPES, 

206 explicit_tag=0xA0, 

207 ), 

208 ASN1F_SEQUENCE_OF("nameString", [], KerberosString, explicit_tag=0xA1), 

209 ) 

210 

211 def toString(self): 

212 """ 

213 Convert a PrincipalName back into its string representation. 

214 """ 

215 return "/".join(x.val.decode() for x in self.nameString) 

216 

217 @staticmethod 

218 def fromUPN(upn: str): 

219 """ 

220 Create a PrincipalName from a UPN string. 

221 """ 

222 user, _ = _parse_upn(upn) 

223 return PrincipalName( 

224 nameString=[ASN1_GENERAL_STRING(user)], 

225 nameType=ASN1_INTEGER(1), # NT-PRINCIPAL 

226 ) 

227 

228 @staticmethod 

229 def fromSPN(spn: str): 

230 """ 

231 Create a PrincipalName from a SPN string. 

232 """ 

233 spn, _ = _parse_spn(spn) 

234 if spn.startswith("krbtgt"): 

235 return PrincipalName( 

236 nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")], 

237 nameType=ASN1_INTEGER(2), # NT-SRV-INST 

238 ) 

239 elif "/" in spn: 

240 return PrincipalName( 

241 nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")], 

242 nameType=ASN1_INTEGER(3), # NT-SRV-HST 

243 ) 

244 else: 

245 # In case of U2U 

246 return PrincipalName( 

247 nameString=[ASN1_GENERAL_STRING(spn)], 

248 nameType=ASN1_INTEGER(1), # NT-PRINCIPAL 

249 ) 

250 

251 

252KerberosTime = ASN1F_GENERALIZED_TIME 

253Microseconds = ASN1F_INTEGER 

254 

255 

256# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1 

257 

258_KRB_E_TYPES = { 

259 1: "DES-CBC-CRC", 

260 2: "DES-CBC-MD4", 

261 3: "DES-CBC-MD5", 

262 5: "DES3-CBC-MD5", 

263 7: "DES3-CBC-SHA1", 

264 9: "DSAWITHSHA1-CMSOID", 

265 10: "MD5WITHRSAENCRYPTION-CMSOID", 

266 11: "SHA1WITHRSAENCRYPTION-CMSOID", 

267 12: "RC2CBC-ENVOID", 

268 13: "RSAENCRYPTION-ENVOID", 

269 14: "RSAES-OAEP-ENV-OID", 

270 15: "DES-EDE3-CBC-ENV-OID", 

271 16: "DES3-CBC-SHA1-KD", 

272 17: "AES128-CTS-HMAC-SHA1-96", 

273 18: "AES256-CTS-HMAC-SHA1-96", 

274 19: "AES128-CTS-HMAC-SHA256-128", 

275 20: "AES256-CTS-HMAC-SHA384-192", 

276 23: "RC4-HMAC", 

277 24: "RC4-HMAC-EXP", 

278 25: "CAMELLIA128-CTS-CMAC", 

279 26: "CAMELLIA256-CTS-CMAC", 

280} 

281 

282# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-2 

283 

284_KRB_S_TYPES = { 

285 1: "CRC32", 

286 2: "RSA-MD4", 

287 3: "RSA-MD4-DES", 

288 4: "DES-MAC", 

289 5: "DES-MAC-K", 

290 6: "RSA-MD4-DES-K", 

291 7: "RSA-MD5", 

292 8: "RSA-MD5-DES", 

293 9: "RSA-MD5-DES3", 

294 10: "SHA1", 

295 12: "HMAC-SHA1-DES3-KD", 

296 13: "HMAC-SHA1-DES3", 

297 14: "SHA1", 

298 15: "HMAC-SHA1-96-AES128", 

299 16: "HMAC-SHA1-96-AES256", 

300 17: "CMAC-CAMELLIA128", 

301 18: "CMAC-CAMELLIA256", 

302 19: "HMAC-SHA256-128-AES128", 

303 20: "HMAC-SHA384-192-AES256", 

304 # RFC 4121 

305 0x8003: "KRB-AUTHENTICATOR", 

306 # [MS-KILE] 

307 0xFFFFFF76: "MD5", 

308 -138: "MD5", 

309} 

310 

311 

312class EncryptedData(ASN1_Packet): 

313 ASN1_codec = ASN1_Codecs.BER 

314 ASN1_root = ASN1F_SEQUENCE( 

315 ASN1F_enum_INTEGER("etype", 0x17, _KRB_E_TYPES, explicit_tag=0xA0), 

316 ASN1F_optional(UInt32("kvno", None, explicit_tag=0xA1)), 

317 ASN1F_STRING("cipher", "", explicit_tag=0xA2), 

318 ) 

319 

320 def get_usage(self): 

321 """ 

322 Get current key usage number and encrypted class 

323 """ 

324 # RFC 4120 sect 7.5.1 

325 if self.underlayer: 

326 if isinstance(self.underlayer, PADATA): 

327 patype = self.underlayer.padataType 

328 if patype == 2: 

329 # AS-REQ PA-ENC-TIMESTAMP padata timestamp 

330 return 1, PA_ENC_TS_ENC 

331 elif patype == 138: 

332 # RFC6113 PA-ENC-TS-ENC 

333 return 54, PA_ENC_TS_ENC 

334 elif isinstance(self.underlayer, KRB_Ticket): 

335 # AS-REP Ticket and TGS-REP Ticket 

336 return 2, EncTicketPart 

337 elif isinstance(self.underlayer, KRB_AS_REP): 

338 # AS-REP encrypted part 

339 return 3, EncASRepPart 

340 elif isinstance(self.underlayer, KRB_AP_REQ) and isinstance( 

341 self.underlayer.underlayer, PADATA 

342 ): 

343 # TGS-REQ PA-TGS-REQ Authenticator 

344 return 7, KRB_Authenticator 

345 elif isinstance(self.underlayer, KRB_TGS_REP): 

346 # TGS-REP encrypted part 

347 return 8, EncTGSRepPart 

348 elif isinstance(self.underlayer, KRB_AP_REQ): 

349 # AP-REQ Authenticator 

350 return 11, KRB_Authenticator 

351 elif isinstance(self.underlayer, KRB_AP_REP): 

352 # AP-REP encrypted part 

353 return 12, EncAPRepPart 

354 elif isinstance(self.underlayer, KRB_PRIV): 

355 # KRB-PRIV encrypted part 

356 return 13, EncKrbPrivPart 

357 elif isinstance(self.underlayer, KRB_CRED): 

358 # KRB-CRED encrypted part 

359 return 14, EncKrbCredPart 

360 elif isinstance(self.underlayer, KrbFastArmoredReq): 

361 # KEY_USAGE_FAST_ENC 

362 return 51, KrbFastReq 

363 elif isinstance(self.underlayer, KrbFastArmoredRep): 

364 # KEY_USAGE_FAST_REP 

365 return 52, KrbFastResponse 

366 raise ValueError( 

367 "Could not guess key usage number. Please specify key_usage_number" 

368 ) 

369 

370 def decrypt(self, key, key_usage_number=None, cls=None): 

371 """ 

372 Decrypt and return the data contained in cipher. 

373 

374 :param key: the key to use for decryption 

375 :param key_usage_number: (optional) specify the key usage number. 

376 Guessed otherwise 

377 :param cls: (optional) the class of the decrypted payload 

378 Guessed otherwise (or bytes) 

379 """ 

380 if key_usage_number is None: 

381 key_usage_number, cls = self.get_usage() 

382 d = key.decrypt(key_usage_number, self.cipher.val) 

383 if cls: 

384 try: 

385 return cls(d) 

386 except BER_Decoding_Error: 

387 if cls == EncASRepPart: 

388 # https://datatracker.ietf.org/doc/html/rfc4120#section-5.4.2 

389 # "Compatibility note: Some implementations unconditionally send an 

390 # encrypted EncTGSRepPart (application tag number 26) in this field 

391 # regardless of whether the reply is a AS-REP or a TGS-REP. In the 

392 # interest of compatibility, implementors MAY relax the check on the 

393 # tag number of the decrypted ENC-PART." 

394 try: 

395 res = EncTGSRepPart(d) 

396 # https://github.com/krb5/krb5/blob/48ccd81656381522d1f9ccb8705c13f0266a46ab/src/lib/krb5/asn.1/asn1_k_encode.c#L1128 

397 # This is a bug because as the RFC clearly says above, we're 

398 # perfectly in our right to be strict on this. (MAY) 

399 log_runtime.warning( 

400 "Implementation bug detected. This looks like MIT Kerberos." 

401 ) 

402 return res 

403 except BER_Decoding_Error: 

404 pass 

405 raise 

406 return d 

407 

408 def encrypt(self, key, text, confounder=None, key_usage_number=None): 

409 """ 

410 Encrypt text and set it into cipher. 

411 

412 :param key: the key to use for encryption 

413 :param text: the bytes value to encode 

414 :param confounder: (optional) specify the confounder bytes. Random otherwise 

415 :param key_usage_number: (optional) specify the key usage number. 

416 Guessed otherwise 

417 """ 

418 if key_usage_number is None: 

419 key_usage_number = self.get_usage()[0] 

420 self.etype = key.etype 

421 self.cipher = ASN1_STRING( 

422 key.encrypt(key_usage_number, text, confounder=confounder) 

423 ) 

424 

425 

426class EncryptionKey(ASN1_Packet): 

427 ASN1_codec = ASN1_Codecs.BER 

428 ASN1_root = ASN1F_SEQUENCE( 

429 ASN1F_enum_INTEGER("keytype", 0, _KRB_E_TYPES, explicit_tag=0xA0), 

430 ASN1F_STRING("keyvalue", "", explicit_tag=0xA1), 

431 ) 

432 

433 def toKey(self): 

434 from scapy.libs.rfc3961 import Key 

435 

436 return Key( 

437 etype=self.keytype.val, 

438 key=self.keyvalue.val, 

439 ) 

440 

441 @classmethod 

442 def fromKey(self, key): 

443 return EncryptionKey( 

444 keytype=key.etype, 

445 keyvalue=key.key, 

446 ) 

447 

448 

449class _Checksum_Field(ASN1F_STRING_PacketField): 

450 def m2i(self, pkt, s): 

451 val = super(_Checksum_Field, self).m2i(pkt, s) 

452 if not val[0].val: 

453 return val 

454 if pkt.cksumtype.val == 0x8003: 

455 # Special case per RFC 4121 

456 return KRB_AuthenticatorChecksum(val[0].val, _underlayer=pkt), val[1] 

457 return val 

458 

459 

460class Checksum(ASN1_Packet): 

461 ASN1_codec = ASN1_Codecs.BER 

462 ASN1_root = ASN1F_SEQUENCE( 

463 ASN1F_enum_INTEGER( 

464 "cksumtype", 

465 0, 

466 _KRB_S_TYPES, 

467 explicit_tag=0xA0, 

468 ), 

469 _Checksum_Field("checksum", "", explicit_tag=0xA1), 

470 ) 

471 

472 def get_usage(self): 

473 """ 

474 Get current key usage number 

475 """ 

476 # RFC 4120 sect 7.5.1 

477 if self.underlayer: 

478 if isinstance(self.underlayer, KRB_Authenticator): 

479 # TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum 

480 # (n°10 should never happen as we use RFC4121) 

481 return 6 

482 elif isinstance(self.underlayer, PA_FOR_USER): 

483 # [MS-SFU] sect 2.2.1 

484 return 17 

485 elif isinstance(self.underlayer, PA_S4U_X509_USER): 

486 # [MS-SFU] sect 2.2.2 

487 return 26 

488 elif isinstance(self.underlayer, AD_KDCIssued): 

489 # AD-KDC-ISSUED checksum 

490 return 19 

491 elif isinstance(self.underlayer, KrbFastArmoredReq): 

492 # KEY_USAGE_FAST_REQ_CHKSUM 

493 return 50 

494 elif isinstance(self.underlayer, KrbFastFinished): 

495 # KEY_USAGE_FAST_FINISHED 

496 return 53 

497 raise ValueError( 

498 "Could not guess key usage number. Please specify key_usage_number" 

499 ) 

500 

501 def verify(self, key, text, key_usage_number=None): 

502 """ 

503 Decrypt and return the data contained in cipher. 

504 

505 :param key: the key to use to check the checksum 

506 :param text: the bytes to verify 

507 :param key_usage_number: (optional) specify the key usage number. 

508 Guessed otherwise 

509 """ 

510 if key_usage_number is None: 

511 key_usage_number = self.get_usage() 

512 key.verify_checksum(key_usage_number, text, self.checksum.val) 

513 

514 def make(self, key, text, key_usage_number=None, cksumtype=None): 

515 """ 

516 Encrypt text and set it into cipher. 

517 

518 :param key: the key to use to make the checksum 

519 :param text: the bytes to make a checksum of 

520 :param key_usage_number: (optional) specify the key usage number. 

521 Guessed otherwise 

522 """ 

523 if key_usage_number is None: 

524 key_usage_number = self.get_usage() 

525 self.cksumtype = cksumtype or key.cksumtype 

526 self.checksum = ASN1_STRING( 

527 key.make_checksum( 

528 keyusage=key_usage_number, 

529 text=text, 

530 cksumtype=self.cksumtype, 

531 ) 

532 ) 

533 

534 

535KerberosFlags = ASN1F_FLAGS 

536 

537_ADDR_TYPES = { 

538 # RFC4120 sect 7.5.3 

539 0x02: "IPv4", 

540 0x03: "Directional", 

541 0x05: "ChaosNet", 

542 0x06: "XNS", 

543 0x07: "ISO", 

544 0x0C: "DECNET Phase IV", 

545 0x10: "AppleTalk DDP", 

546 0x14: "NetBios", 

547 0x18: "IPv6", 

548} 

549 

550 

551class HostAddress(ASN1_Packet): 

552 ASN1_codec = ASN1_Codecs.BER 

553 ASN1_root = ASN1F_SEQUENCE( 

554 ASN1F_enum_INTEGER( 

555 "addrType", 

556 0, 

557 _ADDR_TYPES, 

558 explicit_tag=0xA0, 

559 ), 

560 ASN1F_STRING("address", "", explicit_tag=0xA1), 

561 ) 

562 

563 

564HostAddresses = lambda name, **kwargs: ASN1F_SEQUENCE_OF( 

565 name, [], HostAddress, **kwargs 

566) 

567 

568 

569_AUTHORIZATIONDATA_VALUES = { 

570 # Filled below 

571} 

572 

573 

574class _AuthorizationData_value_Field(ASN1F_STRING_PacketField): 

575 def m2i(self, pkt, s): 

576 val = super(_AuthorizationData_value_Field, self).m2i(pkt, s) 

577 if not val[0].val: 

578 return val 

579 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES: 

580 return ( 

581 _AUTHORIZATIONDATA_VALUES[pkt.adType.val](val[0].val, _underlayer=pkt), 

582 val[1], 

583 ) 

584 return val 

585 

586 

587_AD_TYPES = { 

588 # RFC4120 sect 7.5.4 

589 1: "AD-IF-RELEVANT", 

590 2: "AD-INTENDED-FOR-SERVER", 

591 3: "AD-INTENDED-FOR-APPLICATION-CLASS", 

592 4: "AD-KDC-ISSUED", 

593 5: "AD-AND-OR", 

594 6: "AD-MANDATORY-TICKET-EXTENSIONS", 

595 7: "AD-IN-TICKET-EXTENSIONS", 

596 8: "AD-MANDATORY-FOR-KDC", 

597 64: "OSF-DCE", 

598 65: "SESAME", 

599 66: "AD-OSD-DCE-PKI-CERTID", 

600 128: "AD-WIN2K-PAC", 

601 129: "AD-ETYPE-NEGOTIATION", 

602 # [MS-KILE] additions 

603 141: "KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

604 142: "KERB-LOCAL", 

605 143: "AD-AUTH-DATA-AP-OPTIONS", 

606 144: "KERB-AUTH-DATA-CLIENT-TARGET", 

607} 

608 

609 

610class AuthorizationDataItem(ASN1_Packet): 

611 ASN1_codec = ASN1_Codecs.BER 

612 ASN1_root = ASN1F_SEQUENCE( 

613 ASN1F_enum_INTEGER( 

614 "adType", 

615 0, 

616 _AD_TYPES, 

617 explicit_tag=0xA0, 

618 ), 

619 _AuthorizationData_value_Field("adData", "", explicit_tag=0xA1), 

620 ) 

621 

622 

623class AuthorizationData(ASN1_Packet): 

624 ASN1_codec = ASN1_Codecs.BER 

625 ASN1_root = ASN1F_SEQUENCE_OF( 

626 "seq", [AuthorizationDataItem()], AuthorizationDataItem 

627 ) 

628 

629 def getAuthData(self, adType): 

630 return next((x.adData for x in self.seq if x.adType == adType), None) 

631 

632 

633AD_IF_RELEVANT = AuthorizationData 

634_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT 

635 

636 

637class AD_KDCIssued(ASN1_Packet): 

638 ASN1_codec = ASN1_Codecs.BER 

639 ASN1_root = ASN1F_SEQUENCE( 

640 ASN1F_PACKET("adChecksum", Checksum(), Checksum, explicit_tag=0xA0), 

641 ASN1F_optional( 

642 Realm("iRealm", "", explicit_tag=0xA1), 

643 ), 

644 ASN1F_optional(ASN1F_PACKET("iSname", None, PrincipalName, explicit_tag=0xA2)), 

645 ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA3), 

646 ) 

647 

648 

649_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued 

650 

651 

652class AD_AND_OR(ASN1_Packet): 

653 ASN1_codec = ASN1_Codecs.BER 

654 ASN1_root = ASN1F_SEQUENCE( 

655 Int32("conditionCount", 0, explicit_tag=0xA0), 

656 ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA1), 

657 ) 

658 

659 

660_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR 

661 

662ADMANDATORYFORKDC = AuthorizationData 

663_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC 

664 

665 

666# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xml 

667_PADATA_TYPES = { 

668 1: "PA-TGS-REQ", 

669 2: "PA-ENC-TIMESTAMP", 

670 3: "PA-PW-SALT", 

671 11: "PA-ETYPE-INFO", 

672 14: "PA-PK-AS-REQ-OLD", 

673 15: "PA-PK-AS-REP-OLD", 

674 16: "PA-PK-AS-REQ", 

675 17: "PA-PK-AS-REP", 

676 19: "PA-ETYPE-INFO2", 

677 20: "PA-SVR-REFERRAL-INFO", 

678 111: "TD-CMS-DIGEST-ALGORITHMS", 

679 128: "PA-PAC-REQUEST", 

680 129: "PA-FOR-USER", 

681 130: "PA-FOR-X509-USER", 

682 131: "PA-FOR-CHECK_DUPS", 

683 132: "PA-AS-CHECKSUM", 

684 133: "PA-FX-COOKIE", 

685 134: "PA-AUTHENTICATION-SET", 

686 135: "PA-AUTH-SET-SELECTED", 

687 136: "PA-FX-FAST", 

688 137: "PA-FX-ERROR", 

689 138: "PA-ENCRYPTED-CHALLENGE", 

690 141: "PA-OTP-CHALLENGE", 

691 142: "PA-OTP-REQUEST", 

692 143: "PA-OTP-CONFIRM", 

693 144: "PA-OTP-PIN-CHANGE", 

694 145: "PA-EPAK-AS-REQ", 

695 146: "PA-EPAK-AS-REP", 

696 147: "PA-PKINIT-KX", 

697 148: "PA-PKU2U-NAME", 

698 149: "PA-REQ-ENC-PA-REP", 

699 150: "PA-AS-FRESHNESS", 

700 151: "PA-SPAKE", 

701 161: "KERB-KEY-LIST-REQ", 

702 162: "KERB-KEY-LIST-REP", 

703 165: "PA-SUPPORTED-ENCTYPES", 

704 166: "PA-EXTENDED-ERROR", 

705 167: "PA-PAC-OPTIONS", 

706 170: "KERB-SUPERSEDED-BY-USER", 

707 171: "KERB-DMSA-KEY-PACKAGE", 

708} 

709 

710_PADATA_CLASSES = { 

711 # Filled elsewhere in this file 

712} 

713 

714 

715# RFC4120 

716 

717 

718class _PADATA_value_Field(ASN1F_STRING_PacketField): 

719 """ 

720 A special field that properly dispatches PA-DATA values according to 

721 padata-type and if the paquet is a request or a response. 

722 """ 

723 

724 def m2i(self, pkt, s): 

725 val = super(_PADATA_value_Field, self).m2i(pkt, s) 

726 if pkt.padataType.val in _PADATA_CLASSES: 

727 cls = _PADATA_CLASSES[pkt.padataType.val] 

728 if isinstance(cls, tuple): 

729 parent = pkt.underlayer or pkt.parent 

730 is_reply = False 

731 if parent is not None: 

732 if isinstance(parent, (KRB_AS_REP, KRB_TGS_REP)): 

733 is_reply = True 

734 else: 

735 parent = parent.underlayer or parent.parent 

736 is_reply = isinstance(parent, KRB_ERROR) 

737 cls = cls[is_reply] 

738 if not val[0].val: 

739 return val 

740 return cls(val[0].val, _underlayer=pkt), val[1] 

741 return val 

742 

743 

744class PADATA(ASN1_Packet): 

745 ASN1_codec = ASN1_Codecs.BER 

746 ASN1_root = ASN1F_SEQUENCE( 

747 ASN1F_enum_INTEGER("padataType", 0, _PADATA_TYPES, explicit_tag=0xA1), 

748 _PADATA_value_Field( 

749 "padataValue", 

750 "", 

751 explicit_tag=0xA2, 

752 ), 

753 ) 

754 

755 

756# RFC 4120 sect 5.2.7.2 

757 

758 

759class PA_ENC_TS_ENC(ASN1_Packet): 

760 ASN1_codec = ASN1_Codecs.BER 

761 ASN1_root = ASN1F_SEQUENCE( 

762 KerberosTime("patimestamp", GeneralizedTime(), explicit_tag=0xA0), 

763 ASN1F_optional(Microseconds("pausec", 0, explicit_tag=0xA1)), 

764 ) 

765 

766 

767_PADATA_CLASSES[2] = EncryptedData # PA-ENC-TIMESTAMP 

768_PADATA_CLASSES[138] = EncryptedData # PA-ENCRYPTED-CHALLENGE 

769 

770 

771# RFC 4120 sect 5.2.7.4 

772 

773 

774class ETYPE_INFO_ENTRY(ASN1_Packet): 

775 ASN1_codec = ASN1_Codecs.BER 

776 ASN1_root = ASN1F_SEQUENCE( 

777 ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0), 

778 ASN1F_optional( 

779 ASN1F_STRING("salt", "", explicit_tag=0xA1), 

780 ), 

781 ) 

782 

783 

784class ETYPE_INFO(ASN1_Packet): 

785 ASN1_codec = ASN1_Codecs.BER 

786 ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY()], ETYPE_INFO_ENTRY) 

787 

788 

789_PADATA_CLASSES[11] = ETYPE_INFO 

790 

791# RFC 4120 sect 5.2.7.5 

792 

793 

794class ETYPE_INFO_ENTRY2(ASN1_Packet): 

795 ASN1_codec = ASN1_Codecs.BER 

796 ASN1_root = ASN1F_SEQUENCE( 

797 ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0), 

798 ASN1F_optional( 

799 KerberosString("salt", "", explicit_tag=0xA1), 

800 ), 

801 ASN1F_optional( 

802 ASN1F_STRING("s2kparams", "", explicit_tag=0xA2), 

803 ), 

804 ) 

805 

806 

807class ETYPE_INFO2(ASN1_Packet): 

808 ASN1_codec = ASN1_Codecs.BER 

809 ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY2()], ETYPE_INFO_ENTRY2) 

810 

811 

812_PADATA_CLASSES[19] = ETYPE_INFO2 

813 

814 

815# RFC8636 - PKINIT Algorithm Agility 

816 

817 

818class TD_CMS_DIGEST_ALGORITHMS(ASN1_Packet): 

819 ASN1_codec = ASN1_Codecs.BER 

820 ASN1_root = ASN1F_SEQUENCE_OF("seq", [], X509_AlgorithmIdentifier) 

821 

822 

823_PADATA_CLASSES[111] = TD_CMS_DIGEST_ALGORITHMS 

824 

825 

826# PADATA Extended with RFC6113 

827 

828 

829class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet): 

830 ASN1_codec = ASN1_Codecs.BER 

831 ASN1_root = ASN1F_SEQUENCE( 

832 Int32("paType", 0, explicit_tag=0xA0), 

833 ASN1F_optional( 

834 ASN1F_STRING("paHint", "", explicit_tag=0xA1), 

835 ), 

836 ASN1F_optional( 

837 ASN1F_STRING("paValue", "", explicit_tag=0xA2), 

838 ), 

839 ) 

840 

841 

842class PA_AUTHENTICATION_SET(ASN1_Packet): 

843 ASN1_codec = ASN1_Codecs.BER 

844 ASN1_root = ASN1F_SEQUENCE_OF( 

845 "elems", [PA_AUTHENTICATION_SET_ELEM()], PA_AUTHENTICATION_SET_ELEM 

846 ) 

847 

848 

849_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET 

850 

851 

852# [MS-KILE] sect 2.2.3 

853 

854 

855class PA_PAC_REQUEST(ASN1_Packet): 

856 ASN1_codec = ASN1_Codecs.BER 

857 ASN1_root = ASN1F_SEQUENCE( 

858 ASN1F_BOOLEAN("includePac", True, explicit_tag=0xA0), 

859 ) 

860 

861 

862_PADATA_CLASSES[128] = PA_PAC_REQUEST 

863 

864 

865# [MS-KILE] sect 2.2.5 

866 

867 

868class LSAP_TOKEN_INFO_INTEGRITY(Packet): 

869 fields_desc = [ 

870 FlagsField( 

871 "Flags", 

872 0, 

873 -32, 

874 { 

875 0x00000001: "UAC-Restricted", 

876 }, 

877 ), 

878 LEIntEnumField( 

879 "TokenIL", 

880 0x00002000, 

881 { 

882 0x00000000: "Untrusted", 

883 0x00001000: "Low", 

884 0x00002000: "Medium", 

885 0x00003000: "High", 

886 0x00004000: "System", 

887 0x00005000: "Protected process", 

888 }, 

889 ), 

890 XStrFixedLenField("MachineID", b"", length=32), 

891 ] 

892 

893 

894# [MS-KILE] sect 2.2.6 

895 

896 

897class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField): 

898 def m2i(self, pkt, s): 

899 val = super(_KerbAdRestrictionEntry_Field, self).m2i(pkt, s) 

900 if not val[0].val: 

901 return val 

902 if pkt.restrictionType.val == 0x0000: # LSAP_TOKEN_INFO_INTEGRITY 

903 return LSAP_TOKEN_INFO_INTEGRITY(val[0].val, _underlayer=pkt), val[1] 

904 return val 

905 

906 

907class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet): 

908 name = "KERB-AD-RESTRICTION-ENTRY" 

909 ASN1_codec = ASN1_Codecs.BER 

910 ASN1_root = ASN1F_SEQUENCE( 

911 ASN1F_SEQUENCE( 

912 ASN1F_enum_INTEGER( 

913 "restrictionType", 

914 0, 

915 {0: "LSAP_TOKEN_INFO_INTEGRITY"}, 

916 explicit_tag=0xA0, 

917 ), 

918 _KerbAdRestrictionEntry_Field("restriction", b"", explicit_tag=0xA1), 

919 ) 

920 ) 

921 

922 

923_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY 

924 

925 

926# [MS-KILE] sect 3.2.5.8 

927 

928 

929class KERB_AUTH_DATA_AP_OPTIONS(Packet): 

930 name = "KERB-AUTH-DATA-AP-OPTIONS" 

931 fields_desc = [ 

932 LEIntEnumField( 

933 "apOptions", 

934 0x4000, 

935 { 

936 0x4000: "KERB_AP_OPTIONS_CBT", 

937 0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME", 

938 }, 

939 ), 

940 ] 

941 

942 

943_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS 

944 

945 

946# This has no doc..? [MS-KILE] only mentions its name. 

947 

948 

949class KERB_AUTH_DATA_CLIENT_TARGET(Packet): 

950 name = "KERB-AD-TARGET-PRINCIPAL" 

951 fields_desc = [ 

952 StrFieldUtf16("spn", ""), 

953 ] 

954 

955 

956_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET 

957 

958 

959# RFC6806 sect 6 

960 

961 

962class KERB_AD_LOGIN_ALIAS(ASN1_Packet): 

963 ASN1_codec = ASN1_Codecs.BER 

964 ASN1_root = ASN1F_SEQUENCE(ASN1F_SEQUENCE_OF("loginAliases", [], PrincipalName)) 

965 

966 

967_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS 

968 

969 

970# [MS-KILE] sect 2.2.8 

971 

972 

973class PA_SUPPORTED_ENCTYPES(Packet): 

974 fields_desc = [ 

975 FlagsField( 

976 "flags", 

977 0, 

978 -32, 

979 [ 

980 "DES-CBC-CRC", 

981 "DES-CBC-MD5", 

982 "RC4-HMAC", 

983 "AES128-CTS-HMAC-SHA1-96", 

984 "AES256-CTS-HMAC-SHA1-96", 

985 ] 

986 + ["bit_%d" % i for i in range(11)] 

987 + [ 

988 "FAST-supported", 

989 "Compount-identity-supported", 

990 "Claims-supported", 

991 "Resource-SID-compression-disabled", 

992 ], 

993 ) 

994 ] 

995 

996 

997_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES 

998 

999# [MS-KILE] sect 2.2.10 

1000 

1001 

1002class PA_PAC_OPTIONS(ASN1_Packet): 

1003 ASN1_codec = ASN1_Codecs.BER 

1004 ASN1_root = ASN1F_SEQUENCE( 

1005 KerberosFlags( 

1006 "options", 

1007 "", 

1008 [ 

1009 "Claims", 

1010 "Branch-Aware", 

1011 "Forward-to-Full-DC", 

1012 "Resource-based-constrained-delegation", # [MS-SFU] 2.2.5 

1013 ], 

1014 explicit_tag=0xA0, 

1015 ) 

1016 ) 

1017 

1018 

1019_PADATA_CLASSES[167] = PA_PAC_OPTIONS 

1020 

1021# [MS-KILE] sect 2.2.11 

1022 

1023 

1024class KERB_KEY_LIST_REQ(ASN1_Packet): 

1025 ASN1_codec = ASN1_Codecs.BER 

1026 ASN1_root = ASN1F_SEQUENCE_OF( 

1027 "keytypes", 

1028 [], 

1029 ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES), 

1030 ) 

1031 

1032 

1033_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ 

1034 

1035# [MS-KILE] sect 2.2.12 

1036 

1037 

1038class KERB_KEY_LIST_REP(ASN1_Packet): 

1039 ASN1_codec = ASN1_Codecs.BER 

1040 ASN1_root = ASN1F_SEQUENCE_OF( 

1041 "keys", 

1042 [], 

1043 ASN1F_PACKET("", None, EncryptionKey), 

1044 ) 

1045 

1046 

1047_PADATA_CLASSES[162] = KERB_KEY_LIST_REP 

1048 

1049# [MS-KILE] sect 2.2.13 

1050 

1051 

1052class KERB_SUPERSEDED_BY_USER(ASN1_Packet): 

1053 ASN1_codec = ASN1_Codecs.BER 

1054 ASN1_root = ASN1F_SEQUENCE( 

1055 ASN1F_PACKET("name", None, PrincipalName, explicit_tag=0xA0), 

1056 Realm("realm", None, explicit_tag=0xA1), 

1057 ) 

1058 

1059 

1060_PADATA_CLASSES[170] = KERB_SUPERSEDED_BY_USER 

1061 

1062 

1063# [MS-KILE] sect 2.2.14 

1064 

1065 

1066class KERB_DMSA_KEY_PACKAGE(ASN1_Packet): 

1067 ASN1_codec = ASN1_Codecs.BER 

1068 ASN1_root = ASN1F_SEQUENCE( 

1069 ASN1F_SEQUENCE_OF( 

1070 "currentKeys", 

1071 [], 

1072 ASN1F_PACKET("", None, EncryptionKey), 

1073 explicit_tag=0xA0, 

1074 ), 

1075 ASN1F_optional( 

1076 ASN1F_SEQUENCE_OF( 

1077 "previousKeys", 

1078 [], 

1079 ASN1F_PACKET("", None, EncryptionKey), 

1080 explicit_tag=0xA1, 

1081 ), 

1082 ), 

1083 KerberosTime("expirationInterval", GeneralizedTime(), explicit_tag=0xA2), 

1084 KerberosTime("fetchInterval", GeneralizedTime(), explicit_tag=0xA4), 

1085 ) 

1086 

1087 

1088_PADATA_CLASSES[171] = KERB_DMSA_KEY_PACKAGE 

1089 

1090 

1091# RFC6113 sect 5.4.1 

1092 

1093 

1094class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField): 

1095 def m2i(self, pkt, s): 

1096 val = super(_KrbFastArmor_value_Field, self).m2i(pkt, s) 

1097 if not val[0].val: 

1098 return val 

1099 if pkt.armorType.val == 1: # FX_FAST_ARMOR_AP_REQUEST 

1100 return KRB_AP_REQ(val[0].val, _underlayer=pkt), val[1] 

1101 return val 

1102 

1103 

1104class KrbFastArmor(ASN1_Packet): 

1105 ASN1_codec = ASN1_Codecs.BER 

1106 ASN1_root = ASN1F_SEQUENCE( 

1107 ASN1F_enum_INTEGER( 

1108 "armorType", 1, {1: "FX_FAST_ARMOR_AP_REQUEST"}, explicit_tag=0xA0 

1109 ), 

1110 _KrbFastArmor_value_Field("armorValue", "", explicit_tag=0xA1), 

1111 ) 

1112 

1113 

1114# RFC6113 sect 5.4.2 

1115 

1116 

1117class KrbFastArmoredReq(ASN1_Packet): 

1118 ASN1_codec = ASN1_Codecs.BER 

1119 ASN1_root = ASN1F_SEQUENCE( 

1120 ASN1F_SEQUENCE( 

1121 ASN1F_optional( 

1122 ASN1F_PACKET("armor", None, KrbFastArmor, explicit_tag=0xA0) 

1123 ), 

1124 ASN1F_PACKET("reqChecksum", Checksum(), Checksum, explicit_tag=0xA1), 

1125 ASN1F_PACKET("encFastReq", None, EncryptedData, explicit_tag=0xA2), 

1126 ) 

1127 ) 

1128 

1129 

1130class PA_FX_FAST_REQUEST(ASN1_Packet): 

1131 ASN1_codec = ASN1_Codecs.BER 

1132 ASN1_root = ASN1F_CHOICE( 

1133 "armoredData", 

1134 ASN1_STRING(""), 

1135 ASN1F_PACKET("req", KrbFastArmoredReq, KrbFastArmoredReq, implicit_tag=0xA0), 

1136 ) 

1137 

1138 

1139# RFC6113 sect 5.4.3 

1140 

1141 

1142class KrbFastArmoredRep(ASN1_Packet): 

1143 ASN1_codec = ASN1_Codecs.BER 

1144 ASN1_root = ASN1F_SEQUENCE( 

1145 ASN1F_SEQUENCE( 

1146 ASN1F_PACKET("encFastRep", None, EncryptedData, explicit_tag=0xA0), 

1147 ) 

1148 ) 

1149 

1150 

1151class PA_FX_FAST_REPLY(ASN1_Packet): 

1152 ASN1_codec = ASN1_Codecs.BER 

1153 ASN1_root = ASN1F_CHOICE( 

1154 "armoredData", 

1155 ASN1_STRING(""), 

1156 ASN1F_PACKET("req", KrbFastArmoredRep, KrbFastArmoredRep, implicit_tag=0xA0), 

1157 ) 

1158 

1159 

1160class KrbFastFinished(ASN1_Packet): 

1161 ASN1_codec = ASN1_Codecs.BER 

1162 ASN1_root = ASN1F_SEQUENCE( 

1163 KerberosTime("timestamp", GeneralizedTime(), explicit_tag=0xA0), 

1164 Microseconds("usec", 0, explicit_tag=0xA1), 

1165 Realm("crealm", "", explicit_tag=0xA2), 

1166 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA3), 

1167 ASN1F_PACKET("ticketChecksum", Checksum(), Checksum, explicit_tag=0xA4), 

1168 ) 

1169 

1170 

1171class KrbFastResponse(ASN1_Packet): 

1172 ASN1_codec = ASN1_Codecs.BER 

1173 ASN1_root = ASN1F_SEQUENCE( 

1174 ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA0), 

1175 ASN1F_optional( 

1176 ASN1F_PACKET("strengthenKey", None, EncryptionKey, explicit_tag=0xA1) 

1177 ), 

1178 ASN1F_optional( 

1179 ASN1F_PACKET( 

1180 "finished", KrbFastFinished(), KrbFastFinished, explicit_tag=0xA2 

1181 ) 

1182 ), 

1183 UInt32("nonce", 0, explicit_tag=0xA3), 

1184 ) 

1185 

1186 

1187_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) 

1188 

1189# RFC 4556 

1190 

1191 

1192# sect 3.2.1 

1193 

1194 

1195class ExternalPrincipalIdentifier(ASN1_Packet): 

1196 ASN1_codec = ASN1_Codecs.BER 

1197 ASN1_root = ASN1F_SEQUENCE( 

1198 ASN1F_optional( 

1199 ASN1F_STRING("subjectName", "", implicit_tag=0xA0), 

1200 ), 

1201 ASN1F_optional( 

1202 ASN1F_STRING("issuerAndSerialNumber", "", implicit_tag=0xA1), 

1203 ), 

1204 ASN1F_optional( 

1205 ASN1F_STRING("subjectKeyIdentifier", "", implicit_tag=0xA2), 

1206 ), 

1207 ) 

1208 

1209 

1210class PA_PK_AS_REQ(ASN1_Packet): 

1211 ASN1_codec = ASN1_Codecs.BER 

1212 ASN1_root = ASN1F_SEQUENCE( 

1213 ASN1F_STRING("signedAuthpack", "", implicit_tag=0xA0), 

1214 ASN1F_optional( 

1215 ASN1F_SEQUENCE_OF( 

1216 "trustedCertifiers", 

1217 [ExternalPrincipalIdentifier()], 

1218 ExternalPrincipalIdentifier, 

1219 explicit_tag=0xA1, 

1220 ), 

1221 ), 

1222 ASN1F_optional( 

1223 ASN1F_STRING("kdcPkId", "", implicit_tag=0xA2), 

1224 ), 

1225 ) 

1226 

1227 

1228_PADATA_CLASSES[16] = PA_PK_AS_REQ 

1229 

1230# sect 3.2.3 

1231 

1232 

1233class DHRepInfo(ASN1_Packet): 

1234 ASN1_codec = ASN1_Codecs.BER 

1235 ASN1_root = ASN1F_SEQUENCE( 

1236 ASN1F_STRING("dhSignedData", "", implicit_tag=0xA0), 

1237 ASN1F_optional( 

1238 ASN1F_STRING("serverDHNonce", "", explicit_tag=0xA1), 

1239 ), 

1240 ) 

1241 

1242 

1243class EncKeyPack(ASN1_Packet): 

1244 ASN1_codec = ASN1_Codecs.BER 

1245 ASN1_root = ASN1F_STRING("encKeyPack", "") 

1246 

1247 

1248class PA_PK_AS_REP(ASN1_Packet): 

1249 ASN1_codec = ASN1_Codecs.BER 

1250 ASN1_root = ASN1F_CHOICE( 

1251 "rep", 

1252 ASN1_STRING(""), 

1253 ASN1F_PACKET("dhInfo", DHRepInfo(), DHRepInfo, explicit_tag=0xA0), 

1254 ASN1F_PACKET("encKeyPack", EncKeyPack(), EncKeyPack, explicit_tag=0xA1), 

1255 ) 

1256 

1257 

1258_PADATA_CLASSES[17] = PA_PK_AS_REP 

1259 

1260# [MS-SFU] 

1261 

1262 

1263# sect 2.2.1 

1264class PA_FOR_USER(ASN1_Packet): 

1265 ASN1_codec = ASN1_Codecs.BER 

1266 ASN1_root = ASN1F_SEQUENCE( 

1267 ASN1F_PACKET("userName", PrincipalName(), PrincipalName, explicit_tag=0xA0), 

1268 Realm("userRealm", "", explicit_tag=0xA1), 

1269 ASN1F_PACKET("cksum", Checksum(), Checksum, explicit_tag=0xA2), 

1270 KerberosString("authPackage", "Kerberos", explicit_tag=0xA3), 

1271 ) 

1272 

1273 

1274_PADATA_CLASSES[129] = PA_FOR_USER 

1275 

1276 

1277# sect 2.2.2 

1278 

1279 

1280class S4UUserID(ASN1_Packet): 

1281 ASN1_codec = ASN1_Codecs.BER 

1282 ASN1_root = ASN1F_SEQUENCE( 

1283 UInt32("nonce", 0, explicit_tag=0xA0), 

1284 ASN1F_optional( 

1285 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1), 

1286 ), 

1287 Realm("crealm", "", explicit_tag=0xA2), 

1288 ASN1F_optional( 

1289 ASN1F_STRING("subjectCertificate", None, explicit_tag=0xA3), 

1290 ), 

1291 ASN1F_optional( 

1292 ASN1F_FLAGS( 

1293 "options", 

1294 "", 

1295 [ 

1296 "reserved", 

1297 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS", 

1298 "USE_REPLY_KEY_USAGE", 

1299 "NT_AUTH_POLICY_NOT_REQUIRED", 

1300 "UNCONDITIONAL_DELEGATION", 

1301 ], 

1302 explicit_tag=0xA4, 

1303 ) 

1304 ), 

1305 ) 

1306 

1307 

1308class PA_S4U_X509_USER(ASN1_Packet): 

1309 ASN1_codec = ASN1_Codecs.BER 

1310 ASN1_root = ASN1F_SEQUENCE( 

1311 ASN1F_PACKET("userId", S4UUserID(), S4UUserID, explicit_tag=0xA0), 

1312 ASN1F_PACKET("checksum", Checksum(), Checksum, explicit_tag=0xA1), 

1313 ) 

1314 

1315 

1316_PADATA_CLASSES[130] = PA_S4U_X509_USER 

1317 

1318 

1319# Back to RFC4120 

1320 

1321# sect 5.10 

1322KRB_MSG_TYPES = { 

1323 1: "Ticket", 

1324 2: "Authenticator", 

1325 3: "EncTicketPart", 

1326 10: "AS-REQ", 

1327 11: "AS-REP", 

1328 12: "TGS-REQ", 

1329 13: "TGS-REP", 

1330 14: "AP-REQ", 

1331 15: "AP-REP", 

1332 16: "KRB-TGT-REQ", # U2U 

1333 17: "KRB-TGT-REP", # U2U 

1334 20: "KRB-SAFE", 

1335 21: "KRB-PRIV", 

1336 22: "KRB-CRED", 

1337 25: "EncASRepPart", 

1338 26: "EncTGSRepPart", 

1339 27: "EncAPRepPart", 

1340 28: "EncKrbPrivPart", 

1341 29: "EnvKrbCredPart", 

1342 30: "KRB-ERROR", 

1343} 

1344 

1345# sect 5.3 

1346 

1347 

1348class KRB_Ticket(ASN1_Packet): 

1349 ASN1_codec = ASN1_Codecs.BER 

1350 ASN1_root = ASN1F_SEQUENCE( 

1351 ASN1F_SEQUENCE( 

1352 ASN1F_INTEGER("tktVno", 5, explicit_tag=0xA0), 

1353 Realm("realm", "", explicit_tag=0xA1), 

1354 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xA2), 

1355 ASN1F_PACKET("encPart", EncryptedData(), EncryptedData, explicit_tag=0xA3), 

1356 ), 

1357 implicit_tag=ASN1_Class_KRB.Ticket, 

1358 ) 

1359 

1360 def getSPN(self): 

1361 return "%s@%s" % ( 

1362 self.sname.toString(), 

1363 self.realm.val.decode(), 

1364 ) 

1365 

1366 

1367class TransitedEncoding(ASN1_Packet): 

1368 ASN1_codec = ASN1_Codecs.BER 

1369 ASN1_root = ASN1F_SEQUENCE( 

1370 Int32("trType", 0, explicit_tag=0xA0), 

1371 ASN1F_STRING("contents", "", explicit_tag=0xA1), 

1372 ) 

1373 

1374 

1375_TICKET_FLAGS = [ 

1376 "reserved", 

1377 "forwardable", 

1378 "forwarded", 

1379 "proxiable", 

1380 "proxy", 

1381 "may-postdate", 

1382 "postdated", 

1383 "invalid", 

1384 "renewable", 

1385 "initial", 

1386 "pre-authent", 

1387 "hw-authent", 

1388 "transited-since-policy-checked", 

1389 "ok-as-delegate", 

1390 "unused", 

1391 "canonicalize", # RFC6806 

1392 "anonymous", # RFC6112 + RFC8129 

1393] 

1394 

1395 

1396class EncTicketPart(ASN1_Packet): 

1397 ASN1_codec = ASN1_Codecs.BER 

1398 ASN1_root = ASN1F_SEQUENCE( 

1399 ASN1F_SEQUENCE( 

1400 KerberosFlags( 

1401 "flags", 

1402 "", 

1403 _TICKET_FLAGS, 

1404 explicit_tag=0xA0, 

1405 ), 

1406 ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA1), 

1407 Realm("crealm", "", explicit_tag=0xA2), 

1408 ASN1F_PACKET("cname", PrincipalName(), PrincipalName, explicit_tag=0xA3), 

1409 ASN1F_PACKET( 

1410 "transited", TransitedEncoding(), TransitedEncoding, explicit_tag=0xA4 

1411 ), 

1412 KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5), 

1413 ASN1F_optional( 

1414 KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6) 

1415 ), 

1416 KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7), 

1417 ASN1F_optional( 

1418 KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8), 

1419 ), 

1420 ASN1F_optional( 

1421 HostAddresses("addresses", explicit_tag=0xA9), 

1422 ), 

1423 ASN1F_optional( 

1424 ASN1F_PACKET( 

1425 "authorizationData", None, AuthorizationData, explicit_tag=0xAA 

1426 ), 

1427 ), 

1428 ), 

1429 implicit_tag=ASN1_Class_KRB.EncTicketPart, 

1430 ) 

1431 

1432 

1433# sect 5.4.1 

1434 

1435 

1436class KRB_KDC_REQ_BODY(ASN1_Packet): 

1437 ASN1_codec = ASN1_Codecs.BER 

1438 ASN1_root = ASN1F_SEQUENCE( 

1439 KerberosFlags( 

1440 "kdcOptions", 

1441 "", 

1442 [ 

1443 "reserved", 

1444 "forwardable", 

1445 "forwarded", 

1446 "proxiable", 

1447 "proxy", 

1448 "allow-postdate", 

1449 "postdated", 

1450 "unused7", 

1451 "renewable", 

1452 "unused9", 

1453 "unused10", 

1454 "opt-hardware-auth", 

1455 "unused12", 

1456 "unused13", 

1457 "cname-in-addl-tkt", # [MS-SFU] sect 2.2.3 

1458 "canonicalize", # RFC6806 

1459 "request-anonymous", # RFC6112 + RFC8129 

1460 ] 

1461 + ["unused%d" % i for i in range(17, 26)] 

1462 + [ 

1463 "disable-transited-check", 

1464 "renewable-ok", 

1465 "enc-tkt-in-skey", 

1466 "unused29", 

1467 "renew", 

1468 "validate", 

1469 ], 

1470 explicit_tag=0xA0, 

1471 ), 

1472 ASN1F_optional(ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1)), 

1473 Realm("realm", "", explicit_tag=0xA2), 

1474 ASN1F_optional( 

1475 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA3), 

1476 ), 

1477 ASN1F_optional(KerberosTime("from_", None, explicit_tag=0xA4)), 

1478 KerberosTime("till", GeneralizedTime(), explicit_tag=0xA5), 

1479 ASN1F_optional(KerberosTime("rtime", GeneralizedTime(), explicit_tag=0xA6)), 

1480 UInt32("nonce", 0, explicit_tag=0xA7), 

1481 ASN1F_SEQUENCE_OF("etype", [], Int32, explicit_tag=0xA8), 

1482 ASN1F_optional( 

1483 HostAddresses("addresses", explicit_tag=0xA9), 

1484 ), 

1485 ASN1F_optional( 

1486 ASN1F_PACKET( 

1487 "encAuthorizationData", None, EncryptedData, explicit_tag=0xAA 

1488 ), 

1489 ), 

1490 ASN1F_optional( 

1491 ASN1F_SEQUENCE_OF("additionalTickets", [], KRB_Ticket, explicit_tag=0xAB) 

1492 ), 

1493 ) 

1494 

1495 

1496KRB_KDC_REQ = ASN1F_SEQUENCE( 

1497 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA1), 

1498 ASN1F_enum_INTEGER("msgType", 10, KRB_MSG_TYPES, explicit_tag=0xA2), 

1499 ASN1F_optional(ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA3)), 

1500 ASN1F_PACKET("reqBody", KRB_KDC_REQ_BODY(), KRB_KDC_REQ_BODY, explicit_tag=0xA4), 

1501) 

1502 

1503 

1504class KrbFastReq(ASN1_Packet): 

1505 # RFC6113 sect 5.4.2 

1506 ASN1_codec = ASN1_Codecs.BER 

1507 ASN1_root = ASN1F_SEQUENCE( 

1508 KerberosFlags( 

1509 "fastOptions", 

1510 "", 

1511 [ 

1512 "RESERVED", 

1513 "hide-client-names", 

1514 ] 

1515 + ["res%d" % i for i in range(2, 16)] 

1516 + ["kdc-follow-referrals"], 

1517 explicit_tag=0xA0, 

1518 ), 

1519 ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA1), 

1520 ASN1F_PACKET("reqBody", None, KRB_KDC_REQ_BODY, explicit_tag=0xA2), 

1521 ) 

1522 

1523 

1524class KRB_AS_REQ(ASN1_Packet): 

1525 ASN1_codec = ASN1_Codecs.BER 

1526 ASN1_root = ASN1F_SEQUENCE( 

1527 KRB_KDC_REQ, 

1528 implicit_tag=ASN1_Class_KRB.AS_REQ, 

1529 ) 

1530 

1531 

1532class KRB_TGS_REQ(ASN1_Packet): 

1533 ASN1_codec = ASN1_Codecs.BER 

1534 ASN1_root = ASN1F_SEQUENCE( 

1535 KRB_KDC_REQ, 

1536 implicit_tag=ASN1_Class_KRB.TGS_REQ, 

1537 ) 

1538 msgType = ASN1_INTEGER(12) 

1539 

1540 

1541# sect 5.4.2 

1542 

1543KRB_KDC_REP = ASN1F_SEQUENCE( 

1544 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1545 ASN1F_enum_INTEGER("msgType", 11, KRB_MSG_TYPES, explicit_tag=0xA1), 

1546 ASN1F_optional( 

1547 ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA2), 

1548 ), 

1549 Realm("crealm", "", explicit_tag=0xA3), 

1550 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA4), 

1551 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA5), 

1552 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA6), 

1553) 

1554 

1555 

1556class KRB_AS_REP(ASN1_Packet): 

1557 ASN1_codec = ASN1_Codecs.BER 

1558 ASN1_root = ASN1F_SEQUENCE( 

1559 KRB_KDC_REP, 

1560 implicit_tag=ASN1_Class_KRB.AS_REP, 

1561 ) 

1562 

1563 

1564class KRB_TGS_REP(ASN1_Packet): 

1565 ASN1_codec = ASN1_Codecs.BER 

1566 ASN1_root = ASN1F_SEQUENCE( 

1567 KRB_KDC_REP, 

1568 implicit_tag=ASN1_Class_KRB.TGS_REP, 

1569 ) 

1570 

1571 def getUPN(self): 

1572 return "%s@%s" % ( 

1573 self.cname.toString(), 

1574 self.crealm.val.decode(), 

1575 ) 

1576 

1577 

1578class LastReqItem(ASN1_Packet): 

1579 ASN1_codec = ASN1_Codecs.BER 

1580 ASN1_root = ASN1F_SEQUENCE( 

1581 Int32("lrType", 0, explicit_tag=0xA0), 

1582 KerberosTime("lrValue", GeneralizedTime(), explicit_tag=0xA1), 

1583 ) 

1584 

1585 

1586EncKDCRepPart = ASN1F_SEQUENCE( 

1587 ASN1F_PACKET("key", None, EncryptionKey, explicit_tag=0xA0), 

1588 ASN1F_SEQUENCE_OF("lastReq", [], LastReqItem, explicit_tag=0xA1), 

1589 UInt32("nonce", 0, explicit_tag=0xA2), 

1590 ASN1F_optional( 

1591 KerberosTime("keyExpiration", GeneralizedTime(), explicit_tag=0xA3), 

1592 ), 

1593 KerberosFlags( 

1594 "flags", 

1595 "", 

1596 _TICKET_FLAGS, 

1597 explicit_tag=0xA4, 

1598 ), 

1599 KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5), 

1600 ASN1F_optional( 

1601 KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6), 

1602 ), 

1603 KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7), 

1604 ASN1F_optional( 

1605 KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8), 

1606 ), 

1607 Realm("srealm", "", explicit_tag=0xA9), 

1608 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA), 

1609 ASN1F_optional( 

1610 HostAddresses("caddr", explicit_tag=0xAB), 

1611 ), 

1612 # RFC6806 sect 11 

1613 ASN1F_optional( 

1614 ASN1F_SEQUENCE_OF("encryptedPaData", [], PADATA, explicit_tag=0xAC), 

1615 ), 

1616) 

1617 

1618 

1619class EncASRepPart(ASN1_Packet): 

1620 ASN1_codec = ASN1_Codecs.BER 

1621 ASN1_root = ASN1F_SEQUENCE( 

1622 EncKDCRepPart, 

1623 implicit_tag=ASN1_Class_KRB.EncASRepPart, 

1624 ) 

1625 

1626 

1627class EncTGSRepPart(ASN1_Packet): 

1628 ASN1_codec = ASN1_Codecs.BER 

1629 ASN1_root = ASN1F_SEQUENCE( 

1630 EncKDCRepPart, 

1631 implicit_tag=ASN1_Class_KRB.EncTGSRepPart, 

1632 ) 

1633 

1634 

1635# sect 5.5.1 

1636 

1637 

1638class KRB_AP_REQ(ASN1_Packet): 

1639 ASN1_codec = ASN1_Codecs.BER 

1640 ASN1_root = ASN1F_SEQUENCE( 

1641 ASN1F_SEQUENCE( 

1642 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1643 ASN1F_enum_INTEGER("msgType", 14, KRB_MSG_TYPES, explicit_tag=0xA1), 

1644 KerberosFlags( 

1645 "apOptions", 

1646 "", 

1647 [ 

1648 "reserved", 

1649 "use-session-key", 

1650 "mutual-required", 

1651 ], 

1652 explicit_tag=0xA2, 

1653 ), 

1654 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA3), 

1655 ASN1F_PACKET("authenticator", None, EncryptedData, explicit_tag=0xA4), 

1656 ), 

1657 implicit_tag=ASN1_Class_KRB.AP_REQ, 

1658 ) 

1659 

1660 

1661_PADATA_CLASSES[1] = KRB_AP_REQ 

1662 

1663 

1664class KRB_Authenticator(ASN1_Packet): 

1665 ASN1_codec = ASN1_Codecs.BER 

1666 ASN1_root = ASN1F_SEQUENCE( 

1667 ASN1F_SEQUENCE( 

1668 ASN1F_INTEGER("authenticatorPvno", 5, explicit_tag=0xA0), 

1669 Realm("crealm", "", explicit_tag=0xA1), 

1670 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA2), 

1671 ASN1F_optional( 

1672 ASN1F_PACKET("cksum", None, Checksum, explicit_tag=0xA3), 

1673 ), 

1674 Microseconds("cusec", 0, explicit_tag=0xA4), 

1675 KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA5), 

1676 ASN1F_optional( 

1677 ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA6), 

1678 ), 

1679 ASN1F_optional( 

1680 UInt32("seqNumber", 0, explicit_tag=0xA7), 

1681 ), 

1682 ASN1F_optional( 

1683 ASN1F_PACKET( 

1684 "encAuthorizationData", None, AuthorizationData, explicit_tag=0xA8 

1685 ), 

1686 ), 

1687 ), 

1688 implicit_tag=ASN1_Class_KRB.Authenticator, 

1689 ) 

1690 

1691 

1692# sect 5.5.2 

1693 

1694 

1695class KRB_AP_REP(ASN1_Packet): 

1696 ASN1_codec = ASN1_Codecs.BER 

1697 ASN1_root = ASN1F_SEQUENCE( 

1698 ASN1F_SEQUENCE( 

1699 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1700 ASN1F_enum_INTEGER("msgType", 15, KRB_MSG_TYPES, explicit_tag=0xA1), 

1701 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA2), 

1702 ), 

1703 implicit_tag=ASN1_Class_KRB.AP_REP, 

1704 ) 

1705 

1706 

1707class EncAPRepPart(ASN1_Packet): 

1708 ASN1_codec = ASN1_Codecs.BER 

1709 ASN1_root = ASN1F_SEQUENCE( 

1710 ASN1F_SEQUENCE( 

1711 KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA0), 

1712 Microseconds("cusec", 0, explicit_tag=0xA1), 

1713 ASN1F_optional( 

1714 ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA2), 

1715 ), 

1716 ASN1F_optional( 

1717 UInt32("seqNumber", 0, explicit_tag=0xA3), 

1718 ), 

1719 ), 

1720 implicit_tag=ASN1_Class_KRB.EncAPRepPart, 

1721 ) 

1722 

1723 

1724# sect 5.7 

1725 

1726 

1727class KRB_PRIV(ASN1_Packet): 

1728 ASN1_codec = ASN1_Codecs.BER 

1729 ASN1_root = ASN1F_SEQUENCE( 

1730 ASN1F_SEQUENCE( 

1731 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1732 ASN1F_enum_INTEGER("msgType", 21, KRB_MSG_TYPES, explicit_tag=0xA1), 

1733 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3), 

1734 ), 

1735 implicit_tag=ASN1_Class_KRB.PRIV, 

1736 ) 

1737 

1738 

1739class EncKrbPrivPart(ASN1_Packet): 

1740 ASN1_codec = ASN1_Codecs.BER 

1741 ASN1_root = ASN1F_SEQUENCE( 

1742 ASN1F_SEQUENCE( 

1743 ASN1F_STRING("userData", ASN1_STRING(""), explicit_tag=0xA0), 

1744 ASN1F_optional( 

1745 KerberosTime("timestamp", None, explicit_tag=0xA1), 

1746 ), 

1747 ASN1F_optional( 

1748 Microseconds("usec", None, explicit_tag=0xA2), 

1749 ), 

1750 ASN1F_optional( 

1751 UInt32("seqNumber", None, explicit_tag=0xA3), 

1752 ), 

1753 ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4), 

1754 ASN1F_optional( 

1755 ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5), 

1756 ), 

1757 ), 

1758 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart, 

1759 ) 

1760 

1761 

1762# sect 5.8 

1763 

1764 

1765class KRB_CRED(ASN1_Packet): 

1766 ASN1_codec = ASN1_Codecs.BER 

1767 ASN1_root = ASN1F_SEQUENCE( 

1768 ASN1F_SEQUENCE( 

1769 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1770 ASN1F_enum_INTEGER("msgType", 22, KRB_MSG_TYPES, explicit_tag=0xA1), 

1771 ASN1F_SEQUENCE_OF("tickets", [KRB_Ticket()], KRB_Ticket, explicit_tag=0xA2), 

1772 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3), 

1773 ), 

1774 implicit_tag=ASN1_Class_KRB.CRED, 

1775 ) 

1776 

1777 

1778class KrbCredInfo(ASN1_Packet): 

1779 ASN1_codec = ASN1_Codecs.BER 

1780 ASN1_root = ASN1F_SEQUENCE( 

1781 ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA0), 

1782 ASN1F_optional( 

1783 Realm("prealm", None, explicit_tag=0xA1), 

1784 ), 

1785 ASN1F_optional( 

1786 ASN1F_PACKET("pname", None, PrincipalName, explicit_tag=0xA2), 

1787 ), 

1788 ASN1F_optional( 

1789 KerberosFlags( 

1790 "flags", 

1791 None, 

1792 _TICKET_FLAGS, 

1793 explicit_tag=0xA3, 

1794 ), 

1795 ), 

1796 ASN1F_optional( 

1797 KerberosTime("authtime", None, explicit_tag=0xA4), 

1798 ), 

1799 ASN1F_optional(KerberosTime("starttime", None, explicit_tag=0xA5)), 

1800 ASN1F_optional( 

1801 KerberosTime("endtime", None, explicit_tag=0xA6), 

1802 ), 

1803 ASN1F_optional( 

1804 KerberosTime("renewTill", None, explicit_tag=0xA7), 

1805 ), 

1806 ASN1F_optional( 

1807 Realm("srealm", None, explicit_tag=0xA8), 

1808 ), 

1809 ASN1F_optional( 

1810 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA9), 

1811 ), 

1812 ASN1F_optional( 

1813 HostAddresses("caddr", explicit_tag=0xAA), 

1814 ), 

1815 ) 

1816 

1817 

1818class EncKrbCredPart(ASN1_Packet): 

1819 ASN1_codec = ASN1_Codecs.BER 

1820 ASN1_root = ASN1F_SEQUENCE( 

1821 ASN1F_SEQUENCE( 

1822 ASN1F_SEQUENCE_OF( 

1823 "ticketInfo", 

1824 [KrbCredInfo()], 

1825 KrbCredInfo, 

1826 explicit_tag=0xA0, 

1827 ), 

1828 ASN1F_optional( 

1829 UInt32("nonce", None, explicit_tag=0xA1), 

1830 ), 

1831 ASN1F_optional( 

1832 KerberosTime("timestamp", None, explicit_tag=0xA2), 

1833 ), 

1834 ASN1F_optional( 

1835 Microseconds("usec", None, explicit_tag=0xA3), 

1836 ), 

1837 ASN1F_optional( 

1838 ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4), 

1839 ), 

1840 ASN1F_optional( 

1841 ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5), 

1842 ), 

1843 ), 

1844 implicit_tag=ASN1_Class_KRB.EncKrbCredPart, 

1845 ) 

1846 

1847 

1848# sect 5.9.1 

1849 

1850 

1851class MethodData(ASN1_Packet): 

1852 ASN1_codec = ASN1_Codecs.BER 

1853 ASN1_root = ASN1F_SEQUENCE_OF("seq", [PADATA()], PADATA) 

1854 

1855 

1856class _KRBERROR_data_Field(ASN1F_STRING_PacketField): 

1857 def m2i(self, pkt, s): 

1858 val = super(_KRBERROR_data_Field, self).m2i(pkt, s) 

1859 if not val[0].val: 

1860 return val 

1861 if pkt.errorCode.val in [14, 24, 25, 36]: 

1862 # 14: KDC_ERR_ETYPE_NOSUPP 

1863 # 24: KDC_ERR_PREAUTH_FAILED 

1864 # 25: KDC_ERR_PREAUTH_REQUIRED 

1865 # 36: KRB_AP_ERR_BADMATCH 

1866 return MethodData(val[0].val, _underlayer=pkt), val[1] 

1867 elif pkt.errorCode.val in [6, 7, 12, 13, 18, 29, 41, 60]: 

1868 # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN 

1869 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

1870 # 12: KDC_ERR_POLICY 

1871 # 13: KDC_ERR_BADOPTION 

1872 # 18: KDC_ERR_CLIENT_REVOKED 

1873 # 29: KDC_ERR_SVC_UNAVAILABLE 

1874 # 41: KRB_AP_ERR_MODIFIED 

1875 # 60: KRB_ERR_GENERIC 

1876 try: 

1877 return KERB_ERROR_DATA(val[0].val, _underlayer=pkt), val[1] 

1878 except BER_Decoding_Error: 

1879 if pkt.errorCode.val in [18, 12]: 

1880 # Some types can also happen in FAST sessions 

1881 # 18: KDC_ERR_CLIENT_REVOKED 

1882 return MethodData(val[0].val, _underlayer=pkt), val[1] 

1883 elif pkt.errorCode.val == 7: 

1884 # This looks like an undocumented structure. 

1885 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

1886 return KERB_ERROR_UNK(val[0].val, _underlayer=pkt), val[1] 

1887 raise 

1888 elif pkt.errorCode.val == 69: 

1889 # KRB_AP_ERR_USER_TO_USER_REQUIRED 

1890 return KRB_TGT_REP(val[0].val, _underlayer=pkt), val[1] 

1891 return val 

1892 

1893 

1894class KRB_ERROR(ASN1_Packet): 

1895 ASN1_codec = ASN1_Codecs.BER 

1896 ASN1_root = ASN1F_SEQUENCE( 

1897 ASN1F_SEQUENCE( 

1898 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1899 ASN1F_enum_INTEGER("msgType", 30, KRB_MSG_TYPES, explicit_tag=0xA1), 

1900 ASN1F_optional( 

1901 KerberosTime("ctime", None, explicit_tag=0xA2), 

1902 ), 

1903 ASN1F_optional( 

1904 Microseconds("cusec", None, explicit_tag=0xA3), 

1905 ), 

1906 KerberosTime("stime", GeneralizedTime(), explicit_tag=0xA4), 

1907 Microseconds("susec", 0, explicit_tag=0xA5), 

1908 ASN1F_enum_INTEGER( 

1909 "errorCode", 

1910 0, 

1911 { 

1912 # RFC4120 sect 7.5.9 

1913 0: "KDC_ERR_NONE", 

1914 1: "KDC_ERR_NAME_EXP", 

1915 2: "KDC_ERR_SERVICE_EXP", 

1916 3: "KDC_ERR_BAD_PVNO", 

1917 4: "KDC_ERR_C_OLD_MAST_KVNO", 

1918 5: "KDC_ERR_S_OLD_MAST_KVNO", 

1919 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN", 

1920 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN", 

1921 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE", 

1922 9: "KDC_ERR_NULL_KEY", 

1923 10: "KDC_ERR_CANNOT_POSTDATE", 

1924 11: "KDC_ERR_NEVER_VALID", 

1925 12: "KDC_ERR_POLICY", 

1926 13: "KDC_ERR_BADOPTION", 

1927 14: "KDC_ERR_ETYPE_NOSUPP", 

1928 15: "KDC_ERR_SUMTYPE_NOSUPP", 

1929 16: "KDC_ERR_PADATA_TYPE_NOSUPP", 

1930 17: "KDC_ERR_TRTYPE_NOSUPP", 

1931 18: "KDC_ERR_CLIENT_REVOKED", 

1932 19: "KDC_ERR_SERVICE_REVOKED", 

1933 20: "KDC_ERR_TGT_REVOKED", 

1934 21: "KDC_ERR_CLIENT_NOTYET", 

1935 22: "KDC_ERR_SERVICE_NOTYET", 

1936 23: "KDC_ERR_KEY_EXPIRED", 

1937 24: "KDC_ERR_PREAUTH_FAILED", 

1938 25: "KDC_ERR_PREAUTH_REQUIRED", 

1939 26: "KDC_ERR_SERVER_NOMATCH", 

1940 27: "KDC_ERR_MUST_USE_USER2USER", 

1941 28: "KDC_ERR_PATH_NOT_ACCEPTED", 

1942 29: "KDC_ERR_SVC_UNAVAILABLE", 

1943 31: "KRB_AP_ERR_BAD_INTEGRITY", 

1944 32: "KRB_AP_ERR_TKT_EXPIRED", 

1945 33: "KRB_AP_ERR_TKT_NYV", 

1946 34: "KRB_AP_ERR_REPEAT", 

1947 35: "KRB_AP_ERR_NOT_US", 

1948 36: "KRB_AP_ERR_BADMATCH", 

1949 37: "KRB_AP_ERR_SKEW", 

1950 38: "KRB_AP_ERR_BADADDR", 

1951 39: "KRB_AP_ERR_BADVERSION", 

1952 40: "KRB_AP_ERR_MSG_TYPE", 

1953 41: "KRB_AP_ERR_MODIFIED", 

1954 42: "KRB_AP_ERR_BADORDER", 

1955 44: "KRB_AP_ERR_BADKEYVER", 

1956 45: "KRB_AP_ERR_NOKEY", 

1957 46: "KRB_AP_ERR_MUT_FAIL", 

1958 47: "KRB_AP_ERR_BADDIRECTION", 

1959 48: "KRB_AP_ERR_METHOD", 

1960 49: "KRB_AP_ERR_BADSEQ", 

1961 50: "KRB_AP_ERR_INAPP_CKSUM", 

1962 51: "KRB_AP_PATH_NOT_ACCEPTED", 

1963 52: "KRB_ERR_RESPONSE_TOO_BIG", 

1964 60: "KRB_ERR_GENERIC", 

1965 61: "KRB_ERR_FIELD_TOOLONG", 

1966 62: "KDC_ERROR_CLIENT_NOT_TRUSTED", 

1967 63: "KDC_ERROR_KDC_NOT_TRUSTED", 

1968 64: "KDC_ERROR_INVALID_SIG", 

1969 65: "KDC_ERR_KEY_TOO_WEAK", 

1970 66: "KDC_ERR_CERTIFICATE_MISMATCH", 

1971 67: "KRB_AP_ERR_NO_TGT", 

1972 68: "KDC_ERR_WRONG_REALM", 

1973 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED", 

1974 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE", 

1975 71: "KDC_ERR_INVALID_CERTIFICATE", 

1976 72: "KDC_ERR_REVOKED_CERTIFICATE", 

1977 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN", 

1978 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE", 

1979 75: "KDC_ERR_CLIENT_NAME_MISMATCH", 

1980 76: "KDC_ERR_KDC_NAME_MISMATCH", 

1981 # draft-ietf-kitten-iakerb 

1982 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND", 

1983 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE", 

1984 # RFC6113 

1985 90: "KDC_ERR_PREAUTH_EXPIRED", 

1986 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 

1987 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 

1988 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", 

1989 }, 

1990 explicit_tag=0xA6, 

1991 ), 

1992 ASN1F_optional(Realm("crealm", None, explicit_tag=0xA7)), 

1993 ASN1F_optional( 

1994 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA8), 

1995 ), 

1996 Realm("realm", "", explicit_tag=0xA9), 

1997 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA), 

1998 ASN1F_optional(KerberosString("eText", "", explicit_tag=0xAB)), 

1999 ASN1F_optional(_KRBERROR_data_Field("eData", "", explicit_tag=0xAC)), 

2000 ), 

2001 implicit_tag=ASN1_Class_KRB.ERROR, 

2002 ) 

2003 

2004 def getSPN(self): 

2005 return "%s@%s" % ( 

2006 self.sname.toString(), 

2007 self.realm.val.decode(), 

2008 ) 

2009 

2010 

2011# PA-FX-ERROR 

2012_PADATA_CLASSES[137] = KRB_ERROR 

2013 

2014 

2015# [MS-KILE] sect 2.2.1 

2016 

2017 

2018class KERB_EXT_ERROR(Packet): 

2019 fields_desc = [ 

2020 XLEIntEnumField("status", 0, STATUS_ERREF), 

2021 XLEIntField("reserved", 0), 

2022 XLEIntField("flags", 0x00000001), 

2023 ] 

2024 

2025 

2026# [MS-KILE] sect 2.2.2 

2027 

2028 

2029class _Error_Field(ASN1F_STRING_PacketField): 

2030 def m2i(self, pkt, s): 

2031 val = super(_Error_Field, self).m2i(pkt, s) 

2032 if not val[0].val: 

2033 return val 

2034 if pkt.dataType.val == 3: # KERB_ERR_TYPE_EXTENDED 

2035 return KERB_EXT_ERROR(val[0].val, _underlayer=pkt), val[1] 

2036 return val 

2037 

2038 

2039class KERB_ERROR_DATA(ASN1_Packet): 

2040 ASN1_codec = ASN1_Codecs.BER 

2041 ASN1_root = ASN1F_SEQUENCE( 

2042 ASN1F_enum_INTEGER( 

2043 "dataType", 

2044 2, 

2045 { 

2046 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk 

2047 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY", 

2048 3: "KERB_ERR_TYPE_EXTENDED", 

2049 }, 

2050 explicit_tag=0xA1, 

2051 ), 

2052 ASN1F_optional(_Error_Field("dataValue", None, explicit_tag=0xA2)), 

2053 ) 

2054 

2055 

2056# This looks like an undocumented structure. 

2057 

2058 

2059class KERB_ERROR_UNK(ASN1_Packet): 

2060 ASN1_codec = ASN1_Codecs.BER 

2061 ASN1_root = ASN1F_SEQUENCE( 

2062 ASN1F_SEQUENCE( 

2063 ASN1F_enum_INTEGER( 

2064 "dataType", 

2065 0, 

2066 { 

2067 -128: "KDC_ERR_MUST_USE_USER2USER", 

2068 }, 

2069 explicit_tag=0xA0, 

2070 ), 

2071 ASN1F_STRING("dataValue", None, explicit_tag=0xA1), 

2072 ) 

2073 ) 

2074 

2075 

2076# Kerberos U2U - draft-ietf-cat-user2user-03 

2077 

2078 

2079class KRB_TGT_REQ(ASN1_Packet): 

2080 ASN1_codec = ASN1_Codecs.BER 

2081 ASN1_root = ASN1F_SEQUENCE( 

2082 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

2083 ASN1F_enum_INTEGER("msgType", 16, KRB_MSG_TYPES, explicit_tag=0xA1), 

2084 ASN1F_optional( 

2085 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA2), 

2086 ), 

2087 ASN1F_optional( 

2088 Realm("realm", None, explicit_tag=0xA3), 

2089 ), 

2090 ) 

2091 

2092 

2093class KRB_TGT_REP(ASN1_Packet): 

2094 ASN1_codec = ASN1_Codecs.BER 

2095 ASN1_root = ASN1F_SEQUENCE( 

2096 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

2097 ASN1F_enum_INTEGER("msgType", 17, KRB_MSG_TYPES, explicit_tag=0xA1), 

2098 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA2), 

2099 ) 

2100 

2101 

2102# draft-ietf-kitten-iakerb-03 sect 4 

2103 

2104 

2105class KRB_FINISHED(ASN1_Packet): 

2106 ASN1_codec = ASN1_Codecs.BER 

2107 ASN1_root = ASN1F_SEQUENCE( 

2108 ASN1F_PACKET("gssMic", Checksum(), Checksum, explicit_tag=0xA1), 

2109 ) 

2110 

2111 

2112# RFC 6542 sect 3.1 

2113 

2114 

2115class KRB_GSS_EXT(Packet): 

2116 fields_desc = [ 

2117 IntEnumField( 

2118 "type", 

2119 0, 

2120 { 

2121 # https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml 

2122 0x00000000: "GSS_EXTS_CHANNEL_BINDING", # RFC 6542 sect 3.2 

2123 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard 

2124 0x00000002: "GSS_EXTS_FINISHED", # PKU2U / IAKERB 

2125 }, 

2126 ), 

2127 FieldLenField("length", None, length_of="data", fmt="!I"), 

2128 MultipleTypeField( 

2129 [ 

2130 ( 

2131 PacketField("data", KRB_FINISHED(), KRB_FINISHED), 

2132 lambda pkt: pkt.type == 0x00000002, 

2133 ), 

2134 ], 

2135 XStrLenField("data", b"", length_from=lambda pkt: pkt.length), 

2136 ), 

2137 ] 

2138 

2139 

2140# RFC 4121 sect 4.1.1 

2141 

2142 

2143class KRB_AuthenticatorChecksum(Packet): 

2144 fields_desc = [ 

2145 FieldLenField("Lgth", None, length_of="Bnd", fmt="<I"), 

2146 XStrLenField("Bnd", b"\x00" * 16, length_from=lambda pkt: pkt.Lgth), 

2147 FlagsField( 

2148 "Flags", 

2149 0, 

2150 -32, 

2151 { 

2152 0x01: "GSS_C_DELEG_FLAG", 

2153 0x02: "GSS_C_MUTUAL_FLAG", 

2154 0x04: "GSS_C_REPLAY_FLAG", 

2155 0x08: "GSS_C_SEQUENCE_FLAG", 

2156 0x10: "GSS_C_CONF_FLAG", # confidentiality 

2157 0x20: "GSS_C_INTEG_FLAG", # integrity 

2158 # RFC4757 

2159 0x1000: "GSS_C_DCE_STYLE", 

2160 0x2000: "GSS_C_IDENTIFY_FLAG", 

2161 0x4000: "GSS_C_EXTENDED_ERROR_FLAG", 

2162 }, 

2163 ), 

2164 ConditionalField( 

2165 LEShortField("DlgOpt", 0), 

2166 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2167 ), 

2168 ConditionalField( 

2169 FieldLenField("Dlgth", None, length_of="Deleg"), 

2170 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2171 ), 

2172 ConditionalField( 

2173 PacketLenField( 

2174 "Deleg", KRB_CRED(), KRB_CRED, length_from=lambda pkt: pkt.Dlgth 

2175 ), 

2176 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2177 ), 

2178 # Extensions: RFC 6542 sect 3.1 

2179 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT), 

2180 ] 

2181 

2182 

2183# Kerberos V5 GSS-API - RFC1964 and RFC4121 

2184 

2185_TOK_IDS = { 

2186 # RFC 1964 

2187 b"\x01\x00": "KRB-AP-REQ", 

2188 b"\x02\x00": "KRB-AP-REP", 

2189 b"\x03\x00": "KRB-ERROR", 

2190 b"\x01\x01": "GSS_GetMIC-RFC1964", 

2191 b"\x02\x01": "GSS_Wrap-RFC1964", 

2192 b"\x01\x02": "GSS_Delete_sec_context-RFC1964", 

2193 # U2U: [draft-ietf-cat-user2user-03] 

2194 b"\x04\x00": "KRB-TGT-REQ", 

2195 b"\x04\x01": "KRB-TGT-REP", 

2196 # RFC 4121 

2197 b"\x04\x04": "GSS_GetMIC", 

2198 b"\x05\x04": "GSS_Wrap", 

2199 # IAKERB: [draft-ietf-kitten-iakerb-03] 

2200 b"\x05\x01": "IAKERB_PROXY", 

2201} 

2202_SGN_ALGS = { 

2203 0x00: "DES MAC MD5", 

2204 0x01: "MD2.5", 

2205 0x02: "DES MAC", 

2206 # RFC 4757 

2207 0x11: "HMAC", 

2208} 

2209_SEAL_ALGS = { 

2210 0: "DES", 

2211 0xFFFF: "none", 

2212 # RFC 4757 

2213 0x10: "RC4", 

2214} 

2215 

2216 

2217# RFC 1964 - sect 1.1 

2218 

2219# See https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml 

2220_InitialContextTokens = {} # filled below 

2221 

2222 

2223class KRB_InnerToken(Packet): 

2224 name = "Kerberos v5 InnerToken" 

2225 fields_desc = [ 

2226 StrFixedLenEnumField("TOK_ID", b"\x01\x00", _TOK_IDS, length=2), 

2227 PacketField( 

2228 "root", 

2229 KRB_AP_REQ(), 

2230 lambda x, _parent: _InitialContextTokens[_parent.TOK_ID](x), 

2231 ), 

2232 ] 

2233 

2234 def mysummary(self): 

2235 return self.sprintf( 

2236 "Kerberos %s" % _TOK_IDS.get(self.TOK_ID, repr(self.TOK_ID)) 

2237 ) 

2238 

2239 def guess_payload_class(self, payload): 

2240 if self.TOK_ID in [b"\x01\x01", b"\x02\x01", b"\x04\x04", b"\x05\x04"]: 

2241 return conf.padding_layer 

2242 return Kerberos 

2243 

2244 @classmethod 

2245 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

2246 if _pkt and len(_pkt) >= 13: 

2247 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper 

2248 if _pkt[2:13] == b"\x06\t*\x86H\x86\xf7\x12\x01\x02\x02": 

2249 return KRB_GSSAPI_Token 

2250 return cls 

2251 

2252 

2253# RFC 4121 - sect 4.1 

2254 

2255 

2256class KRB_GSSAPI_Token(GSSAPI_BLOB): 

2257 name = "Kerberos GSSAPI-Token" 

2258 ASN1_codec = ASN1_Codecs.BER 

2259 ASN1_root = ASN1F_SEQUENCE( 

2260 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"), 

2261 ASN1F_PACKET( 

2262 "innerToken", 

2263 KRB_InnerToken(), 

2264 KRB_InnerToken, 

2265 implicit_tag=0x0, 

2266 ), 

2267 implicit_tag=ASN1_Class_KRB.Token, 

2268 ) 

2269 

2270 

2271# RFC 1964 - sect 1.2.1 

2272 

2273 

2274class KRB_GSS_MIC_RFC1964(Packet): 

2275 name = "Kerberos v5 MIC Token (RFC1964)" 

2276 fields_desc = [ 

2277 LEShortEnumField("SGN_ALG", 0, _SGN_ALGS), 

2278 XLEIntField("Filler", 0xFFFFFFFF), 

2279 XStrFixedLenField("SND_SEQ", b"", length=8), 

2280 PadField( # sect 1.2.2.3 

2281 XStrFixedLenField("SGN_CKSUM", b"", length=8), 

2282 align=8, 

2283 padwith=b"\x04", 

2284 ), 

2285 ] 

2286 

2287 def default_payload_class(self, payload): 

2288 return conf.padding_layer 

2289 

2290 

2291_InitialContextTokens[b"\x01\x01"] = KRB_GSS_MIC_RFC1964 

2292 

2293# RFC 1964 - sect 1.2.2 

2294 

2295 

2296class KRB_GSS_Wrap_RFC1964(Packet): 

2297 name = "Kerberos v5 GSS_Wrap (RFC1964)" 

2298 fields_desc = [ 

2299 LEShortEnumField("SGN_ALG", 0, _SGN_ALGS), 

2300 LEShortEnumField("SEAL_ALG", 0, _SEAL_ALGS), 

2301 XLEShortField("Filler", 0xFFFF), 

2302 XStrFixedLenField("SND_SEQ", b"", length=8), 

2303 PadField( # sect 1.2.2.3 

2304 XStrFixedLenField("SGN_CKSUM", b"", length=8), 

2305 align=8, 

2306 padwith=b"\x04", 

2307 ), 

2308 # sect 1.2.2.3 

2309 XStrFixedLenField("CONFOUNDER", b"", length=8), 

2310 ] 

2311 

2312 def default_payload_class(self, payload): 

2313 return conf.padding_layer 

2314 

2315 

2316_InitialContextTokens[b"\x02\x01"] = KRB_GSS_Wrap_RFC1964 

2317 

2318 

2319# RFC 1964 - sect 1.2.2 

2320 

2321 

2322class KRB_GSS_Delete_sec_context_RFC1964(Packet): 

2323 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)" 

2324 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc 

2325 

2326 

2327_InitialContextTokens[b"\x01\x02"] = KRB_GSS_Delete_sec_context_RFC1964 

2328 

2329 

2330# RFC 4121 - sect 4.2.2 

2331_KRB5_GSS_Flags = [ 

2332 "SentByAcceptor", 

2333 "Sealed", 

2334 "AcceptorSubkey", 

2335] 

2336 

2337 

2338# RFC 4121 - sect 4.2.6.1 

2339 

2340 

2341class KRB_GSS_MIC(Packet): 

2342 name = "Kerberos v5 MIC Token" 

2343 fields_desc = [ 

2344 FlagsField("Flags", 0, 8, _KRB5_GSS_Flags), 

2345 XStrFixedLenField("Filler", b"\xff\xff\xff\xff\xff", length=5), 

2346 LongField("SND_SEQ", 0), # Big endian 

2347 XStrField("SGN_CKSUM", b"\x00" * 12), 

2348 ] 

2349 

2350 def default_payload_class(self, payload): 

2351 return conf.padding_layer 

2352 

2353 

2354_InitialContextTokens[b"\x04\x04"] = KRB_GSS_MIC 

2355 

2356 

2357# RFC 4121 - sect 4.2.6.2 

2358 

2359 

2360class KRB_GSS_Wrap(Packet): 

2361 name = "Kerberos v5 Wrap Token" 

2362 fields_desc = [ 

2363 FlagsField("Flags", 0, 8, _KRB5_GSS_Flags), 

2364 XByteField("Filler", 0xFF), 

2365 ShortField("EC", 0), # Big endian 

2366 ShortField("RRC", 0), # Big endian 

2367 LongField("SND_SEQ", 0), # Big endian 

2368 MultipleTypeField( 

2369 [ 

2370 ( 

2371 XStrField("Data", b""), 

2372 lambda pkt: pkt.Flags.Sealed, 

2373 ) 

2374 ], 

2375 XStrLenField("Data", b"", length_from=lambda pkt: pkt.EC), 

2376 ), 

2377 ] 

2378 

2379 def default_payload_class(self, payload): 

2380 return conf.padding_layer 

2381 

2382 

2383_InitialContextTokens[b"\x05\x04"] = KRB_GSS_Wrap 

2384 

2385 

2386# Kerberos IAKERB - draft-ietf-kitten-iakerb-03 

2387 

2388 

2389class IAKERB_HEADER(ASN1_Packet): 

2390 ASN1_codec = ASN1_Codecs.BER 

2391 ASN1_root = ASN1F_SEQUENCE( 

2392 Realm("targetRealm", "", explicit_tag=0xA1), 

2393 ASN1F_optional( 

2394 ASN1F_STRING("cookie", None, explicit_tag=0xA2), 

2395 ), 

2396 ) 

2397 

2398 

2399_InitialContextTokens[b"\x05\x01"] = IAKERB_HEADER 

2400 

2401 

2402# Register for GSSAPI 

2403 

2404# Kerberos 5 

2405_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2406_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2407# Kerberos 5 - U2U 

2408_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken 

2409# Kerberos 5 - IAKERB 

2410_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken 

2411 

2412 

2413# Entry class 

2414 

2415# RFC4120 sect 5.10 

2416 

2417 

2418class Kerberos(ASN1_Packet): 

2419 ASN1_codec = ASN1_Codecs.BER 

2420 ASN1_root = ASN1F_CHOICE( 

2421 "root", 

2422 None, 

2423 # RFC4120 

2424 KRB_GSSAPI_Token, # [APPLICATION 0] 

2425 KRB_Ticket, # [APPLICATION 1] 

2426 KRB_Authenticator, # [APPLICATION 2] 

2427 KRB_AS_REQ, # [APPLICATION 10] 

2428 KRB_AS_REP, # [APPLICATION 11] 

2429 KRB_TGS_REQ, # [APPLICATION 12] 

2430 KRB_TGS_REP, # [APPLICATION 13] 

2431 KRB_AP_REQ, # [APPLICATION 14] 

2432 KRB_AP_REP, # [APPLICATION 15] 

2433 # RFC4120 

2434 KRB_ERROR, # [APPLICATION 30] 

2435 ) 

2436 

2437 def mysummary(self): 

2438 return self.root.summary() 

2439 

2440 

2441bind_bottom_up(UDP, Kerberos, sport=88) 

2442bind_bottom_up(UDP, Kerberos, dport=88) 

2443bind_layers(UDP, Kerberos, sport=88, dport=88) 

2444 

2445_InitialContextTokens[b"\x01\x00"] = KRB_AP_REQ 

2446_InitialContextTokens[b"\x02\x00"] = KRB_AP_REP 

2447_InitialContextTokens[b"\x03\x00"] = KRB_ERROR 

2448_InitialContextTokens[b"\x04\x00"] = KRB_TGT_REQ 

2449_InitialContextTokens[b"\x04\x01"] = KRB_TGT_REP 

2450 

2451 

2452# RFC4120 sect 7.2.2 

2453 

2454 

2455class KerberosTCPHeader(Packet): 

2456 # According to RFC 5021, first bit to 1 has a special meaning and 

2457 # negotiates Kerberos TCP extensions... But apart from rfc6251 no one used that 

2458 # https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-4 

2459 fields_desc = [LenField("len", None, fmt="!I")] 

2460 

2461 @classmethod 

2462 def tcp_reassemble(cls, data, *args, **kwargs): 

2463 if len(data) < 4: 

2464 return None 

2465 length = struct.unpack("!I", data[:4])[0] 

2466 if len(data) == length + 4: 

2467 return cls(data) 

2468 

2469 

2470bind_layers(KerberosTCPHeader, Kerberos) 

2471 

2472bind_bottom_up(TCP, KerberosTCPHeader, sport=88) 

2473bind_layers(TCP, KerberosTCPHeader, dport=88) 

2474 

2475 

2476# RFC3244 sect 2 

2477 

2478 

2479class KPASSWD_REQ(Packet): 

2480 fields_desc = [ 

2481 ShortField("len", None), 

2482 ShortField("pvno", 0xFF80), 

2483 ShortField("apreqlen", None), 

2484 PacketLenField( 

2485 "apreq", KRB_AP_REQ(), KRB_AP_REQ, length_from=lambda pkt: pkt.apreqlen 

2486 ), 

2487 ConditionalField( 

2488 PacketLenField( 

2489 "krbpriv", 

2490 KRB_PRIV(), 

2491 KRB_PRIV, 

2492 length_from=lambda pkt: pkt.len - 6 - pkt.apreqlen, 

2493 ), 

2494 lambda pkt: pkt.apreqlen != 0, 

2495 ), 

2496 ConditionalField( 

2497 PacketLenField( 

2498 "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6 

2499 ), 

2500 lambda pkt: pkt.apreqlen == 0, 

2501 ), 

2502 ] 

2503 

2504 def post_build(self, p, pay): 

2505 if self.len is None: 

2506 p = struct.pack("!H", len(p)) + p[2:] 

2507 if self.apreqlen is None and self.krbpriv is not None: 

2508 p = p[:4] + struct.pack("!H", len(self.apreq)) + p[6:] 

2509 return p + pay 

2510 

2511 

2512class ChangePasswdData(ASN1_Packet): 

2513 ASN1_codec = ASN1_Codecs.BER 

2514 ASN1_root = ASN1F_SEQUENCE( 

2515 ASN1F_STRING("newpasswd", ASN1_STRING(""), explicit_tag=0xA0), 

2516 ASN1F_optional( 

2517 ASN1F_PACKET("targname", None, PrincipalName, explicit_tag=0xA1) 

2518 ), 

2519 ASN1F_optional(Realm("targrealm", None, explicit_tag=0xA2)), 

2520 ) 

2521 

2522 

2523class KPASSWD_REP(Packet): 

2524 fields_desc = [ 

2525 ShortField("len", None), 

2526 ShortField("pvno", 0x0001), 

2527 ShortField("apreplen", None), 

2528 PacketLenField( 

2529 "aprep", KRB_AP_REP(), KRB_AP_REP, length_from=lambda pkt: pkt.apreplen 

2530 ), 

2531 ConditionalField( 

2532 PacketLenField( 

2533 "krbpriv", 

2534 KRB_PRIV(), 

2535 KRB_PRIV, 

2536 length_from=lambda pkt: pkt.len - 6 - pkt.apreplen, 

2537 ), 

2538 lambda pkt: pkt.apreplen != 0, 

2539 ), 

2540 ConditionalField( 

2541 PacketLenField( 

2542 "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6 

2543 ), 

2544 lambda pkt: pkt.apreplen == 0, 

2545 ), 

2546 ] 

2547 

2548 def post_build(self, p, pay): 

2549 if self.len is None: 

2550 p = struct.pack("!H", len(p)) + p[2:] 

2551 if self.apreplen is None and self.krbpriv is not None: 

2552 p = p[:4] + struct.pack("!H", len(self.aprep)) + p[6:] 

2553 return p + pay 

2554 

2555 def answers(self, other): 

2556 return isinstance(other, KPASSWD_REQ) 

2557 

2558 

2559KPASSWD_RESULTS = { 

2560 0: "KRB5_KPASSWD_SUCCESS", 

2561 1: "KRB5_KPASSWD_MALFORMED", 

2562 2: "KRB5_KPASSWD_HARDERROR", 

2563 3: "KRB5_KPASSWD_AUTHERROR", 

2564 4: "KRB5_KPASSWD_SOFTERROR", 

2565 5: "KRB5_KPASSWD_ACCESSDENIED", 

2566 6: "KRB5_KPASSWD_BAD_VERSION", 

2567 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED", 

2568} 

2569 

2570 

2571class KPasswdRepData(Packet): 

2572 fields_desc = [ 

2573 ShortEnumField("resultCode", 0, KPASSWD_RESULTS), 

2574 StrField("resultString", ""), 

2575 ] 

2576 

2577 

2578class Kpasswd(Packet): 

2579 @classmethod 

2580 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

2581 if _pkt and len(_pkt) >= 4: 

2582 if _pkt[2:4] == b"\xff\x80": 

2583 return KPASSWD_REQ 

2584 elif _pkt[2:4] == b"\x00\x01": 

2585 asn1_tag = BER_id_dec(_pkt[6:8])[0] & 0x1F 

2586 if asn1_tag == 14: 

2587 return KPASSWD_REQ 

2588 elif asn1_tag == 15: 

2589 return KPASSWD_REP 

2590 return KPASSWD_REQ 

2591 

2592 

2593bind_bottom_up(UDP, Kpasswd, sport=464) 

2594bind_bottom_up(UDP, Kpasswd, dport=464) 

2595bind_top_down(UDP, KPASSWD_REQ, sport=464, dport=464) 

2596bind_top_down(UDP, KPASSWD_REP, sport=464, dport=464) 

2597 

2598 

2599class KpasswdTCPHeader(Packet): 

2600 fields_desc = [LenField("len", None, fmt="!I")] 

2601 

2602 @classmethod 

2603 def tcp_reassemble(cls, data, *args, **kwargs): 

2604 if len(data) < 4: 

2605 return None 

2606 length = struct.unpack("!I", data[:4])[0] 

2607 if len(data) == length + 4: 

2608 return cls(data) 

2609 

2610 

2611bind_layers(KpasswdTCPHeader, Kpasswd) 

2612 

2613bind_bottom_up(TCP, KpasswdTCPHeader, sport=464) 

2614bind_layers(TCP, KpasswdTCPHeader, dport=464) 

2615 

2616# [MS-KKDCP] 

2617 

2618 

2619class _KerbMessage_Field(ASN1F_STRING_PacketField): 

2620 def m2i(self, pkt, s): 

2621 val = super(_KerbMessage_Field, self).m2i(pkt, s) 

2622 if not val[0].val: 

2623 return val 

2624 return KerberosTCPHeader(val[0].val, _underlayer=pkt), val[1] 

2625 

2626 

2627class KDC_PROXY_MESSAGE(ASN1_Packet): 

2628 ASN1_codec = ASN1_Codecs.BER 

2629 ASN1_root = ASN1F_SEQUENCE( 

2630 _KerbMessage_Field("kerbMessage", "", explicit_tag=0xA0), 

2631 ASN1F_optional(Realm("targetDomain", None, explicit_tag=0xA1)), 

2632 ASN1F_optional( 

2633 ASN1F_FLAGS( 

2634 "dclocatorHint", 

2635 None, 

2636 FlagsField("", 0, -32, _NV_VERSION).names, 

2637 explicit_tag=0xA2, 

2638 ) 

2639 ), 

2640 ) 

2641 

2642 

2643class KdcProxySocket(SuperSocket): 

2644 """ 

2645 This is a wrapper of a HTTP_Client that does KKDCP proxying, 

2646 disguised as a SuperSocket to be compatible with the rest of the KerberosClient. 

2647 """ 

2648 

2649 def __init__( 

2650 self, 

2651 url, 

2652 targetDomain, 

2653 dclocatorHint=None, 

2654 no_check_certificate=False, 

2655 **kwargs, 

2656 ): 

2657 self.url = url 

2658 self.targetDomain = targetDomain 

2659 self.dclocatorHint = dclocatorHint 

2660 self.no_check_certificate = no_check_certificate 

2661 self.queue = deque() 

2662 super(KdcProxySocket, self).__init__(**kwargs) 

2663 

2664 def recv(self, x=None): 

2665 return self.queue.popleft() 

2666 

2667 def send(self, x, **kwargs): 

2668 from scapy.layers.http import HTTP_Client 

2669 

2670 cli = HTTP_Client(no_check_certificate=self.no_check_certificate) 

2671 try: 

2672 # sr it via the web client 

2673 resp = cli.request( 

2674 self.url, 

2675 Method="POST", 

2676 data=bytes( 

2677 # Wrap request in KDC_PROXY_MESSAGE 

2678 KDC_PROXY_MESSAGE( 

2679 kerbMessage=bytes(x), 

2680 targetDomain=ASN1_GENERAL_STRING(self.targetDomain.encode()), 

2681 # dclocatorHint is optional 

2682 dclocatorHint=self.dclocatorHint, 

2683 ) 

2684 ), 

2685 http_headers={ 

2686 "Cache-Control": "no-cache", 

2687 "Pragma": "no-cache", 

2688 "User-Agent": "kerberos/1.0", 

2689 }, 

2690 ) 

2691 if resp and conf.raw_layer in resp: 

2692 # Parse the payload 

2693 resp = KDC_PROXY_MESSAGE(resp.load).kerbMessage 

2694 # We have an answer, queue it. 

2695 self.queue.append(resp) 

2696 else: 

2697 raise EOFError 

2698 finally: 

2699 cli.close() 

2700 

2701 @staticmethod 

2702 def select(sockets, remain=None): 

2703 return [x for x in sockets if isinstance(x, KdcProxySocket) and x.queue] 

2704 

2705 

2706# Util functions 

2707 

2708 

2709class KerberosClient(Automaton): 

2710 """ 

2711 :param mode: the mode to use for the client (default: AS_REQ). 

2712 :param ip: the IP of the DC (default: discovered by dclocator) 

2713 :param upn: the UPN of the client. 

2714 :param password: the password of the client. 

2715 :param key: the Key of the client (instead of the password) 

2716 :param realm: the realm of the domain. (default: from the UPN) 

2717 :param spn: the SPN to request in a TGS-REQ 

2718 :param ticket: the existing ticket to use in a TGS-REQ 

2719 :param host: the name of the host doing the request 

2720 :param renew: sets the Renew flag in a TGS-REQ 

2721 :param additional_tickets: in U2U or S4U2Proxy, the additional tickets 

2722 :param u2u: sets the U2U flag 

2723 :param for_user: the UPN of another user in TGS-REQ, to do a S4U2Self 

2724 :param s4u2proxy: sets the S4U2Proxy flag 

2725 :param dmsa: sets the 'unconditional delegation' mode for DMSA TGT retrieval 

2726 :param kdc_proxy: specify a KDC proxy url 

2727 :param kdc_proxy_no_check_certificate: do not check the KDC proxy certificate 

2728 :param fast: use FAST armoring 

2729 :param armor_ticket: an external ticket to use for armoring 

2730 :param armor_ticket_upn: the UPN of the client of the armoring ticket 

2731 :param armor_ticket_skey: the session Key object of the armoring ticket 

2732 :param etypes: specify the list of encryption types to support 

2733 :param port: the Kerberos port (default 88) 

2734 :param timeout: timeout of each request (default 5) 

2735 """ 

2736 

2737 RES_AS_MODE = namedtuple("AS_Result", ["asrep", "sessionkey", "kdcrep"]) 

2738 RES_TGS_MODE = namedtuple("TGS_Result", ["tgsrep", "sessionkey", "kdcrep"]) 

2739 

2740 class MODE(IntEnum): 

2741 AS_REQ = 0 

2742 TGS_REQ = 1 

2743 GET_SALT = 2 

2744 

2745 def __init__( 

2746 self, 

2747 mode=MODE.AS_REQ, 

2748 ip=None, 

2749 upn=None, 

2750 password=None, 

2751 key=None, 

2752 realm=None, 

2753 spn=None, 

2754 ticket=None, 

2755 host=None, 

2756 renew=False, 

2757 additional_tickets=[], 

2758 u2u=False, 

2759 for_user=None, 

2760 s4u2proxy=False, 

2761 dmsa=False, 

2762 kdc_proxy=None, 

2763 kdc_proxy_no_check_certificate=False, 

2764 fast=False, 

2765 armor_ticket=None, 

2766 armor_ticket_upn=None, 

2767 armor_ticket_skey=None, 

2768 key_list_req=[], 

2769 etypes=None, 

2770 port=88, 

2771 timeout=5, 

2772 **kwargs, 

2773 ): 

2774 import scapy.libs.rfc3961 # Trigger error if any # noqa: F401 

2775 from scapy.layers.ldap import dclocator 

2776 

2777 if not upn: 

2778 raise ValueError("Invalid upn") 

2779 if not spn: 

2780 raise ValueError("Invalid spn") 

2781 if realm is None: 

2782 if mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

2783 _, realm = _parse_upn(upn) 

2784 elif mode == self.MODE.TGS_REQ: 

2785 _, realm = _parse_spn(spn) 

2786 if not realm and ticket: 

2787 # if no realm is specified, but there's a ticket, take the realm 

2788 # of the ticket. 

2789 realm = ticket.realm.val.decode() 

2790 else: 

2791 raise ValueError("Invalid realm") 

2792 

2793 if mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

2794 if not host: 

2795 raise ValueError("Invalid host") 

2796 elif mode == self.MODE.TGS_REQ: 

2797 if not ticket: 

2798 raise ValueError("Invalid ticket") 

2799 

2800 if not ip and not kdc_proxy: 

2801 # No KDC IP provided. Find it by querying the DNS 

2802 ip = dclocator( 

2803 realm, 

2804 timeout=timeout, 

2805 # Use connect mode instead of ldap for compatibility 

2806 # with MIT kerberos servers 

2807 mode="connect", 

2808 port=port, 

2809 debug=kwargs.get("debug", 0), 

2810 ).ip 

2811 

2812 if fast: 

2813 if mode == self.MODE.AS_REQ: 

2814 # Requires an external ticket 

2815 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

2816 raise ValueError( 

2817 "Implicit armoring is not possible on AS-REQ: " 

2818 "please provide the 3 required armor arguments" 

2819 ) 

2820 elif mode == self.MODE.TGS_REQ: 

2821 if armor_ticket and (not armor_ticket_upn or not armor_ticket_skey): 

2822 raise ValueError( 

2823 "Cannot specify armor_ticket without armor_ticket_{upn,skey}" 

2824 ) 

2825 

2826 if mode == self.MODE.GET_SALT: 

2827 if etypes is not None: 

2828 raise ValueError("Cannot specify etypes in GET_SALT mode !") 

2829 

2830 from scapy.libs.rfc3961 import EncryptionType 

2831 

2832 etypes = [ 

2833 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

2834 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

2835 ] 

2836 elif etypes is None: 

2837 from scapy.libs.rfc3961 import EncryptionType 

2838 

2839 etypes = [ 

2840 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

2841 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

2842 EncryptionType.RC4_HMAC, 

2843 EncryptionType.RC4_HMAC_EXP, 

2844 EncryptionType.DES_CBC_MD5, 

2845 ] 

2846 self.etypes = etypes 

2847 

2848 self.mode = mode 

2849 

2850 self.result = None # Result 

2851 

2852 self._timeout = timeout 

2853 self._ip = ip 

2854 self._port = port 

2855 self.kdc_proxy = kdc_proxy 

2856 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

2857 

2858 if self.mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

2859 self.host = host.upper() 

2860 self.password = password and bytes_encode(password) 

2861 self.spn = spn 

2862 self.upn = upn 

2863 self.realm = realm.upper() 

2864 self.ticket = ticket 

2865 self.fast = fast 

2866 self.armor_ticket = armor_ticket 

2867 self.armor_ticket_upn = armor_ticket_upn 

2868 self.armor_ticket_skey = armor_ticket_skey 

2869 self.key_list_req = key_list_req 

2870 self.renew = renew 

2871 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

2872 self.u2u = u2u # U2U 

2873 self.for_user = for_user # FOR-USER 

2874 self.s4u2proxy = s4u2proxy # S4U2Proxy 

2875 self.dmsa = dmsa # DMSA 

2876 self.key = key 

2877 self.subkey = None # In the AP-REQ authenticator 

2878 self.replykey = None # Key used for reply 

2879 # See RFC4120 - sect 7.2.2 

2880 # This marks whether we should follow-up after an EOF 

2881 self.should_followup = False 

2882 # This marks that we sent a FAST-req and are awaiting for an answer 

2883 self.fast_req_sent = False 

2884 # Session parameters 

2885 self.pre_auth = False 

2886 self.fast_rep = None 

2887 self.fast_error = None 

2888 self.fast_skey = None # The random subkey used for fast 

2889 self.fast_armorkey = None # The armor key 

2890 self.fxcookie = None 

2891 

2892 sock = self._connect() 

2893 super(KerberosClient, self).__init__( 

2894 sock=sock, 

2895 **kwargs, 

2896 ) 

2897 

2898 def _connect(self): 

2899 if self.kdc_proxy: 

2900 # If we are using a KDC Proxy, wrap the socket with the KdcProxySocket, 

2901 # that takes our messages and transport them over HTTP. 

2902 sock = KdcProxySocket( 

2903 url=self.kdc_proxy, 

2904 targetDomain=self.realm, 

2905 no_check_certificate=self.kdc_proxy_no_check_certificate, 

2906 ) 

2907 else: 

2908 sock = socket.socket() 

2909 sock.settimeout(self._timeout) 

2910 sock.connect((self._ip, self._port)) 

2911 sock = StreamSocket(sock, KerberosTCPHeader) 

2912 return sock 

2913 

2914 def send(self, pkt): 

2915 super(KerberosClient, self).send(KerberosTCPHeader() / pkt) 

2916 

2917 def _base_kdc_req(self, now_time): 

2918 kdcreq = KRB_KDC_REQ_BODY( 

2919 etype=[ASN1_INTEGER(x) for x in self.etypes], 

2920 additionalTickets=None, 

2921 # Windows default 

2922 kdcOptions="forwardable+renewable+canonicalize+renewable-ok", 

2923 cname=None, 

2924 realm=ASN1_GENERAL_STRING(self.realm), 

2925 till=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)), 

2926 rtime=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)), 

2927 nonce=ASN1_INTEGER(RandNum(0, 0x7FFFFFFF)._fix()), 

2928 ) 

2929 if self.renew: 

2930 kdcreq.kdcOptions.set(30, 1) # set 'renew' (bit 30) 

2931 return kdcreq 

2932 

2933 def calc_fast_armorkey(self): 

2934 """ 

2935 Calculate and return the FAST armorkey 

2936 """ 

2937 # Generate a random key of the same type than ticket_skey 

2938 from scapy.libs.rfc3961 import Key, KRB_FX_CF2 

2939 

2940 if self.mode == self.MODE.AS_REQ: 

2941 # AS-REQ mode 

2942 self.fast_skey = Key.new_random_key(self.armor_ticket_skey.etype) 

2943 

2944 self.fast_armorkey = KRB_FX_CF2( 

2945 self.fast_skey, 

2946 self.armor_ticket_skey, 

2947 b"subkeyarmor", 

2948 b"ticketarmor", 

2949 ) 

2950 elif self.mode == self.MODE.TGS_REQ: 

2951 # TGS-REQ: 2 cases 

2952 

2953 self.subkey = Key.new_random_key(self.key.etype) 

2954 

2955 if not self.armor_ticket: 

2956 # Case 1: Implicit armoring 

2957 self.fast_armorkey = KRB_FX_CF2( 

2958 self.subkey, 

2959 self.key, 

2960 b"subkeyarmor", 

2961 b"ticketarmor", 

2962 ) 

2963 else: 

2964 # Case 2: Explicit armoring, in "Compounded Identity mode". 

2965 # This is a Microsoft extension: see [MS-KILE] sect 3.3.5.7.4 

2966 

2967 self.fast_skey = Key.new_random_key(self.armor_ticket_skey.etype) 

2968 

2969 explicit_armor_key = KRB_FX_CF2( 

2970 self.fast_skey, 

2971 self.armor_ticket_skey, 

2972 b"subkeyarmor", 

2973 b"ticketarmor", 

2974 ) 

2975 

2976 self.fast_armorkey = KRB_FX_CF2( 

2977 explicit_armor_key, 

2978 self.subkey, 

2979 b"explicitarmor", 

2980 b"tgsarmor", 

2981 ) 

2982 

2983 def _fast_wrap(self, kdc_req, padata, now_time, pa_tgsreq_ap=None): 

2984 """ 

2985 :param kdc_req: the KDC_REQ_BODY to wrap 

2986 :param padata: the list of PADATA to wrap 

2987 :param now_time: the current timestamp used by the client 

2988 """ 

2989 

2990 # Create the PA Fast request wrapper 

2991 pafastreq = PA_FX_FAST_REQUEST( 

2992 armoredData=KrbFastArmoredReq( 

2993 reqChecksum=Checksum(), 

2994 encFastReq=EncryptedData(), 

2995 ) 

2996 ) 

2997 

2998 if self.armor_ticket is not None: 

2999 # EXPLICIT mode only (AS-REQ or TGS-REQ) 

3000 

3001 pafastreq.armoredData.armor = KrbFastArmor( 

3002 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3003 armorValue=KRB_AP_REQ( 

3004 ticket=self.armor_ticket, 

3005 authenticator=EncryptedData(), 

3006 ), 

3007 ) 

3008 

3009 # Populate the authenticator. Note the client is the wrapper 

3010 _, crealm = _parse_upn(self.armor_ticket_upn) 

3011 authenticator = KRB_Authenticator( 

3012 crealm=ASN1_GENERAL_STRING(crealm), 

3013 cname=PrincipalName.fromUPN(self.armor_ticket_upn), 

3014 cksum=None, 

3015 ctime=ASN1_GENERALIZED_TIME(now_time), 

3016 cusec=ASN1_INTEGER(0), 

3017 subkey=EncryptionKey.fromKey(self.fast_skey), 

3018 seqNumber=ASN1_INTEGER(0), 

3019 encAuthorizationData=None, 

3020 ) 

3021 pafastreq.armoredData.armor.armorValue.authenticator.encrypt( 

3022 self.armor_ticket_skey, 

3023 authenticator, 

3024 ) 

3025 

3026 # Sign the fast request wrapper 

3027 if self.mode == self.MODE.TGS_REQ: 

3028 # "for a TGS-REQ, it is performed over the type AP- 

3029 # REQ in the PA-TGS-REQ padata of the TGS request" 

3030 pafastreq.armoredData.reqChecksum.make( 

3031 self.fast_armorkey, 

3032 bytes(pa_tgsreq_ap), 

3033 ) 

3034 else: 

3035 # "For an AS-REQ, it is performed over the type KDC-REQ- 

3036 # BODY for the req-body field of the KDC-REQ structure of the 

3037 # containing message" 

3038 pafastreq.armoredData.reqChecksum.make( 

3039 self.fast_armorkey, 

3040 bytes(kdc_req), 

3041 ) 

3042 

3043 # Build and encrypt the Fast request 

3044 fastreq = KrbFastReq( 

3045 padata=padata, 

3046 reqBody=kdc_req, 

3047 ) 

3048 pafastreq.armoredData.encFastReq.encrypt( 

3049 self.fast_armorkey, 

3050 fastreq, 

3051 ) 

3052 

3053 # Return the PADATA 

3054 return PADATA( 

3055 padataType=ASN1_INTEGER(136), # PA-FX-FAST 

3056 padataValue=pafastreq, 

3057 ) 

3058 

3059 def as_req(self): 

3060 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

3061 

3062 # 1. Build and populate KDC-REQ 

3063 kdc_req = self._base_kdc_req(now_time=now_time) 

3064 kdc_req.addresses = [ 

3065 HostAddress( 

3066 addrType=ASN1_INTEGER(20), # Netbios 

3067 address=ASN1_STRING(self.host.ljust(16, " ")), 

3068 ) 

3069 ] 

3070 kdc_req.cname = PrincipalName.fromUPN(self.upn) 

3071 kdc_req.sname = PrincipalName.fromSPN(self.spn) 

3072 

3073 # 2. Build the list of PADATA 

3074 padata = [ 

3075 PADATA( 

3076 padataType=ASN1_INTEGER(128), # PA-PAC-REQUEST 

3077 padataValue=PA_PAC_REQUEST(includePac=ASN1_BOOLEAN(-1)), 

3078 ) 

3079 ] 

3080 

3081 # Cookie support 

3082 if self.fxcookie: 

3083 padata.insert( 

3084 0, 

3085 PADATA( 

3086 padataType=133, # PA-FX-COOKIE 

3087 padataValue=self.fxcookie, 

3088 ), 

3089 ) 

3090 

3091 # FAST 

3092 if self.fast: 

3093 # Calculate the armor key 

3094 self.calc_fast_armorkey() 

3095 

3096 # [MS-KILE] sect 3.2.5.5 

3097 # "When sending the AS-REQ, add a PA-PAC-OPTIONS [167]" 

3098 padata.append( 

3099 PADATA( 

3100 padataType=ASN1_INTEGER(167), # PA-PAC-OPTIONS 

3101 padataValue=PA_PAC_OPTIONS( 

3102 options="Claims", 

3103 ), 

3104 ) 

3105 ) 

3106 

3107 # Pre-auth is requested 

3108 if self.pre_auth: 

3109 if self.fast: 

3110 # Special FAST factor 

3111 # RFC6113 sect 5.4.6 

3112 from scapy.libs.rfc3961 import KRB_FX_CF2 

3113 

3114 # Calculate the 'challenge key' 

3115 ts_key = KRB_FX_CF2( 

3116 self.fast_armorkey, 

3117 self.key, 

3118 b"clientchallengearmor", 

3119 b"challengelongterm", 

3120 ) 

3121 pafactor = PADATA( 

3122 padataType=138, # PA-ENCRYPTED-CHALLENGE 

3123 padataValue=EncryptedData(), 

3124 ) 

3125 else: 

3126 # Usual 'timestamp' factor 

3127 ts_key = self.key 

3128 pafactor = PADATA( 

3129 padataType=2, # PA-ENC-TIMESTAMP 

3130 padataValue=EncryptedData(), 

3131 ) 

3132 pafactor.padataValue.encrypt( 

3133 ts_key, 

3134 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3135 ) 

3136 padata.insert( 

3137 0, 

3138 pafactor, 

3139 ) 

3140 

3141 # FAST support 

3142 if self.fast: 

3143 # We are using RFC6113's FAST armoring. The PADATA's are therefore 

3144 # hidden inside the encrypted section. 

3145 padata = [ 

3146 self._fast_wrap( 

3147 kdc_req=kdc_req, 

3148 padata=padata, 

3149 now_time=now_time, 

3150 ) 

3151 ] 

3152 

3153 # 3. Build the request 

3154 asreq = Kerberos( 

3155 root=KRB_AS_REQ( 

3156 padata=padata, 

3157 reqBody=kdc_req, 

3158 ) 

3159 ) 

3160 

3161 # Note the reply key 

3162 self.replykey = self.key 

3163 

3164 return asreq 

3165 

3166 def tgs_req(self): 

3167 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

3168 

3169 # Compute armor key for FAST 

3170 if self.fast: 

3171 self.calc_fast_armorkey() 

3172 

3173 # 1. Build and populate KDC-REQ 

3174 kdc_req = self._base_kdc_req(now_time=now_time) 

3175 kdc_req.sname = PrincipalName.fromSPN(self.spn) 

3176 

3177 # Additional tickets 

3178 if self.additional_tickets: 

3179 kdc_req.additionalTickets = self.additional_tickets 

3180 

3181 # U2U 

3182 if self.u2u: 

3183 kdc_req.kdcOptions.set(28, 1) # set 'enc-tkt-in-skey' (bit 28) 

3184 

3185 # 2. Build the list of PADATA 

3186 padata = [] 

3187 

3188 # [MS-SFU] FOR-USER extension 

3189 if self.for_user is not None: 

3190 from scapy.libs.rfc3961 import ChecksumType, EncryptionType 

3191 

3192 # [MS-SFU] note 4: 

3193 # "Windows Vista, Windows Server 2008, Windows 7, and Windows Server 

3194 # 2008 R2 send the PA-S4U-X509-USER padata type alone if the user's 

3195 # certificate is available. 

3196 # If the user's certificate is not available, it sends both the 

3197 # PA-S4U-X509-USER padata type and the PA-FOR-USER padata type. 

3198 # When the PA-S4U-X509-USER padata type is used without the user's 

3199 # certificate, the certificate field is not present." 

3200 

3201 # 1. Add PA_S4U_X509_USER 

3202 pasfux509 = PA_S4U_X509_USER( 

3203 userId=S4UUserID( 

3204 nonce=kdc_req.nonce, 

3205 # [MS-SFU] note 5: 

3206 # "Windows S4U clients always set this option." 

3207 options="USE_REPLY_KEY_USAGE", 

3208 cname=PrincipalName.fromUPN(self.for_user), 

3209 crealm=ASN1_GENERAL_STRING(_parse_upn(self.for_user)[1]), 

3210 subjectCertificate=None, # TODO 

3211 ), 

3212 checksum=Checksum(), 

3213 ) 

3214 

3215 if self.dmsa: 

3216 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

3217 pasfux509.userId.options.set(4, 1) 

3218 

3219 if self.key.etype in [EncryptionType.RC4_HMAC, EncryptionType.RC4_HMAC_EXP]: 

3220 # "if the key's encryption type is RC4_HMAC_NT (23) the checksum type 

3221 # is rsa-md4 (2) as defined in section 6.2.6 of [RFC3961]." 

3222 pasfux509.checksum.make( 

3223 self.key, 

3224 bytes(pasfux509.userId), 

3225 cksumtype=ChecksumType.RSA_MD4, 

3226 ) 

3227 else: 

3228 pasfux509.checksum.make( 

3229 self.key, 

3230 bytes(pasfux509.userId), 

3231 ) 

3232 padata.append( 

3233 PADATA( 

3234 padataType=ASN1_INTEGER(130), # PA-FOR-X509-USER 

3235 padataValue=pasfux509, 

3236 ) 

3237 ) 

3238 

3239 # 2. Add PA_FOR_USER 

3240 if True: # XXX user's certificate is not available. 

3241 paforuser = PA_FOR_USER( 

3242 userName=PrincipalName.fromUPN(self.for_user), 

3243 userRealm=ASN1_GENERAL_STRING(_parse_upn(self.for_user)[1]), 

3244 cksum=Checksum(), 

3245 ) 

3246 S4UByteArray = struct.pack( # [MS-SFU] sect 2.2.1 

3247 "<I", paforuser.userName.nameType.val 

3248 ) + ( 

3249 ( 

3250 "".join(x.val for x in paforuser.userName.nameString) 

3251 + paforuser.userRealm.val 

3252 + paforuser.authPackage.val 

3253 ).encode() 

3254 ) 

3255 paforuser.cksum.make( 

3256 self.key, 

3257 S4UByteArray, 

3258 cksumtype=ChecksumType.HMAC_MD5, 

3259 ) 

3260 padata.append( 

3261 PADATA( 

3262 padataType=ASN1_INTEGER(129), # PA-FOR-USER 

3263 padataValue=paforuser, 

3264 ) 

3265 ) 

3266 

3267 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

3268 if self.s4u2proxy: 

3269 # "PA-PAC-OPTIONS with resource-based constrained-delegation bit set" 

3270 padata.append( 

3271 PADATA( 

3272 padataType=ASN1_INTEGER(167), # PA-PAC-OPTIONS 

3273 padataValue=PA_PAC_OPTIONS( 

3274 options="Resource-based-constrained-delegation", 

3275 ), 

3276 ) 

3277 ) 

3278 # "kdc-options field: MUST include the new cname-in-addl-tkt options flag" 

3279 kdc_req.kdcOptions.set(14, 1) 

3280 

3281 # [MS-KILE] 2.2.11 KERB-KEY-LIST-REQ 

3282 if self.key_list_req: 

3283 padata.append( 

3284 PADATA( 

3285 padataType=ASN1_INTEGER(161), # KERB-KEY-LIST-REQ 

3286 padataValue=KERB_KEY_LIST_REQ( 

3287 keytypes=[ASN1_INTEGER(x) for x in self.key_list_req] 

3288 ), 

3289 ) 

3290 ) 

3291 

3292 # 3. Build the AP-req inside a PA 

3293 apreq = KRB_AP_REQ(ticket=self.ticket, authenticator=EncryptedData()) 

3294 pa_tgs_req = PADATA( 

3295 padataType=ASN1_INTEGER(1), # PA-TGS-REQ 

3296 padataValue=apreq, 

3297 ) 

3298 

3299 # 4. Populate it's authenticator 

3300 _, crealm = _parse_upn(self.upn) 

3301 authenticator = KRB_Authenticator( 

3302 crealm=ASN1_GENERAL_STRING(crealm), 

3303 cname=PrincipalName.fromUPN(self.upn), 

3304 cksum=None, 

3305 ctime=ASN1_GENERALIZED_TIME(now_time), 

3306 cusec=ASN1_INTEGER(0), 

3307 subkey=EncryptionKey.fromKey(self.subkey) if self.subkey else None, 

3308 seqNumber=None, 

3309 encAuthorizationData=None, 

3310 ) 

3311 

3312 # Compute checksum 

3313 if self.key.cksumtype: 

3314 authenticator.cksum = Checksum() 

3315 authenticator.cksum.make( 

3316 self.key, 

3317 bytes(kdc_req), 

3318 ) 

3319 

3320 # Encrypt authenticator 

3321 apreq.authenticator.encrypt(self.key, authenticator) 

3322 

3323 # 5. Process FAST if required 

3324 if self.fast: 

3325 padata = [ 

3326 self._fast_wrap( 

3327 kdc_req=kdc_req, 

3328 padata=padata, 

3329 now_time=now_time, 

3330 pa_tgsreq_ap=apreq, 

3331 ) 

3332 ] 

3333 

3334 # 6. Add the final PADATA 

3335 padata.append(pa_tgs_req) 

3336 

3337 # 7. Build the request 

3338 tgsreq = Kerberos( 

3339 root=KRB_TGS_REQ( 

3340 padata=padata, 

3341 reqBody=kdc_req, 

3342 ) 

3343 ) 

3344 

3345 # Note the reply key 

3346 if self.subkey: 

3347 self.replykey = self.subkey 

3348 else: 

3349 self.replykey = self.key 

3350 

3351 return tgsreq 

3352 

3353 @ATMT.state(initial=1) 

3354 def BEGIN(self): 

3355 pass 

3356 

3357 @ATMT.condition(BEGIN) 

3358 def should_send_as_req(self): 

3359 if self.mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

3360 raise self.SENT_AS_REQ() 

3361 

3362 @ATMT.condition(BEGIN) 

3363 def should_send_tgs_req(self): 

3364 if self.mode == self.MODE.TGS_REQ: 

3365 raise self.SENT_TGS_REQ() 

3366 

3367 @ATMT.action(should_send_as_req) 

3368 def send_as_req(self): 

3369 self.send(self.as_req()) 

3370 

3371 @ATMT.action(should_send_tgs_req) 

3372 def send_tgs_req(self): 

3373 self.send(self.tgs_req()) 

3374 

3375 @ATMT.state() 

3376 def SENT_AS_REQ(self): 

3377 pass 

3378 

3379 @ATMT.state() 

3380 def SENT_TGS_REQ(self): 

3381 pass 

3382 

3383 def _process_padatas_and_key(self, padatas): 

3384 from scapy.libs.rfc3961 import EncryptionType, Key, KRB_FX_CF2 

3385 

3386 etype = None 

3387 salt = b"" 

3388 # 1. Process pa-data 

3389 if padatas is not None: 

3390 for padata in padatas: 

3391 if padata.padataType == 0x13 and etype is None: # PA-ETYPE-INFO2 

3392 elt = padata.padataValue.seq[0] 

3393 if elt.etype.val in self.etypes: 

3394 etype = elt.etype.val 

3395 if etype != EncryptionType.RC4_HMAC: 

3396 salt = elt.salt.val 

3397 elif padata.padataType == 133: # PA-FX-COOKIE 

3398 self.fxcookie = padata.padataValue 

3399 elif padata.padataType == 136: # PA-FX-FAST 

3400 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

3401 self.fast_rep = ( 

3402 padata.padataValue.armoredData.encFastRep.decrypt( 

3403 self.fast_armorkey, 

3404 ) 

3405 ) 

3406 elif padata.padataType == 137: # PA-FX-ERROR 

3407 self.fast_error = padata.padataValue 

3408 elif padata.padataType == 130: # PA-FOR-X509-USER 

3409 # Verify S4U checksum 

3410 key_usage_number = None 

3411 pasfux509 = padata.padataValue 

3412 # [MS-SFU] sect 2.2.2 

3413 # "In a reply, indicates that it was signed with key usage 27" 

3414 if pasfux509.userId.options.val[2] == "1": # USE_REPLY_KEY_USAGE 

3415 key_usage_number = 27 

3416 pasfux509.checksum.verify( 

3417 self.key, 

3418 bytes(pasfux509.userId), 

3419 key_usage_number=key_usage_number, 

3420 ) 

3421 

3422 # 2. Update the current key if necessary 

3423 

3424 # Compute key if not already provided 

3425 if self.key is None and etype is not None: 

3426 self.key = Key.string_to_key( 

3427 etype, 

3428 self.password, 

3429 salt, 

3430 ) 

3431 

3432 # Update the key with the fast reply, if necessary 

3433 if self.fast_rep and self.fast_rep.strengthenKey: 

3434 # "The strengthen-key field MAY be set in an AS reply" 

3435 self.replykey = KRB_FX_CF2( 

3436 self.fast_rep.strengthenKey.toKey(), 

3437 self.replykey, 

3438 b"strengthenkey", 

3439 b"replykey", 

3440 ) 

3441 

3442 @ATMT.receive_condition(SENT_AS_REQ, prio=0) 

3443 def receive_salt_mode(self, pkt): 

3444 # This is only for "Salt-Mode", a mode where we get the salt then 

3445 # exit. 

3446 if self.mode == self.MODE.GET_SALT: 

3447 if Kerberos not in pkt: 

3448 raise self.FINAL() 

3449 if not isinstance(pkt.root, KRB_ERROR): 

3450 log_runtime.error("Pre-auth is likely disabled !") 

3451 raise self.FINAL() 

3452 if pkt.root.errorCode == 25: # KDC_ERR_PREAUTH_REQUIRED 

3453 for padata in pkt.root.eData.seq: 

3454 if padata.padataType == 0x13: # PA-ETYPE-INFO2 

3455 elt = padata.padataValue.seq[0] 

3456 if elt.etype.val in self.etypes: 

3457 self.result = elt.salt.val 

3458 raise self.FINAL() 

3459 else: 

3460 log_runtime.error("Failed to retrieve the salt !") 

3461 raise self.FINAL() 

3462 

3463 @ATMT.receive_condition(SENT_AS_REQ, prio=1) 

3464 def receive_krb_error_as_req(self, pkt): 

3465 # We check for Kerberos errors. 

3466 # There is a special case for PREAUTH_REQUIRED error, which means that preauth 

3467 # is required and we need to do a second exchange. 

3468 if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR): 

3469 # Process PAs if available 

3470 if pkt.root.eData and isinstance(pkt.root.eData, MethodData): 

3471 self._process_padatas_and_key(pkt.root.eData.seq) 

3472 

3473 # Special case for FAST errors 

3474 if self.fast_rep: 

3475 # This is actually a fast response error ! 

3476 frep, self.fast_rep = self.fast_rep, None 

3477 # Re-process PAs 

3478 self._process_padatas_and_key(frep.padata) 

3479 # Extract real Kerberos error from FAST message 

3480 ferr = Kerberos(root=self.fast_error) 

3481 self.fast_error = None 

3482 # Recurse 

3483 self.receive_krb_error_as_req(ferr) 

3484 return 

3485 

3486 if pkt.root.errorCode == 25: # KDC_ERR_PREAUTH_REQUIRED 

3487 if not self.key: 

3488 log_runtime.error( 

3489 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

3490 "but no possible key could be computed." 

3491 ) 

3492 raise self.FINAL() 

3493 self.should_followup = True 

3494 self.pre_auth = True 

3495 raise self.BEGIN() 

3496 else: 

3497 log_runtime.error("Received KRB_ERROR") 

3498 pkt.show() 

3499 raise self.FINAL() 

3500 

3501 @ATMT.receive_condition(SENT_AS_REQ, prio=2) 

3502 def receive_as_rep(self, pkt): 

3503 if Kerberos in pkt and isinstance(pkt.root, KRB_AS_REP): 

3504 raise self.FINAL().action_parameters(pkt) 

3505 

3506 @ATMT.eof(SENT_AS_REQ) 

3507 def retry_after_eof_in_apreq(self): 

3508 if self.should_followup: 

3509 # Reconnect and Restart 

3510 self.should_followup = False 

3511 self.update_sock(self._connect()) 

3512 raise self.BEGIN() 

3513 else: 

3514 log_runtime.error("Socket was closed in an unexpected state") 

3515 raise self.FINAL() 

3516 

3517 @ATMT.action(receive_as_rep) 

3518 def decrypt_as_rep(self, pkt): 

3519 self._process_padatas_and_key(pkt.root.padata) 

3520 if not self.pre_auth: 

3521 log_runtime.warning("Pre-authentication was disabled for this account !") 

3522 

3523 # Process FAST response 

3524 if self.fast_rep: 

3525 # Verify the ticket-checksum 

3526 self.fast_rep.finished.ticketChecksum.verify( 

3527 self.fast_armorkey, 

3528 bytes(pkt.root.ticket), 

3529 ) 

3530 self.fast_rep = None 

3531 elif self.fast: 

3532 raise ValueError("Answer was not FAST ! Is it supported?") 

3533 

3534 # Decrypt AS-REP response 

3535 enc = pkt.root.encPart 

3536 res = enc.decrypt(self.replykey) 

3537 self.result = self.RES_AS_MODE(pkt.root, res.key.toKey(), res) 

3538 

3539 @ATMT.receive_condition(SENT_TGS_REQ) 

3540 def receive_krb_error_tgs_req(self, pkt): 

3541 if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR): 

3542 # Process PAs if available 

3543 if pkt.root.eData and isinstance(pkt.root.eData, MethodData): 

3544 self._process_padatas_and_key(pkt.root.eData.seq) 

3545 

3546 if self.fast_rep: 

3547 # This is actually a fast response error ! 

3548 frep, self.fast_rep = self.fast_rep, None 

3549 # Re-process PAs 

3550 self._process_padatas_and_key(frep.padata) 

3551 # Extract real Kerberos error from FAST message 

3552 ferr = Kerberos(root=self.fast_error) 

3553 self.fast_error = None 

3554 # Recurse 

3555 self.receive_krb_error_tgs_req(ferr) 

3556 return 

3557 

3558 if ( 

3559 pkt.root.errorCode == 0x07 

3560 and isinstance(pkt.root.eData, KERB_ERROR_UNK) 

3561 and pkt.root.eData.dataType == -128 

3562 ): 

3563 log_runtime.warning( 

3564 "KDC requires U2U for SPN '%s' !" % pkt.root.getSPN() 

3565 ) 

3566 else: 

3567 log_runtime.warning("Received KRB_ERROR") 

3568 pkt.show() 

3569 raise self.FINAL() 

3570 

3571 @ATMT.receive_condition(SENT_TGS_REQ) 

3572 def receive_tgs_rep(self, pkt): 

3573 if Kerberos in pkt and isinstance(pkt.root, KRB_TGS_REP): 

3574 if ( 

3575 not self.renew 

3576 and not self.dmsa 

3577 and pkt.root.ticket.sname.nameString[0].val == b"krbtgt" 

3578 ): 

3579 log_runtime.warning("Received a cross-realm referral ticket !") 

3580 raise self.FINAL().action_parameters(pkt) 

3581 

3582 @ATMT.action(receive_tgs_rep) 

3583 def decrypt_tgs_rep(self, pkt): 

3584 self._process_padatas_and_key(pkt.root.padata) 

3585 

3586 # Process FAST response 

3587 if self.fast_rep: 

3588 # Verify the ticket-checksum 

3589 self.fast_rep.finished.ticketChecksum.verify( 

3590 self.fast_armorkey, 

3591 bytes(pkt.root.ticket), 

3592 ) 

3593 self.fast_rep = None 

3594 elif self.fast: 

3595 raise ValueError("Answer was not FAST ! Is it supported?") 

3596 

3597 # Decrypt TGS-REP response 

3598 enc = pkt.root.encPart 

3599 if self.subkey: 

3600 # "In a TGS-REP message, the key 

3601 # usage value is 8 if the TGS session key is used, or 9 if a TGS 

3602 # authenticator subkey is used." 

3603 res = enc.decrypt(self.replykey, key_usage_number=9, cls=EncTGSRepPart) 

3604 else: 

3605 res = enc.decrypt(self.replykey) 

3606 

3607 # Store result 

3608 self.result = self.RES_TGS_MODE(pkt.root, res.key.toKey(), res) 

3609 

3610 @ATMT.state(final=1) 

3611 def FINAL(self): 

3612 pass 

3613 

3614 

3615def _parse_upn(upn): 

3616 """ 

3617 Extract the username and realm from full UPN 

3618 """ 

3619 m = re.match(r"^([^@\\/]+)(@|\\)([^@\\/]+)$", upn) 

3620 if not m: 

3621 err = "Invalid UPN: '%s'" % upn 

3622 if "/" in upn: 

3623 err += ". Did you mean '%s' ?" % upn.replace("/", "\\") 

3624 elif "@" not in upn and "\\" not in upn: 

3625 err += ". Provide domain as so: '%s@domain.local'" % upn 

3626 raise ValueError(err) 

3627 if m.group(2) == "@": 

3628 user = m.group(1) 

3629 domain = m.group(3) 

3630 else: 

3631 user = m.group(3) 

3632 domain = m.group(1) 

3633 return user, domain 

3634 

3635 

3636def _parse_spn(spn): 

3637 """ 

3638 Extract ServiceName and realm from full SPN 

3639 """ 

3640 # See [MS-ADTS] sect 2.2.21 for SPN format. We discard the servicename. 

3641 m = re.match(r"^((?:[^@\\/]+)/(?:[^@\\/]+))(?:/[^@\\/]+)?(?:@([^@\\/]+))?$", spn) 

3642 if not m: 

3643 try: 

3644 # If SPN is a UPN, we are doing U2U :D 

3645 return _parse_upn(spn) 

3646 except ValueError: 

3647 raise ValueError("Invalid SPN: '%s'" % spn) 

3648 return m.group(1), m.group(2) 

3649 

3650 

3651def _spn_are_equal(spn1, spn2): 

3652 """ 

3653 Check that two SPNs are equal. 

3654 """ 

3655 spn1, _ = _parse_spn(spn1) 

3656 spn2, _ = _parse_spn(spn2) 

3657 return spn1.lower() == spn2.lower() 

3658 

3659 

3660def krb_as_req( 

3661 upn, spn=None, ip=None, key=None, password=None, realm=None, host="WIN10", **kwargs 

3662): 

3663 r""" 

3664 Kerberos AS-Req 

3665 

3666 :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user" 

3667 or "user@DOMAIN" 

3668 :param spn: (optional) the full service principal name. 

3669 Defaults to "krbtgt/<realm>" 

3670 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for 

3671 _kerberos._tcp.dc._msdcs.domain.local). 

3672 :param key: (optional) pass the Key object. 

3673 :param password: (optional) otherwise, pass the user's password 

3674 :param realm: (optional) the realm to use. Otherwise use the one from UPN. 

3675 :param host: (optional) the host performing the AS-Req. WIN10 by default. 

3676 

3677 :return: returns a named tuple (asrep=<...>, sessionkey=<...>) 

3678 

3679 Example:: 

3680 

3681 >>> # The KDC is on 192.168.122.17, we ask a TGT for user1 

3682 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1") 

3683 

3684 Equivalent:: 

3685 

3686 >>> from scapy.libs.rfc3961 import Key, EncryptionType 

3687 >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546 

3688 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

3689 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key) 

3690 """ 

3691 if realm is None: 

3692 _, realm = _parse_upn(upn) 

3693 if key is None: 

3694 if password is None: 

3695 try: 

3696 from prompt_toolkit import prompt 

3697 

3698 password = prompt("Enter password: ", is_password=True) 

3699 except ImportError: 

3700 password = input("Enter password: ") 

3701 cli = KerberosClient( 

3702 mode=KerberosClient.MODE.AS_REQ, 

3703 realm=realm, 

3704 ip=ip, 

3705 spn=spn or "krbtgt/" + realm, 

3706 host=host, 

3707 upn=upn, 

3708 password=password, 

3709 key=key, 

3710 **kwargs, 

3711 ) 

3712 cli.run() 

3713 cli.stop() 

3714 return cli.result 

3715 

3716 

3717def krb_tgs_req( 

3718 upn, 

3719 spn, 

3720 sessionkey, 

3721 ticket, 

3722 ip=None, 

3723 renew=False, 

3724 realm=None, 

3725 additional_tickets=[], 

3726 u2u=False, 

3727 etypes=None, 

3728 for_user=None, 

3729 s4u2proxy=False, 

3730 **kwargs, 

3731): 

3732 r""" 

3733 Kerberos TGS-Req 

3734 

3735 :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user" 

3736 or "user@DOMAIN" 

3737 :param spn: the full service principal name (e.g. "cifs/srv1") 

3738 :param sessionkey: the session key retrieved from the tgt 

3739 :param ticket: the tgt ticket 

3740 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for 

3741 _kerberos._tcp.dc._msdcs.domain.local). 

3742 :param renew: ask for renewal 

3743 :param realm: (optional) the realm to use. Otherwise use the one from SPN. 

3744 :param additional_tickets: (optional) a list of additional tickets to pass. 

3745 :param u2u: (optional) if specified, enable U2U and request the ticket to be 

3746 signed using the session key from the first additional ticket. 

3747 :param etypes: array of EncryptionType values. 

3748 By default: AES128, AES256, RC4, DES_MD5 

3749 :param for_user: a user principal name to request the ticket for. This is the 

3750 S4U2Self extension. 

3751 

3752 :return: returns a named tuple (tgsrep=<...>, sessionkey=<...>) 

3753 

3754 Example:: 

3755 

3756 >>> # The KDC is on 192.168.122.17, we ask a TGT for user1 

3757 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1") 

3758 

3759 Equivalent:: 

3760 

3761 >>> from scapy.libs.rfc3961 import Key, EncryptionType 

3762 >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546 

3763 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

3764 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key) 

3765 """ 

3766 cli = KerberosClient( 

3767 mode=KerberosClient.MODE.TGS_REQ, 

3768 realm=realm, 

3769 upn=upn, 

3770 ip=ip, 

3771 spn=spn, 

3772 key=sessionkey, 

3773 ticket=ticket, 

3774 renew=renew, 

3775 additional_tickets=additional_tickets, 

3776 u2u=u2u, 

3777 etypes=etypes, 

3778 for_user=for_user, 

3779 s4u2proxy=s4u2proxy, 

3780 **kwargs, 

3781 ) 

3782 cli.run() 

3783 cli.stop() 

3784 return cli.result 

3785 

3786 

3787def krb_as_and_tgs(upn, spn, ip=None, key=None, password=None, **kwargs): 

3788 """ 

3789 Kerberos AS-Req then TGS-Req 

3790 """ 

3791 res = krb_as_req(upn=upn, ip=ip, key=key, password=password, **kwargs) 

3792 if not res: 

3793 return 

3794 return krb_tgs_req( 

3795 upn=upn, 

3796 spn=spn, 

3797 sessionkey=res.sessionkey, 

3798 ticket=res.asrep.ticket, 

3799 ip=ip, 

3800 **kwargs, 

3801 ) 

3802 

3803 

3804def krb_get_salt(upn, ip=None, realm=None, host="WIN10", **kwargs): 

3805 """ 

3806 Kerberos AS-Req only to get the salt associated with the UPN. 

3807 """ 

3808 if realm is None: 

3809 _, realm = _parse_upn(upn) 

3810 cli = KerberosClient( 

3811 mode=KerberosClient.MODE.GET_SALT, 

3812 realm=realm, 

3813 ip=ip, 

3814 spn="krbtgt/" + realm, 

3815 upn=upn, 

3816 host=host, 

3817 **kwargs, 

3818 ) 

3819 cli.run() 

3820 cli.stop() 

3821 return cli.result 

3822 

3823 

3824def kpasswd( 

3825 upn, 

3826 targetupn=None, 

3827 ip=None, 

3828 password=None, 

3829 newpassword=None, 

3830 key=None, 

3831 ticket=None, 

3832 realm=None, 

3833 ssp=None, 

3834 setpassword=None, 

3835 timeout=3, 

3836 port=464, 

3837 debug=0, 

3838 **kwargs, 

3839): 

3840 """ 

3841 Change a password using RFC3244's Kerberos Set / Change Password. 

3842 

3843 :param upn: the UPN to use for authentication 

3844 :param targetupn: (optional) the UPN to change the password of. If not specified, 

3845 same as upn. 

3846 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for 

3847 _kerberos._tcp.dc._msdcs.domain.local). 

3848 :param key: (optional) pass the Key object. 

3849 :param ticket: (optional) a ticket to use. Either a TGT or ST for kadmin/changepw. 

3850 :param password: (optional) otherwise, pass the user's password 

3851 :param realm: (optional) the realm to use. Otherwise use the one from UPN. 

3852 :param setpassword: (optional) use "Set Password" mechanism. 

3853 :param ssp: (optional) a Kerberos SSP for the service kadmin/changepw@REALM. 

3854 If provided, you probably don't need anything else. Otherwise built. 

3855 """ 

3856 from scapy.layers.ldap import dclocator 

3857 

3858 if not realm: 

3859 _, realm = _parse_upn(upn) 

3860 spn = "kadmin/changepw@%s" % realm 

3861 if ip is None: 

3862 ip = dclocator( 

3863 realm, 

3864 timeout=timeout, 

3865 # Use connect mode instead of ldap for compatibility 

3866 # with MIT kerberos servers 

3867 mode="connect", 

3868 port=port, 

3869 debug=debug, 

3870 ).ip 

3871 if ssp is None and ticket is not None: 

3872 tktspn = ticket.getSPN().split("/")[0] 

3873 assert tktspn in ["krbtgt", "kadmin"], "Unexpected ticket type ! %s" % tktspn 

3874 if tktspn == "krbtgt": 

3875 log_runtime.info( 

3876 "Using 'Set Password' mode. This only works with admin privileges." 

3877 ) 

3878 setpassword = True 

3879 resp = krb_tgs_req( 

3880 upn=upn, 

3881 spn=spn, 

3882 ticket=ticket, 

3883 sessionkey=key, 

3884 ip=ip, 

3885 debug=debug, 

3886 ) 

3887 if resp is None: 

3888 return 

3889 ticket = resp.tgsrep.ticket 

3890 key = resp.sessionkey 

3891 if setpassword is None: 

3892 setpassword = bool(targetupn) 

3893 elif setpassword and targetupn is None: 

3894 targetupn = upn 

3895 assert setpassword or not targetupn, "Cannot use targetupn in changepassword mode !" 

3896 # Get a ticket for kadmin/changepw 

3897 if ssp is None: 

3898 if ticket is None: 

3899 # Get a ticket for kadmin/changepw through AS-REQ 

3900 resp = krb_as_req( 

3901 upn=upn, 

3902 spn=spn, 

3903 key=key, 

3904 ip=ip, 

3905 password=password, 

3906 debug=debug, 

3907 ) 

3908 if resp is None: 

3909 return 

3910 ticket = resp.asrep.ticket 

3911 key = resp.sessionkey 

3912 ssp = KerberosSSP( 

3913 UPN=upn, 

3914 SPN=spn, 

3915 ST=ticket, 

3916 KEY=key, 

3917 DC_IP=ip, 

3918 debug=debug, 

3919 **kwargs, 

3920 ) 

3921 Context, tok, negResult = ssp.GSS_Init_sec_context( 

3922 None, 

3923 req_flags=0, # No GSS_C_MUTUAL_FLAG 

3924 ) 

3925 if negResult != GSS_S_CONTINUE_NEEDED: 

3926 warning("SSP failed on initial GSS_Init_sec_context !") 

3927 if tok: 

3928 tok.show() 

3929 return 

3930 apreq = tok.innerToken.root 

3931 # Connect 

3932 sock = socket.socket() 

3933 sock.settimeout(timeout) 

3934 sock.connect((ip, port)) 

3935 sock = StreamSocket(sock, KpasswdTCPHeader) 

3936 # Do KPASSWD request 

3937 if newpassword is None: 

3938 try: 

3939 from prompt_toolkit import prompt 

3940 

3941 newpassword = prompt("Enter NEW password: ", is_password=True) 

3942 except ImportError: 

3943 newpassword = input("Enter NEW password: ") 

3944 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

3945 krbpriv.encPart.encrypt( 

3946 Context.KrbSessionKey, 

3947 EncKrbPrivPart( 

3948 sAddress=HostAddress( 

3949 addrType=ASN1_INTEGER(2), # IPv4 

3950 address=ASN1_STRING(b"\xc0\xa8\x00e"), 

3951 ), 

3952 userData=ASN1_STRING( 

3953 bytes( 

3954 ChangePasswdData( 

3955 newpasswd=newpassword, 

3956 targname=PrincipalName.fromUPN(targetupn), 

3957 targrealm=realm, 

3958 ) 

3959 ) 

3960 if setpassword 

3961 else newpassword 

3962 ), 

3963 timestamp=None, 

3964 usec=None, 

3965 seqNumber=Context.SendSeqNum, 

3966 ), 

3967 ) 

3968 resp = sock.sr1( 

3969 KpasswdTCPHeader() 

3970 / KPASSWD_REQ( 

3971 pvno=0xFF80 if setpassword else 1, 

3972 apreq=apreq, 

3973 krbpriv=krbpriv, 

3974 ), 

3975 timeout=timeout, 

3976 verbose=0, 

3977 ) 

3978 # Verify KPASSWD response 

3979 if not resp: 

3980 raise TimeoutError("KPASSWD_REQ timed out !") 

3981 if KPASSWD_REP not in resp: 

3982 resp.show() 

3983 raise ValueError("Invalid response to KPASSWD_REQ !") 

3984 Context, tok, negResult = ssp.GSS_Init_sec_context(Context, resp.aprep) 

3985 if negResult != GSS_S_COMPLETE: 

3986 warning("SSP failed on subsequent GSS_Init_sec_context !") 

3987 if tok: 

3988 tok.show() 

3989 return 

3990 # Parse answer KRB_PRIV 

3991 krbanswer = resp.krbpriv.encPart.decrypt(Context.KrbSessionKey) 

3992 userRep = KPasswdRepData(krbanswer.userData.val) 

3993 if userRep.resultCode != 0: 

3994 warning(userRep.sprintf("KPASSWD failed !")) 

3995 userRep.show() 

3996 return 

3997 print(userRep.sprintf("%resultCode%")) 

3998 

3999 

4000# SSP 

4001 

4002 

4003class KerberosSSP(SSP): 

4004 """ 

4005 The KerberosSSP 

4006 

4007 Client settings: 

4008 

4009 :param ST: the service ticket to use for access. 

4010 If not provided, will be retrieved 

4011 :param SPN: the SPN of the service to use 

4012 :param UPN: The client UPN 

4013 :param DC_IP: (optional) is ST+KEY are not provided, will need to contact 

4014 the KDC at this IP. If not provided, will perform dc locator. 

4015 :param TGT: (optional) pass a TGT to use to get the ST. 

4016 :param KEY: the session key associated with the ST if it is provided, 

4017 OR the session key associated with the TGT 

4018 OR the kerberos key associated with the UPN 

4019 :param PASSWORD: (optional) if a UPN is provided and not a KEY, this is the 

4020 password of the UPN. 

4021 :param U2U: (optional) use U2U when requesting the ST. 

4022 

4023 Server settings: 

4024 

4025 :param SPN: the SPN of the service to use. 

4026 :param KEY: the kerberos key to use to decrypt the AP-req 

4027 :param UPN: (optional) the UPN, if used in U2U mode. 

4028 :param TGT: (optional) pass a TGT to use for U2U. 

4029 :param DC_IP: (optional) if TGT is not provided, request one on the KDC at 

4030 this IP using using the KEY when using U2U. 

4031 """ 

4032 

4033 oid = "1.2.840.113554.1.2.2" 

4034 auth_type = 0x10 

4035 

4036 class STATE(SSP.STATE): 

4037 INIT = 1 

4038 CLI_SENT_TGTREQ = 2 

4039 CLI_SENT_APREQ = 3 

4040 CLI_RCVD_APREP = 4 

4041 SRV_SENT_APREP = 5 

4042 

4043 class CONTEXT(SSP.CONTEXT): 

4044 __slots__ = [ 

4045 "SessionKey", 

4046 "ServerHostname", 

4047 "U2U", 

4048 "KrbSessionKey", # raw Key object 

4049 "STSessionKey", # raw ST Key object (for DCE_STYLE) 

4050 "SeqNum", # for AP 

4051 "SendSeqNum", # for MIC 

4052 "RecvSeqNum", # for MIC 

4053 "IsAcceptor", 

4054 "SendSealKeyUsage", 

4055 "SendSignKeyUsage", 

4056 "RecvSealKeyUsage", 

4057 "RecvSignKeyUsage", 

4058 # server-only 

4059 "UPN", 

4060 "PAC", 

4061 ] 

4062 

4063 def __init__(self, IsAcceptor, req_flags=None): 

4064 self.state = KerberosSSP.STATE.INIT 

4065 self.SessionKey = None 

4066 self.ServerHostname = None 

4067 self.U2U = False 

4068 self.SendSeqNum = 0 

4069 self.RecvSeqNum = 0 

4070 self.KrbSessionKey = None 

4071 self.STSessionKey = None 

4072 self.IsAcceptor = IsAcceptor 

4073 self.UPN = None 

4074 self.PAC = None 

4075 # [RFC 4121] sect 2 

4076 if IsAcceptor: 

4077 self.SendSealKeyUsage = 22 

4078 self.SendSignKeyUsage = 23 

4079 self.RecvSealKeyUsage = 24 

4080 self.RecvSignKeyUsage = 25 

4081 else: 

4082 self.SendSealKeyUsage = 24 

4083 self.SendSignKeyUsage = 25 

4084 self.RecvSealKeyUsage = 22 

4085 self.RecvSignKeyUsage = 23 

4086 super(KerberosSSP.CONTEXT, self).__init__(req_flags=req_flags) 

4087 

4088 def clifailure(self): 

4089 self.__init__(self.IsAcceptor, req_flags=self.flags) 

4090 

4091 def __repr__(self): 

4092 if self.U2U: 

4093 return "KerberosSSP-U2U" 

4094 return "KerberosSSP" 

4095 

4096 def __init__( 

4097 self, 

4098 ST=None, 

4099 UPN=None, 

4100 PASSWORD=None, 

4101 U2U=False, 

4102 KEY=None, 

4103 SPN=None, 

4104 TGT=None, 

4105 DC_IP=None, 

4106 SKEY_TYPE=None, 

4107 debug=0, 

4108 **kwargs, 

4109 ): 

4110 self.ST = ST 

4111 self.UPN = UPN 

4112 self.KEY = KEY 

4113 self.SPN = SPN 

4114 self.TGT = TGT 

4115 self.PASSWORD = PASSWORD 

4116 self.U2U = U2U 

4117 self.DC_IP = DC_IP 

4118 self.debug = debug 

4119 if SKEY_TYPE is None: 

4120 from scapy.libs.rfc3961 import EncryptionType 

4121 

4122 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

4123 self.SKEY_TYPE = SKEY_TYPE 

4124 super(KerberosSSP, self).__init__(**kwargs) 

4125 

4126 def GSS_GetMICEx(self, Context, msgs, qop_req=0): 

4127 """ 

4128 [MS-KILE] sect 3.4.5.6 

4129 

4130 - AES: RFC4121 sect 4.2.6.1 

4131 """ 

4132 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4133 # Concatenate the ToSign 

4134 ToSign = b"".join(x.data for x in msgs if x.sign) 

4135 sig = KRB_InnerToken( 

4136 TOK_ID=b"\x04\x04", 

4137 root=KRB_GSS_MIC( 

4138 Flags="AcceptorSubkey" 

4139 + ("+SentByAcceptor" if Context.IsAcceptor else ""), 

4140 SND_SEQ=Context.SendSeqNum, 

4141 ), 

4142 ) 

4143 ToSign += bytes(sig)[:16] 

4144 sig.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4145 keyusage=Context.SendSignKeyUsage, 

4146 text=ToSign, 

4147 ) 

4148 else: 

4149 raise NotImplementedError 

4150 Context.SendSeqNum += 1 

4151 return sig 

4152 

4153 def GSS_VerifyMICEx(self, Context, msgs, signature): 

4154 """ 

4155 [MS-KILE] sect 3.4.5.7 

4156 

4157 - AES: RFC4121 sect 4.2.6.1 

4158 """ 

4159 Context.RecvSeqNum = signature.root.SND_SEQ 

4160 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4161 # Concatenate the ToSign 

4162 ToSign = b"".join(x.data for x in msgs if x.sign) 

4163 ToSign += bytes(signature)[:16] 

4164 sig = Context.KrbSessionKey.make_checksum( 

4165 keyusage=Context.RecvSignKeyUsage, 

4166 text=ToSign, 

4167 ) 

4168 else: 

4169 raise NotImplementedError 

4170 if sig != signature.root.SGN_CKSUM: 

4171 raise ValueError("ERROR: Checksums don't match") 

4172 

4173 def GSS_WrapEx(self, Context, msgs, qop_req=0): 

4174 """ 

4175 [MS-KILE] sect 3.4.5.4 

4176 

4177 - AES: RFC4121 sect 4.2.6.2 and [MS-KILE] sect 3.4.5.4.1 

4178 - HMAC-RC4: RFC4757 sect 7.3 and [MS-KILE] sect 3.4.5.4.1 

4179 """ 

4180 # Is confidentiality in use? 

4181 confidentiality = (Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG) and any( 

4182 x.conf_req_flag for x in msgs 

4183 ) 

4184 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4185 # Build token 

4186 tok = KRB_InnerToken( 

4187 TOK_ID=b"\x05\x04", 

4188 root=KRB_GSS_Wrap( 

4189 Flags="AcceptorSubkey" 

4190 + ("+SentByAcceptor" if Context.IsAcceptor else "") 

4191 + ("+Sealed" if confidentiality else ""), 

4192 SND_SEQ=Context.SendSeqNum, 

4193 RRC=0, 

4194 ), 

4195 ) 

4196 Context.SendSeqNum += 1 

4197 # Real separation starts now: RFC4121 sect 4.2.4 

4198 if confidentiality: 

4199 # Confidentiality is requested (see RFC4121 sect 4.3) 

4200 # {"header" | encrypt(plaintext-data | filler | "header")} 

4201 # 0. Roll confounder 

4202 Confounder = os.urandom(Context.KrbSessionKey.ep.blocksize) 

4203 # 1. Concatenate the data to be encrypted 

4204 Data = b"".join(x.data for x in msgs if x.conf_req_flag) 

4205 DataLen = len(Data) 

4206 # 2. Add filler 

4207 # [MS-KILE] sect 3.4.5.4.1 - "For AES-SHA1 ciphers, the EC must not 

4208 # be zero" 

4209 tok.root.EC = ((-DataLen) % Context.KrbSessionKey.ep.blocksize) or 16 

4210 Filler = b"\x00" * tok.root.EC 

4211 Data += Filler 

4212 # 3. Add first 16 octets of the Wrap token "header" 

4213 PlainHeader = bytes(tok)[:16] 

4214 Data += PlainHeader 

4215 # 4. Build 'ToSign', exclusively used for checksum 

4216 ToSign = Confounder 

4217 ToSign += b"".join(x.data for x in msgs if x.sign) 

4218 ToSign += Filler 

4219 ToSign += PlainHeader 

4220 # 5. Finalize token for signing 

4221 # "The RRC field is [...] 28 if encryption is requested." 

4222 tok.root.RRC = 28 

4223 # 6. encrypt() is the encryption operation (which provides for 

4224 # integrity protection) 

4225 Data = Context.KrbSessionKey.encrypt( 

4226 keyusage=Context.SendSealKeyUsage, 

4227 plaintext=Data, 

4228 confounder=Confounder, 

4229 signtext=ToSign, 

4230 ) 

4231 # 7. Rotate 

4232 Data = strrot(Data, tok.root.RRC + tok.root.EC) 

4233 # 8. Split (token and encrypted messages) 

4234 toklen = len(Data) - DataLen 

4235 tok.root.Data = Data[:toklen] 

4236 offset = toklen 

4237 for msg in msgs: 

4238 msglen = len(msg.data) 

4239 if msg.conf_req_flag: 

4240 msg.data = Data[offset : offset + msglen] 

4241 offset += msglen 

4242 return msgs, tok 

4243 else: 

4244 # No confidentiality is requested 

4245 # {"header" | plaintext-data | get_mic(plaintext-data | "header")} 

4246 # 0. Concatenate the data 

4247 Data = b"".join(x.data for x in msgs if x.sign) 

4248 DataLen = len(Data) 

4249 # 1. Add first 16 octets of the Wrap token "header" 

4250 ToSign = Data 

4251 ToSign += bytes(tok)[:16] 

4252 # 2. get_mic() is the checksum operation for the required 

4253 # checksum mechanism 

4254 Mic = Context.KrbSessionKey.make_checksum( 

4255 keyusage=Context.SendSealKeyUsage, 

4256 text=ToSign, 

4257 ) 

4258 # In Wrap tokens without confidentiality, the EC field SHALL be used 

4259 # to encode the number of octets in the trailing checksum 

4260 tok.root.EC = 12 # len(tok.root.Data) == 12 for AES 

4261 # "The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption 

4262 # is requested" 

4263 tok.root.RRC = 12 

4264 # 3. Concat and pack 

4265 for msg in msgs: 

4266 if msg.sign: 

4267 msg.data = b"" 

4268 Data = Data + Mic 

4269 # 4. Rotate 

4270 tok.root.Data = strrot(Data, tok.root.RRC) 

4271 return msgs, tok 

4272 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

4273 from scapy.libs.rfc3961 import ( 

4274 Cipher, 

4275 Hmac_MD5, 

4276 _rfc1964pad, 

4277 decrepit_algorithms, 

4278 ) 

4279 

4280 # Build token 

4281 seq = struct.pack(">I", Context.SendSeqNum) 

4282 tok = KRB_InnerToken( 

4283 TOK_ID=b"\x02\x01", 

4284 root=KRB_GSS_Wrap_RFC1964( 

4285 SGN_ALG="HMAC", 

4286 SEAL_ALG="RC4" if confidentiality else "none", 

4287 SND_SEQ=seq 

4288 + ( 

4289 # See errata 

4290 b"\xff\xff\xff\xff" 

4291 if Context.IsAcceptor 

4292 else b"\x00\x00\x00\x00" 

4293 ), 

4294 ), 

4295 ) 

4296 Context.SendSeqNum += 1 

4297 # 0. Concatenate data 

4298 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

4299 ToEncrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

4300 Kss = Context.KrbSessionKey.key 

4301 # 1. Roll confounder 

4302 Confounder = os.urandom(8) 

4303 # 2. Compute the 'Kseq' key 

4304 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

4305 if Context.KrbSessionKey.etype == 24: # EXP 

4306 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4307 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4308 else: 

4309 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4310 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4311 # 3. Build SGN_CKSUM 

4312 tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4313 keyusage=13, # See errata 

4314 text=bytes(tok)[:8] + Confounder + ToSign, 

4315 )[:8] 

4316 # 4. Populate token + encrypt 

4317 if confidentiality: 

4318 # 'encrypt' is requested 

4319 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4320 tok.root.CONFOUNDER = rc4.update(Confounder) 

4321 Data = rc4.update(ToEncrypt) 

4322 # Split encrypted data 

4323 offset = 0 

4324 for msg in msgs: 

4325 msglen = len(msg.data) 

4326 if msg.conf_req_flag: 

4327 msg.data = Data[offset : offset + msglen] 

4328 offset += msglen 

4329 else: 

4330 # 'encrypt' is not requested 

4331 tok.root.CONFOUNDER = Confounder 

4332 # 5. Compute the 'Kseq' key 

4333 if Context.KrbSessionKey.etype == 24: # EXP 

4334 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4335 Kseq = Kseq[:7] + b"\xab" * 9 

4336 else: 

4337 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

4338 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

4339 # 6. Encrypt 'SND_SEQ' 

4340 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

4341 tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ) 

4342 # 7. Include 'InitialContextToken pseudo ASN.1 header' 

4343 tok = KRB_GSSAPI_Token( 

4344 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

4345 innerToken=tok, 

4346 ) 

4347 return msgs, tok 

4348 else: 

4349 raise NotImplementedError 

4350 

4351 def GSS_UnwrapEx(self, Context, msgs, signature): 

4352 """ 

4353 [MS-KILE] sect 3.4.5.5 

4354 

4355 - AES: RFC4121 sect 4.2.6.2 

4356 - HMAC-RC4: RFC4757 sect 7.3 

4357 """ 

4358 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4359 confidentiality = signature.root.Flags.Sealed 

4360 # Real separation starts now: RFC4121 sect 4.2.4 

4361 if confidentiality: 

4362 # 0. Concatenate the data 

4363 Data = signature.root.Data 

4364 Data += b"".join(x.data for x in msgs if x.conf_req_flag) 

4365 # 1. Un-Rotate 

4366 Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False) 

4367 

4368 # 2. Function to build 'ToSign', exclusively used for checksum 

4369 def MakeToSign(Confounder, DecText): 

4370 offset = 0 

4371 # 2.a Confounder 

4372 ToSign = Confounder 

4373 # 2.b Messages 

4374 for msg in msgs: 

4375 msglen = len(msg.data) 

4376 if msg.conf_req_flag: 

4377 ToSign += DecText[offset : offset + msglen] 

4378 offset += msglen 

4379 elif msg.sign: 

4380 ToSign += msg.data 

4381 # 2.c Filler & Padding 

4382 ToSign += DecText[offset:] 

4383 return ToSign 

4384 

4385 # 3. Decrypt 

4386 Data = Context.KrbSessionKey.decrypt( 

4387 keyusage=Context.RecvSealKeyUsage, 

4388 ciphertext=Data, 

4389 presignfunc=MakeToSign, 

4390 ) 

4391 # 4. Split 

4392 Data, f16header = ( 

4393 Data[:-16], 

4394 Data[-16:], 

4395 ) 

4396 # 5. Check header 

4397 hdr = signature.copy() 

4398 hdr.root.RRC = 0 

4399 if f16header != bytes(hdr)[:16]: 

4400 raise ValueError("ERROR: Headers don't match") 

4401 # 6. Split (and ignore filler) 

4402 offset = 0 

4403 for msg in msgs: 

4404 msglen = len(msg.data) 

4405 if msg.conf_req_flag: 

4406 msg.data = Data[offset : offset + msglen] 

4407 offset += msglen 

4408 # Case without msgs 

4409 if len(msgs) == 1 and not msgs[0].data: 

4410 msgs[0].data = Data 

4411 return msgs 

4412 else: 

4413 # No confidentiality is requested 

4414 # 0. Concatenate the data 

4415 Data = signature.root.Data 

4416 Data += b"".join(x.data for x in msgs if x.sign) 

4417 # 1. Un-Rotate 

4418 Data = strrot(Data, signature.root.RRC, right=False) 

4419 # 2. Split 

4420 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

4421 # "Both the EC field and the RRC field in 

4422 # the token header SHALL be filled with zeroes for the purpose of 

4423 # calculating the checksum." 

4424 ToSign = Data 

4425 hdr = signature.copy() 

4426 hdr.root.RRC = 0 

4427 hdr.root.EC = 0 

4428 # Concatenate the data 

4429 ToSign += bytes(hdr)[:16] 

4430 # 3. Calculate the signature 

4431 sig = Context.KrbSessionKey.make_checksum( 

4432 keyusage=Context.RecvSealKeyUsage, 

4433 text=ToSign, 

4434 ) 

4435 # 4. Compare 

4436 if sig != Mic: 

4437 raise ValueError("ERROR: Checksums don't match") 

4438 # Case without msgs 

4439 if len(msgs) == 1 and not msgs[0].data: 

4440 msgs[0].data = Data 

4441 return msgs 

4442 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

4443 from scapy.libs.rfc3961 import ( 

4444 Cipher, 

4445 Hmac_MD5, 

4446 _rfc1964pad, 

4447 decrepit_algorithms, 

4448 ) 

4449 

4450 # Drop wrapping 

4451 tok = signature.innerToken 

4452 

4453 # Detect confidentiality 

4454 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

4455 

4456 # 0. Concatenate data 

4457 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

4458 Kss = Context.KrbSessionKey.key 

4459 # 1. Compute the 'Kseq' key 

4460 if Context.KrbSessionKey.etype == 24: # EXP 

4461 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4462 Kseq = Kseq[:7] + b"\xab" * 9 

4463 else: 

4464 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

4465 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

4466 # 2. Decrypt 'SND_SEQ' 

4467 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

4468 seq = rc4.update(tok.root.SND_SEQ)[:4] 

4469 # 3. Compute the 'Kcrypt' key 

4470 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

4471 if Context.KrbSessionKey.etype == 24: # EXP 

4472 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4473 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4474 else: 

4475 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4476 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4477 # 4. Decrypt 

4478 if confidentiality: 

4479 # 'encrypt' was requested 

4480 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4481 Confounder = rc4.update(tok.root.CONFOUNDER) 

4482 Data = rc4.update(ToDecrypt) 

4483 # Split encrypted data 

4484 offset = 0 

4485 for msg in msgs: 

4486 msglen = len(msg.data) 

4487 if msg.conf_req_flag: 

4488 msg.data = Data[offset : offset + msglen] 

4489 offset += msglen 

4490 else: 

4491 # 'encrypt' was not requested 

4492 Confounder = tok.root.CONFOUNDER 

4493 # 5. Verify SGN_CKSUM 

4494 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

4495 Context.KrbSessionKey.verify_checksum( 

4496 keyusage=13, # See errata 

4497 text=bytes(tok)[:8] + Confounder + ToSign, 

4498 cksum=tok.root.SGN_CKSUM, 

4499 ) 

4500 return msgs 

4501 else: 

4502 raise NotImplementedError 

4503 

4504 def GSS_Init_sec_context( 

4505 self, 

4506 Context: CONTEXT, 

4507 token=None, 

4508 req_flags: Optional[GSS_C_FLAGS] = None, 

4509 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

4510 ): 

4511 if Context is None: 

4512 # New context 

4513 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

4514 

4515 from scapy.libs.rfc3961 import Key 

4516 

4517 if Context.state == self.STATE.INIT and self.U2U: 

4518 # U2U - Get TGT 

4519 Context.state = self.STATE.CLI_SENT_TGTREQ 

4520 return ( 

4521 Context, 

4522 KRB_GSSAPI_Token( 

4523 MechType="1.2.840.113554.1.2.2.3", # U2U 

4524 innerToken=KRB_InnerToken( 

4525 TOK_ID=b"\x04\x00", 

4526 root=KRB_TGT_REQ(), 

4527 ), 

4528 ), 

4529 GSS_S_CONTINUE_NEEDED, 

4530 ) 

4531 

4532 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

4533 if not self.UPN: 

4534 raise ValueError("Missing UPN attribute") 

4535 # Do we have a ST? 

4536 if self.ST is None: 

4537 # Client sends an AP-req 

4538 if not self.SPN: 

4539 raise ValueError("Missing SPN attribute") 

4540 additional_tickets = [] 

4541 if self.U2U: 

4542 try: 

4543 # GSSAPI / Kerberos 

4544 tgt_rep = token.root.innerToken.root 

4545 except AttributeError: 

4546 try: 

4547 # Kerberos 

4548 tgt_rep = token.innerToken.root 

4549 except AttributeError: 

4550 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4551 if not isinstance(tgt_rep, KRB_TGT_REP): 

4552 tgt_rep.show() 

4553 raise ValueError("KerberosSSP: Unexpected token !") 

4554 additional_tickets = [tgt_rep.ticket] 

4555 if self.TGT is not None: 

4556 if not self.KEY: 

4557 raise ValueError("Cannot use TGT without the KEY") 

4558 # Use TGT 

4559 res = krb_tgs_req( 

4560 upn=self.UPN, 

4561 spn=self.SPN, 

4562 ip=self.DC_IP, 

4563 sessionkey=self.KEY, 

4564 ticket=self.TGT, 

4565 additional_tickets=additional_tickets, 

4566 u2u=self.U2U, 

4567 debug=self.debug, 

4568 ) 

4569 else: 

4570 # Ask for TGT then ST 

4571 res = krb_as_and_tgs( 

4572 upn=self.UPN, 

4573 spn=self.SPN, 

4574 ip=self.DC_IP, 

4575 key=self.KEY, 

4576 password=self.PASSWORD, 

4577 additional_tickets=additional_tickets, 

4578 u2u=self.U2U, 

4579 debug=self.debug, 

4580 ) 

4581 if not res: 

4582 # Failed to retrieve the ticket 

4583 return Context, None, GSS_S_FAILURE 

4584 self.ST, self.KEY = res.tgsrep.ticket, res.sessionkey 

4585 elif not self.KEY: 

4586 raise ValueError("Must provide KEY with ST") 

4587 Context.STSessionKey = self.KEY 

4588 

4589 # Save ServerHostname 

4590 if len(self.ST.sname.nameString) == 2: 

4591 Context.ServerHostname = self.ST.sname.nameString[1].val.decode() 

4592 

4593 # Build the KRB-AP 

4594 apOptions = ASN1_BIT_STRING("000") 

4595 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

4596 apOptions.set(2, "1") # mutual-required 

4597 if self.U2U: 

4598 apOptions.set(1, "1") # use-session-key 

4599 Context.U2U = True 

4600 ap_req = KRB_AP_REQ( 

4601 apOptions=apOptions, 

4602 ticket=self.ST, 

4603 authenticator=EncryptedData(), 

4604 ) 

4605 

4606 # Get the current time 

4607 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

4608 # Pick a random session key 

4609 Context.KrbSessionKey = Key.new_random_key( 

4610 self.SKEY_TYPE, 

4611 ) 

4612 

4613 # We use a random SendSeqNum 

4614 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

4615 

4616 # Get the realm of the client 

4617 _, crealm = _parse_upn(self.UPN) 

4618 

4619 # Build and encrypt the full KRB_Authenticator 

4620 ap_req.authenticator.encrypt( 

4621 Context.STSessionKey, 

4622 KRB_Authenticator( 

4623 crealm=crealm, 

4624 cname=PrincipalName.fromUPN(self.UPN), 

4625 # RFC 4121 checksum 

4626 cksum=Checksum( 

4627 cksumtype="KRB-AUTHENTICATOR", 

4628 checksum=KRB_AuthenticatorChecksum( 

4629 # RFC 4121 sect 4.1.1.2 

4630 # "The Bnd field contains the MD5 hash of channel bindings" 

4631 Bnd=( 

4632 chan_bindings.digestMD5() 

4633 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4634 else (b"\x00" * 16) 

4635 ), 

4636 Flags=int(Context.flags), 

4637 ), 

4638 ), 

4639 ctime=ASN1_GENERALIZED_TIME(now_time), 

4640 cusec=ASN1_INTEGER(0), 

4641 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

4642 seqNumber=Context.SendSeqNum, 

4643 encAuthorizationData=AuthorizationData( 

4644 seq=[ 

4645 AuthorizationDataItem( 

4646 adType="AD-IF-RELEVANT", 

4647 adData=AuthorizationData( 

4648 seq=[ 

4649 AuthorizationDataItem( 

4650 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

4651 adData=KERB_AD_RESTRICTION_ENTRY( 

4652 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

4653 MachineID=bytes(RandBin(32)) 

4654 ) 

4655 ), 

4656 ), 

4657 # This isn't documented, but sent on Windows :/ 

4658 AuthorizationDataItem( 

4659 adType="KERB-LOCAL", 

4660 adData=b"\x00" * 16, 

4661 ), 

4662 ] 

4663 + ( 

4664 # Channel bindings 

4665 [ 

4666 AuthorizationDataItem( 

4667 adType="AD-AUTH-DATA-AP-OPTIONS", 

4668 adData=KERB_AUTH_DATA_AP_OPTIONS( 

4669 apOptions="KERB_AP_OPTIONS_CBT" 

4670 ), 

4671 ) 

4672 ] 

4673 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4674 else [] 

4675 ) 

4676 ), 

4677 ) 

4678 ] 

4679 ), 

4680 ), 

4681 ) 

4682 Context.state = self.STATE.CLI_SENT_APREQ 

4683 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4684 # Raw kerberos DCE-STYLE 

4685 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

4686 else: 

4687 # Kerberos wrapper 

4688 return ( 

4689 Context, 

4690 KRB_GSSAPI_Token( 

4691 innerToken=KRB_InnerToken( 

4692 root=ap_req, 

4693 ) 

4694 ), 

4695 GSS_S_CONTINUE_NEEDED, 

4696 ) 

4697 

4698 elif Context.state == self.STATE.CLI_SENT_APREQ: 

4699 if isinstance(token, KRB_AP_REP): 

4700 # Raw AP_REP was passed 

4701 ap_rep = token 

4702 else: 

4703 try: 

4704 # GSSAPI / Kerberos 

4705 ap_rep = token.root.innerToken.root 

4706 except AttributeError: 

4707 try: 

4708 # Kerberos 

4709 ap_rep = token.innerToken.root 

4710 except AttributeError: 

4711 try: 

4712 # Raw kerberos DCE-STYLE 

4713 ap_rep = token.root 

4714 except AttributeError: 

4715 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4716 if not isinstance(ap_rep, KRB_AP_REP): 

4717 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4718 # Retrieve SessionKey 

4719 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

4720 if repPart.subkey is not None: 

4721 Context.SessionKey = repPart.subkey.keyvalue.val 

4722 Context.KrbSessionKey = repPart.subkey.toKey() 

4723 # OK ! 

4724 Context.state = self.STATE.CLI_RCVD_APREP 

4725 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4726 # [MS-KILE] sect 3.4.5.1 

4727 # The client MUST generate an additional AP exchange reply message 

4728 # exactly as the server would as the final message to send to the 

4729 # server. 

4730 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

4731 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

4732 cli_ap_rep.encPart.encrypt( 

4733 Context.STSessionKey, 

4734 EncAPRepPart( 

4735 ctime=ASN1_GENERALIZED_TIME(now_time), 

4736 seqNumber=repPart.seqNumber, 

4737 subkey=None, 

4738 ), 

4739 ) 

4740 return Context, cli_ap_rep, GSS_S_COMPLETE 

4741 return Context, None, GSS_S_COMPLETE 

4742 elif ( 

4743 Context.state == self.STATE.CLI_RCVD_APREP 

4744 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

4745 ): 

4746 # DCE_STYLE with SPNEGOSSP 

4747 return Context, None, GSS_S_COMPLETE 

4748 else: 

4749 raise ValueError("KerberosSSP: Unknown state") 

4750 

4751 def GSS_Accept_sec_context( 

4752 self, 

4753 Context: CONTEXT, 

4754 token=None, 

4755 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

4756 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

4757 ): 

4758 if Context is None: 

4759 # New context 

4760 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

4761 

4762 from scapy.libs.rfc3961 import Key 

4763 import scapy.layers.msrpce.mspac # noqa: F401 

4764 

4765 if Context.state == self.STATE.INIT: 

4766 if self.UPN and self.SPN: 

4767 raise ValueError("Cannot use SPN and UPN at the same time !") 

4768 if self.SPN and self.TGT: 

4769 raise ValueError("Cannot use TGT with SPN.") 

4770 if self.UPN and not self.TGT: 

4771 # UPN is provided: use U2U 

4772 res = krb_as_req( 

4773 self.UPN, 

4774 self.DC_IP, 

4775 key=self.KEY, 

4776 password=self.PASSWORD, 

4777 ) 

4778 self.TGT, self.KEY = res.asrep.ticket, res.sessionkey 

4779 

4780 # Server receives AP-req, sends AP-rep 

4781 if isinstance(token, KRB_AP_REQ): 

4782 # Raw AP_REQ was passed 

4783 ap_req = token 

4784 else: 

4785 try: 

4786 # GSSAPI/Kerberos 

4787 ap_req = token.root.innerToken.root 

4788 except AttributeError: 

4789 try: 

4790 # Kerberos 

4791 ap_req = token.innerToken.root 

4792 except AttributeError: 

4793 try: 

4794 # Raw kerberos 

4795 ap_req = token.root 

4796 except AttributeError: 

4797 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4798 

4799 if isinstance(ap_req, KRB_TGT_REQ): 

4800 # Special U2U case 

4801 Context.U2U = True 

4802 return ( 

4803 None, 

4804 KRB_GSSAPI_Token( 

4805 MechType="1.2.840.113554.1.2.2.3", # U2U 

4806 innerToken=KRB_InnerToken( 

4807 TOK_ID=b"\x04\x01", 

4808 root=KRB_TGT_REP( 

4809 ticket=self.TGT, 

4810 ), 

4811 ), 

4812 ), 

4813 GSS_S_CONTINUE_NEEDED, 

4814 ) 

4815 elif not isinstance(ap_req, KRB_AP_REQ): 

4816 ap_req.show() 

4817 raise ValueError("Unexpected type in KerberosSSP") 

4818 if not self.KEY: 

4819 raise ValueError("Missing KEY attribute") 

4820 

4821 # If using a UPN, require U2U 

4822 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

4823 # Required but not provided. Return an error 

4824 Context.U2U = True 

4825 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

4826 err = KRB_GSSAPI_Token( 

4827 innerToken=KRB_InnerToken( 

4828 TOK_ID=b"\x03\x00", 

4829 root=KRB_ERROR( 

4830 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

4831 stime=ASN1_GENERALIZED_TIME(now_time), 

4832 realm=ap_req.ticket.realm, 

4833 sname=ap_req.ticket.sname, 

4834 eData=KRB_TGT_REP( 

4835 ticket=self.TGT, 

4836 ), 

4837 ), 

4838 ) 

4839 ) 

4840 return Context, err, GSS_S_CONTINUE_NEEDED 

4841 

4842 # Validate the 'serverName' of the ticket. 

4843 sname = ap_req.ticket.getSPN() 

4844 our_sname = self.SPN or self.UPN 

4845 if not _spn_are_equal(our_sname, sname): 

4846 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

4847 err = KRB_GSSAPI_Token( 

4848 innerToken=KRB_InnerToken( 

4849 TOK_ID=b"\x03\x00", 

4850 root=KRB_ERROR( 

4851 errorCode="KRB_AP_ERR_BADMATCH", 

4852 stime=ASN1_GENERALIZED_TIME(now_time), 

4853 realm=ap_req.ticket.realm, 

4854 sname=ap_req.ticket.sname, 

4855 eData=None, 

4856 ), 

4857 ) 

4858 ) 

4859 return Context, err, GSS_S_BAD_MECH 

4860 

4861 # Decrypt the ticket 

4862 try: 

4863 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

4864 except ValueError as ex: 

4865 warning("KerberosSSP: %s (bad KEY?)" % ex) 

4866 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

4867 err = KRB_GSSAPI_Token( 

4868 innerToken=KRB_InnerToken( 

4869 TOK_ID=b"\x03\x00", 

4870 root=KRB_ERROR( 

4871 errorCode="KRB_AP_ERR_MODIFIED", 

4872 stime=ASN1_GENERALIZED_TIME(now_time), 

4873 realm=ap_req.ticket.realm, 

4874 sname=ap_req.ticket.sname, 

4875 eData=None, 

4876 ), 

4877 ) 

4878 ) 

4879 return Context, err, GSS_S_DEFECTIVE_TOKEN 

4880 

4881 # Store information about the user in the Context 

4882 if tkt.authorizationData and tkt.authorizationData.seq: 

4883 # Get AD-IF-RELEVANT 

4884 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

4885 if adIfRelevant: 

4886 # Get AD-WIN2K-PAC 

4887 Context.PAC = adIfRelevant.getAuthData(0x80) 

4888 

4889 # Get AP-REQ session key 

4890 Context.STSessionKey = tkt.key.toKey() 

4891 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

4892 

4893 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

4894 subkey = None 

4895 if ap_req.apOptions.val[2] == "1": # mutual-required 

4896 appkey = Key.new_random_key( 

4897 self.SKEY_TYPE, 

4898 ) 

4899 Context.KrbSessionKey = appkey 

4900 Context.SessionKey = appkey.key 

4901 subkey = EncryptionKey.fromKey(appkey) 

4902 else: 

4903 Context.KrbSessionKey = self.KEY 

4904 Context.SessionKey = self.KEY.key 

4905 

4906 # Eventually process the "checksum" 

4907 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

4908 # KRB-Authenticator 

4909 authcksum = authenticator.cksum.checksum 

4910 Context.flags = authcksum.Flags 

4911 # Check channel bindings 

4912 if ( 

4913 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4914 and chan_bindings.digestMD5() != authcksum.Bnd 

4915 and not ( 

4916 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

4917 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

4918 ) 

4919 ): 

4920 # Channel binding checks failed. 

4921 return Context, None, GSS_S_BAD_BINDINGS 

4922 elif ( 

4923 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4924 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

4925 ): 

4926 # Uhoh, we required channel bindings 

4927 return Context, None, GSS_S_BAD_BINDINGS 

4928 

4929 # Build response (RFC4120 sect 3.2.4) 

4930 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

4931 ap_rep.encPart.encrypt( 

4932 Context.STSessionKey, 

4933 EncAPRepPart( 

4934 ctime=authenticator.ctime, 

4935 cusec=authenticator.cusec, 

4936 seqNumber=None, 

4937 subkey=subkey, 

4938 ), 

4939 ) 

4940 Context.state = self.STATE.SRV_SENT_APREP 

4941 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4942 # [MS-KILE] sect 3.4.5.1 

4943 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

4944 return Context, ap_rep, GSS_S_COMPLETE # success 

4945 elif ( 

4946 Context.state == self.STATE.SRV_SENT_APREP 

4947 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

4948 ): 

4949 # [MS-KILE] sect 3.4.5.1 

4950 # The server MUST receive the additional AP exchange reply message and 

4951 # verify that the message is constructed correctly. 

4952 if not token: 

4953 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4954 # Server receives AP-req, sends AP-rep 

4955 if isinstance(token, KRB_AP_REP): 

4956 # Raw AP_REP was passed 

4957 ap_rep = token 

4958 else: 

4959 try: 

4960 # GSSAPI/Kerberos 

4961 ap_rep = token.root.innerToken.root 

4962 except AttributeError: 

4963 try: 

4964 # Raw Kerberos 

4965 ap_rep = token.root 

4966 except AttributeError: 

4967 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4968 # Decrypt the AP-REP 

4969 try: 

4970 ap_rep.encPart.decrypt(Context.STSessionKey) 

4971 except ValueError as ex: 

4972 warning("KerberosSSP: %s (bad KEY?)" % ex) 

4973 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4974 return Context, None, GSS_S_COMPLETE # success 

4975 else: 

4976 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

4977 

4978 def GSS_Passive(self, Context: CONTEXT, token=None): 

4979 if Context is None: 

4980 Context = self.CONTEXT(True) 

4981 Context.passive = True 

4982 

4983 if Context.state == self.STATE.INIT: 

4984 Context, _, status = self.GSS_Accept_sec_context(Context, token) 

4985 Context.state = self.STATE.CLI_SENT_APREQ 

4986 return Context, GSS_S_CONTINUE_NEEDED 

4987 elif Context.state == self.STATE.CLI_SENT_APREQ: 

4988 Context, _, status = self.GSS_Init_sec_context(Context, token) 

4989 return Context, status 

4990 

4991 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

4992 if Context.IsAcceptor is not IsAcceptor: 

4993 return 

4994 # Swap everything 

4995 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

4996 Context.RecvSealKeyUsage, 

4997 Context.SendSealKeyUsage, 

4998 ) 

4999 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

5000 Context.RecvSignKeyUsage, 

5001 Context.SendSignKeyUsage, 

5002 ) 

5003 Context.IsAcceptor = not Context.IsAcceptor 

5004 

5005 def MaximumSignatureLength(self, Context: CONTEXT): 

5006 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

5007 # TODO: support DES 

5008 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5009 return 76 

5010 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

5011 return 45 

5012 else: 

5013 raise NotImplementedError 

5014 else: 

5015 return 28 

5016 

5017 def canMechListMIC(self, Context: CONTEXT): 

5018 return bool(Context.KrbSessionKey)