4646 >>> enc.decrypt(k)
4747"""
4848
49- from collections import namedtuple
49+ from collections import namedtuple , deque
5050from datetime import datetime , timedelta , timezone
5151from enum import IntEnum
5252
117117 XStrField ,
118118)
119119from scapy .packet import Packet , bind_bottom_up , bind_top_down , bind_layers
120- from scapy .supersocket import StreamSocket
120+ from scapy .supersocket import StreamSocket , SuperSocket
121121from scapy .utils import strrot , strxor
122122from scapy .volatile import GeneralizedTime , RandNum , RandBin
123123
@@ -2523,14 +2523,77 @@ class KDC_PROXY_MESSAGE(ASN1_Packet):
25232523 ASN1F_optional (
25242524 ASN1F_FLAGS (
25252525 "dclocatorHint" ,
2526- "" ,
2526+ None ,
25272527 FlagsField ("" , 0 , - 32 , _NV_VERSION ).names ,
25282528 explicit_tag = 0xA2 ,
25292529 )
25302530 ),
25312531 )
25322532
25332533
2534+ class KdcProxySocket (SuperSocket ):
2535+ """
2536+ This is a wrapper of a HTTP_Client that does KKDCP proxying,
2537+ disguised as a SuperSocket to be compatible with the rest of the KerberosClient.
2538+ """
2539+
2540+ def __init__ (
2541+ self ,
2542+ url ,
2543+ targetDomain ,
2544+ dclocatorHint = None ,
2545+ no_check_certificate = False ,
2546+ ** kwargs ,
2547+ ):
2548+ self .url = url
2549+ self .targetDomain = targetDomain
2550+ self .dclocatorHint = dclocatorHint
2551+ self .no_check_certificate = no_check_certificate
2552+ self .queue = deque ()
2553+ super (KdcProxySocket , self ).__init__ (** kwargs )
2554+
2555+ def recv (self , x = None ):
2556+ return self .queue .popleft ()
2557+
2558+ def send (self , x , ** kwargs ):
2559+ from scapy .layers .http import HTTP_Client
2560+
2561+ cli = HTTP_Client (no_check_certificate = self .no_check_certificate )
2562+ try :
2563+ # sr it via the web client
2564+ resp = cli .request (
2565+ self .url ,
2566+ Method = "POST" ,
2567+ data = bytes (
2568+ # Wrap request in KDC_PROXY_MESSAGE
2569+ KDC_PROXY_MESSAGE (
2570+ kerbMessage = bytes (x ),
2571+ targetDomain = ASN1_GENERAL_STRING (self .targetDomain .encode ()),
2572+ # dclocatorHint is optional
2573+ dclocatorHint = self .dclocatorHint ,
2574+ )
2575+ ),
2576+ http_headers = {
2577+ "Cache-Control" : "no-cache" ,
2578+ "Pragma" : "no-cache" ,
2579+ "User-Agent" : "kerberos/1.0" ,
2580+ },
2581+ )
2582+ if resp and conf .raw_layer in resp :
2583+ # Parse the payload
2584+ resp = KDC_PROXY_MESSAGE (resp .load ).kerbMessage
2585+ # We have an answer, queue it.
2586+ self .queue .append (resp )
2587+ else :
2588+ raise EOFError
2589+ finally :
2590+ cli .close ()
2591+
2592+ @staticmethod
2593+ def select (sockets , remain = None ):
2594+ return [x for x in sockets if isinstance (x , KdcProxySocket ) and x .queue ]
2595+
2596+
25342597# Util functions
25352598
25362599
@@ -2558,6 +2621,8 @@ def __init__(
25582621 u2u = False ,
25592622 for_user = None ,
25602623 s4u2proxy = False ,
2624+ kdc_proxy = None ,
2625+ kdc_proxy_no_check_certificate = False ,
25612626 etypes = None ,
25622627 key = None ,
25632628 port = 88 ,
@@ -2590,7 +2655,7 @@ def __init__(
25902655 if not ticket :
25912656 raise ValueError ("Invalid ticket" )
25922657
2593- if not ip :
2658+ if not ip and not kdc_proxy :
25942659 # No KDC IP provided. Find it by querying the DNS
25952660 ip = dclocator (
25962661 realm ,
@@ -2630,7 +2695,8 @@ def __init__(
26302695 self ._timeout = timeout
26312696 self ._ip = ip
26322697 self ._port = port
2633- sock = self ._connect ()
2698+ self .kdc_proxy = kdc_proxy
2699+ self .kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate
26342700
26352701 if self .mode in [self .MODE .AS_REQ , self .MODE .GET_SALT ]:
26362702 self .host = host .upper ()
@@ -2651,16 +2717,25 @@ def __init__(
26512717 # Negotiated parameters
26522718 self .pre_auth = False
26532719 self .fxcookie = None
2720+
2721+ sock = self ._connect ()
26542722 super (KerberosClient , self ).__init__ (
26552723 sock = sock ,
26562724 ** kwargs ,
26572725 )
26582726
26592727 def _connect (self ):
2660- sock = socket .socket ()
2661- sock .settimeout (self ._timeout )
2662- sock .connect ((self ._ip , self ._port ))
2663- sock = StreamSocket (sock , KerberosTCPHeader )
2728+ if self .kdc_proxy :
2729+ sock = KdcProxySocket (
2730+ url = self .kdc_proxy ,
2731+ targetDomain = self .realm ,
2732+ no_check_certificate = self .kdc_proxy_no_check_certificate ,
2733+ )
2734+ else :
2735+ sock = socket .socket ()
2736+ sock .settimeout (self ._timeout )
2737+ sock .connect ((self ._ip , self ._port ))
2738+ sock = StreamSocket (sock , KerberosTCPHeader )
26642739 return sock
26652740
26662741 def send (self , pkt ):
0 commit comments