Create a WEF simulator in python using kerberos authentication
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.
- "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.
- You are using 'kerberos' library directly, which can be more cumbersome and error-prone then using a higher-level library like 'requests-kerberos'
- 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.