I recently wanted to learn more about the internals of Active Directory Federation Services (ADFS) and created an Azure Resource Manager (ARM) template to deploy a basic lab environment. As part of my initial research process, I wanted to understand how a user got authenticated before getting an authentication token to access a cloud service. Thefore, I figured it would be good to document some of it by inspecting the network traffic it generates.
In this post, I will show you how to use fiddler and Wireshark to inspect the network traffic generated while accessing and providing credentials to the default ADFS Sign On page via the Intranet. This basic example does not require to have a SAML Service Provider (Relaying Party Trust) set up since, once again, I am interested in the process before getting an authentication token.
- An Active Directory (AD) Environment with a Domain Controller (DC)
- An Active Directory Federation Service (ADFS) server
- A federation server farm set up
- A domain joined computer
- [Optional] You can deploy all the above in less than 30 minutes with this ARM template from the project Blacksmith.
- On the Domain Joined Computer:
- On the ADFS Server:
- Install Wireshark
Once you have all the requirements above taken care of, I recommend to validate your ADFS setup.
Validate ADFS Server Setup (Server Side)
- RDP to ADFS Server
- Check if the ADFS serve is running
- Check ADFS properties
- You can get the ADFS Service
HostNameby running the following command (You will need that value in the next section)
Get-AdfsProperties | select-object HostName
- Check ADFS servers available and certificates
- We are going to be using the ADFS Sign On page via the Intranet so we also need to check if that feature is enabled. We do it by verifying if the ADFS property
EnableIdpInitiatedSignonPageis set to
Get-AdfsProperties | select-object EnableIdpInitiatedSignonPage
- If property is set to
False, run this command to enable it and restart the ADFS service
Set-AdfsProperties -EnableIdpInitiatedSignonPage $true Restart-Service -Name adfssrv
- In order to avoid continuous credentials prompt while authenticating and capturing/proxying traffic with fiddler, we need to disable the
Extended Protection for Authenticationproperty in the ADFS server.
Get-AdfsProperties | select ExtendedProtectionTokenCheck Set-ADFSProperties -ExtendedProtectionTokenCheck:None Restart-Service -Name adfssrv Get-AdfsProperties | select ExtendedProtectionTokenCheck
Validate ADFS Server Setup (Client Side)
From a domain joined computer, we can check the ADFS server setup by exploring the federation server service metadata
- RDP to domain joined endpoint
- Browse to
<ADFS HostName>with the
HostNamevalue of the ADFS service obtained in the previous section)
Another easy way to validate that the federation service is running an handling kerberos authentication is by browsing to
https://<ADFS HostName>/adfs/ls/IdpInitiatedSignon.aspx and entering domain credentials (replace
<ADFS HostName> with the
HostName value of the ADFS service obtained in the previous section)
- If everything is working properly (at least on-prem via the intranet), you will get the
You are signed inmessage
That was very easy right? Now, let’s set up our network traffic captures.
Client Network Capture Setup
- Log on (if you disconnected) to domain joined computer
- Open fiddler
Decrypt HTTPS trafficoption in Tools > Options > HTTPs
- Trust the fiddler root certificate
- I used Microsoft Edge for this blog post. Therefore, We need to enable Microsoft Edge to send network traffic to the local computer (AppContainer Loopback Exemption). WinConfig > Microsoft Edge > Save Changes
- Make sure you are capturing traffic and that the
Kerberosextension is available under the
Inspectorsoptions. You can simply open Microsoft Edge and go to any site (just to generate traffic and not to validate Kerberos parsers)
- Close browser and remove all sessions captured by Fiddler. Getting ready!
- Open Edge from Fiddler and Filter Web Browser Only
- Filter traffic to only capture from web browsers
- Open Wireshark and apply the following filter:
ip.addr == <DC IP Address> or ip.addr == <ADFS IP Address>
ADFS Server Network Capture Setup
- Open Wireshark and apply the following filter:
ip.addr == <DC IP Address> or ip.addr == <Domain Joined Computer IP Address>
Capture Network Traffic
- Once again, on the client, browse to
https://<ADFS FQDN>/adfs/ls/IdpInitiatedSignon.aspxand click on
- Enter Domain Credentials
- You will see a few events captured by fiddler. I recommend to filter the results on the specific
microsoftedgecpprocess that handled the authentication as shown below:
- You will also see a few events in Wireshark (both client and server). I am interested in the
KRB5protocol ones as shown below
- Stop fiddler and wireshark captures. Time to learn a little bit more about this process
Inspect Network Traffic
1. Access to ADFS Sign On Page
Client Connects to the ADFS server via
https://adfs.solorigatelabs.com/adfs/ls/idpinitiatedsignon.aspx . Here is where we get to the Open Threat Research banner with the option to
Sign In and the message
You are not signed in. Sign in to this site. Nothing special. Just a simple GET request to get to ADFS sign on page.
2. Redirection to ADFS Server and SamlRequest Generation
Client clicks on the
Sign In button. That click makes a
POST request to
The ADFS server receives the requests and returns a
302 Response Code and it sets the new
https://adfs.solorigatelabs.com:443/adfs/ls/wia?client-request-id=6717a4e4-50f7-4655-7700-0080000000d5 where we can see the use of Windows Integrated Authentication (WIA) which is used for authentication requests that occur within the organization’s internal network (intranet) for any application that uses a browser for its authentication.
One thing also that was provided in the 302 Redirect Message was a
MSISSamlRequest value inside of a cookie which contained the
SamlRequest (AuthnRequest). A SAML Request is usually sent by the SAML service before the user is redirected to the Identify Provider (ADFS Server itself). The identity provider then decodes the SAML request and gets ready to authenticate the user.
This was the
MSISSamlRequest value inside of the cookie (Base64 Encoded)
After base64 decoding that value, we get to the Url encoded value of
BaseUrl which contains the
After Url decoding the
baseUrl value, we get the following value:
We can then take the deflated base64 encoded SAML Message inside of the
SamlRequest and decode and inflate it.
<samlp:AuthnRequest ID="_80182abd-1dca-41a5-990b-d7b5566760ff" Version="2.0" IssueInstant="2021-01-05T07:03:10.092Z" Destination="https://adfs.solorigatelabs.com/adfs/ls/" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://ADFS.solorigatelabs.com/adfs/services/trust</Issuer></samlp:AuthnRequest>
This message contains details needed by the ADFS server (Identity Provider) to process the user authentication. You can also decode all those string with tools from here https://www.samltool.com/online_tools.php.
- Base64 Decode
- URL Decode
- Base64 Decode + Inflate
3. Enter Credentials in Logon Form
After the previous redirection, the client receives a
401 Response Code. This is simply telling the client to authenticate against the ADFS server (Identity Provider). Here is where we entered our domain credentials
4. Kerberos Authentication
The Identity Provider decodes the
SAMLRequest and performs the user authentication via Kerberos.
AS-REQ (Client -> Domain Controller The client first sends a request to the Kerberos Authentication Service (AS) to get TGT.
- Client-Principal: pgustavo
- Principal Service: krbtgt/SOLORIGATELABS
PREAUTH_REQUIRED (Domain Controller -> Client)
Kerberos Pre-Authentication is a security feature which offers protection against password-guessing attacks. The AS request identifies the client to the KDC in Plaintext. If Kerberos Pre-Authentication is enabled, a Timestamp will be encrypted using the user’s password hash as an encryption key. If the KDC reads a valid time when using the user’s password hash, which is available in the Microsoft Active Directory, to decrypt the Timestamp, the KDC knows that request isn’t a replay of a previous request.
Error Code: 25 - HEX -> 0x19 (Source)
AS-REQ (Client -> Domain Controller) The client sends another request to the Kerberos Authentication Service (AS), but with the encrypted timestamp this time.
AS-RESP (Domain Controller -> Client) Client receives a response with a TGT for user pgustavo. This is just to request a service ticket to access the ADFS service.
TGS-REQ (Client -> Domain Controller)
Client requests access to
adfs.solorigatelabs.com to the Ticket Granting Server (TGS)
TGS-REP (Domain Controller -> Client)
TGS responds with a service ticket to the
AS-REQ (ADFS -> Domain Controller) After pgustavo enters its credentials, the ADFS server handles the authentication process and sends a request to the Kerberos Authentication Service (AS) on behalf of pgustavo.
- User being authenticated: pgustavo
- Service requested: krbtgt
- Host Address: ADFS01 Server
PREAUTH_REQUIRED (Domain Controller -> ADFS)
S4U2self TGS Exchange (Delegation) - TGS-REQ (ADFS -> Domain Controller)
S4U2Self delegation sub-protocol is used by the ADFS service to obtain a ticket on behalf of
In a KRB_TGS_REQ and KRB_TGS_REP subprotocol message sequence, a Kerberos principal uses its ticket-granting ticket (TGT) to request a service ticket to a service. The TGS uses the requesting principal’s identity from the TGT passed in the KRB_TGS_REQ message to create the service ticket.
In the S4U2self TGS exchange subprotocol extension, a service requests a service ticket to itself on behalf of a user. The user is identified to the KDC by the user name and user realm. Alternatively, the user might be identified using the user’s certificate.
The service uses its own TGT and adds a new type of padata
If the service possesses the user certificate, it can obtain a service ticket to itself on that user’s behalf using the S4U2self TGS exchange subprotocol extension, with a new padata type PA-S4U-X509-USER (ID 130)
S4U2self TGS Exchange (Delegation) - TGS-REP (Domain Controller -> ADFS)
The ADFS service gets a ticket with the username
pgustavo and the service name mapped to the
AP-REQ (Client -> ADFS)
After pgustavo is authenticated via Kerberos, it then sends a kerberos ticket in the authorization header (Negotiate). This is parsed by the Fiddler
4. Successful Authentication & Authentication Cookies
A final redirection occurs since we are simply authenticating against the ADFS server. Remember there are no service providers set up.
We also finally get “Authentication Cookies” such as
The MSISAuth (MSISAuth + MSISAuth1 + …) are the encrypted cookies used to validate the SAML assertion produced for the client. The cookie is used for subsequent authentications against the ADFS. These are what we call the “authentication cookies”, and you will see these cookies ONLY when AD FS 2.0 is the IdP. Without these, the client will not experience SSO.
After going through all those steps, I put together this image to summarize the main steps. This is going to help me as a reference for when I add service providers.
That’s it! I hope you enjoyed this post and helps you as a reference for other projects!
Subscribe to Open Threat Research Blog
Get the latest posts delivered right to your inbox