Create a WEF simulator in python using kerberos authentication

Create a WEF simulator in python using kerberos authentication
python
Ethan Jackson

I have a real WEF/WEC setup where i have three machines: Windows Server, Windows 10 (WEF) and Windows 10 (WEC). It works just fine like this... But i want to have a WEF simulator using python with kerbeos authentication.

I installed Wireshark on my WEF, just to see what it is actually sending to WEC and seems it is always sending two requests First one is authenticating using Kerberos token (as you can see it shows HTTP request 1/2):

Hypertext Transfer Protocol POST /wsman HTTP/1.1\r\n Connection: Keep-Alive\r\n Content-Type: application/soap+xml;charset=UTF-16\r\n [truncated]Authorization: Kerberos <kerbeors token> GSS-API Generic Security Service Application Program Interface User-Agent: Microsoft WinRM Client\r\n Content-Length: 0\r\n [Content length: 0] Host: wec.com:8080\r\n \r\n [Full request URI: http://wec.com:8080/wsman] [HTTP request 1/2] [Next request in frame: 24]

And the second one is actually the one contains the XML data (see HTTP request 2/2):

Hypertext Transfer Protocol POST /wsman HTTP/1.1\r\n Connection: Keep-Alive\r\n Content-Type: multipart/encrypted;protocol="application/HTTP-Kerberos-session-encrypted";boundary="Encrypted Boundary"\r\n User-Agent: Microsoft WinRM Client\r\n Content-Length: 3472\r\n [Content length: 3472] Host: wec.com:8080\r\n \r\n [Full request URI: http://wec.com:8080/wsman] [HTTP request 2/2] [Prev request in frame: 22] File Data: 3472 bytes

Sample xml data:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd"> <s:Header> <a:To>http://wec.com:8080/wsman</a:To> <m:MachineID xmlns:m="http://schemas.microsoft.com/wbem/wsman/1/machineid" s:mustUnderstand="false">wef.wec.com </m:MachineID> <a:ReplyTo> <a:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address> </a:ReplyTo> <a:Action s:mustUnderstand="true">http://schemas.dmtf.org/wbem/wsman/1/wsman/Events</a:Action> <w:MaxEnvelopeSize s:mustUnderstand="true">512000</w:MaxEnvelopeSize> <a:MessageID>uuid:87AF6068-CB36-4B7C-8C4B-038D839CF904</a:MessageID> <w:Locale xml:lang="en-US" s:mustUnderstand="false" /> <p:DataLocale xml:lang="en-US" s:mustUnderstand="false" /> <p:SessionId s:mustUnderstand="false">uuid:1707AC9F-3D93-4B88-825C-B75403C72C7C</p:SessionId> <p:OperationID s:mustUnderstand="false">uuid:FA29F086-B795-4F4A-B825-8628BFB8F157</p:OperationID> <p:SequenceId s:mustUnderstand="false">1</p:SequenceId> <w:OperationTimeout>PT60.000S</w:OperationTimeout> <e:Identifier xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing">uuid:8e6f0ea4-1f4e-11ef-801a-616c6d617765 </e:Identifier> <w:Bookmark> <BookmarkList> <Bookmark Channel="Application" RecordId="17256411" IsCurrent="true"/> <Bookmark Channel="Security" RecordId="1"/> <Bookmark Channel="System" RecordId="2470"/> </BookmarkList> </w:Bookmark> <w:AckRequested/> </s:Header> <s:Body> <w:Events> <w:Event Action="http://schemas.dmtf.org/wbem/wsman/1/wsman/Event"> <Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'> <System> <Provider Name='Microsoft-Windows-Security-SPP' Guid='{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}' EventSourceName='Software Protection Platform Service'/> <EventID Qualifiers='16384'>16384</EventID> <Version>0</Version> <Level>4</Level> <Task>0</Task> <Opcode>0</Opcode> <Keywords>0x80000000000000</Keywords> <TimeCreated SystemTime='2024-05-31T12:23:09.8605030Z'/> <EventRecordID>17256409</EventRecordID> <Correlation/> <Execution ProcessID='0' ThreadID='0'/> <Channel>Application</Channel> <Computer>wef.wec.com</Computer> <Security/> </System> <EventData> <Data>2024-06-14T16:57:09Z</Data> <Data>RulesEngine</Data> </EventData> <RenderingInfo Culture='en-US'> <Message>Successfully scheduled Software Protection service for re-start at 2024-06-14T16:57:09Z. Reason: RulesEngine.</Message> <Level>Information</Level> <Task></Task> <Opcode></Opcode> <Channel></Channel> <Provider>Microsoft-Windows-Security-SPP</Provider> <Keywords> <Keyword>Classic</Keyword> </Keywords> </RenderingInfo> </Event> </w:Event> </w:Events> </s:Body> </s:Envelope>

How can i send this in python? Sending these one by one, didn't work. This is my last piece of code i tried, but WEC is not accepting it:

import requests import kerberos from requests_toolbelt.multipart.encoder import MultipartEncoder def get_kerberos_token(service): __, krb_context = kerberos.authGSSClientInit(service) kerberos.authGSSClientStep(krb_context, "") negotiate_details = kerberos.authGSSClientResponse(krb_context) return negotiate_details multipart_data = MultipartEncoder( fields={ 'part1': ('', '', 'application/HTTP-Kerberos-session-encrypted'), 'part2': ('', xml_content, 'application/octet-stream') }, boundary='Encrypted Boundary' ) headers = { 'Connection': 'Keep-Alive', 'Content-Type': multipart_data.content_type, 'User-Agent': 'Microsoft WinRM Client', 'Host': '127.0.0.1:8080', 'Authorization': f'Kerberos {get_kerberos_token()}' } response = requests.post( url='http://127.0.0.1:8080/wsman', data=multipart_data, headers=headers )

Answer

It looks like you're on the right track, but there are some things you can change and improve.

  1. "kerberos.authGSSClientInit" requires a service. When you call "kerberos.authGSSClientInit()" you need to provide the 'service' properly. This typically looks like 'HTTP@hostname' so the function 'get_kerberos_token()' needs a proper service string.
  2. You are using 'kerberos' library directly, which can be more cumbersome and error-prone then using a higher-level library like 'requests-kerberos'
  3. Adjust the 'Authorization' header to integrate the Kerberos token correctly.

I didn't test this I just corrected the code.

import requests from requests_kerberos import HTTPKerberosAuth, OPTIONAL from requests_toolbelt.multipart.encoder import MultipartEncoder # Function to read XML content from an external file # This function opens the specified XML file, reads the content, and returns it as a string def read_xml_content(file_path): with open(file_path, 'r', encoding='utf-8') as file: return file.read() # Path to the external XML file xml_file_path = 'event_data.xml' # Read the XML content from the file # This variable will hold the XML data read from the file xml_content = read_xml_content(xml_file_path) # Create a multipart encoder with the required boundary and fields # This sets up the multipart form-data payload with the defined boundary and fields multipart_data = MultipartEncoder( fields={ 'part1': ('', '', 'application/HTTP-Kerberos-session-encrypted'), 'part2': ('', xml_content, 'application/octet-stream') }, boundary='Encrypted Boundary' ) # Set up headers # In this section we define the headers required for the HTTP request headers = { 'Connection': 'Keep-Alive', 'Content-Type': multipart_data.content_type, # This is set to the content type from the multipart encoder 'User-Agent': 'Microsoft WinRM Client', # User-Agent string similar to what a Windows client might send 'Host': '127.0.0.1:8080', # Update as necessary for your specific server } # Initialize Kerberos authentication using requests-kerberos # This initializes the Kerberos authentication handler to be used in the request kerberos_auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL) # Perform the HTTP POST request # This sends the POST request with the multipart data and the headers specified, and uses Kerberos authentication response = requests.post( url='http://127.0.0.1:8080/wsman', # Update as necessary with your specific endpoint data=multipart_data, headers=headers, auth=kerberos_auth # The Kerberos authentication is handled here ) # Check the response # This checks the HTTP response status and prints appropriate messages based on the status if response.status_code == 200: print("Request sent successfully!") else: print(f"Failed to send request. Status code: {response.status_code}") print("Response content:", response.content)

I introuduced 'read_xml.content(file_path)' function to read XML from an external file named 'event_data.xml', I leveraged 'requests_kerberos' for handling Kerberos authentication. 'HTTPKerberosAuth' handles the 'Authorization' header; no need to manually set the token. I removed the manual Kreberos token insertion to let 'requests-kerberos' handle it. I ensured that the header 'Authorization' utilizes the 'kerberos_auth' instance for embedding the Kerberos token.This should ensure that WEF client works smoothly with Kerberos authentication, ensuring your HTTP requests are properly authenticated and sent to the WEC server.

Related Articles