cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

I'm beginning to think that I had the wrong approach to a topic that I posted in a previous question (here), regarding Domain Fronting.  Is there a way to compare the host name for a GET or POST to that of the CONNECT in which they are tunneled?  The idea being to restrict GET's and POST's to the domain of the CONNECT, at least for those destinations with less trustworthy risk scores. 

And, this brings up a related question: are the details in the SSL certificate from the CONNECT, particularly that of CN's and alternate names, visible to the tunneled GET's and POST's?  If so, what would be a good approach to validate the current hostname to the CN and alternate names?

  

3 Solutions

Accepted Solutions
Former Member
Not applicable
Report Inappropriate Content
Message 3 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

I found a good test for this as well as a means to detect it on MWG.

To test, here is a curl command which opens a tunnel for cnn.com, and once the tunnel is opened, requests are sent for mcafee.com instead.

curl --insecure -v -s -o /dev/null --proxy http://yourmwg:9090 -H "Host: mcafee.com" -H "Connection: close" "https://cnn.com/"

In the Web Gateway we can make use of the Connection.Variables.* events and properties to store the originally requested domain from the CONNECT request, and recall it once we're inside the tunnel to perform a test to see if the original domain matches the domain requested in the tunnel.

Now this might have some caveats, specifically related to transparent proxy. So by default these rules only apply to Explicit proxy requests. For transparent proxy requests, the MWG relies on the SNI header in order to determine the originally requested domain, so if that is not present, then the MWG would only know the destination IP, and in most cases that will result in a mismatch.

2018-08-29_094418.png2018-08-29_094450.png2018-08-29_094505.pngLet me know if you have any questions on the rules and if this helps at all. At first it might be good to just monitor to these things, then block (in case there is false positives).

 

Best Regards,

Jon

View solution in original post

jebeling
Employee
Employee
Report Inappropriate Content
Message 5 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

The URL.DiscardedHost property was added in 7.8.2. From the interface reference guide:

URL.DiscardedHost String

Name of a host that was discarded when conflicting host names occurred in a request sent in HTTP(S) or SSL communication.

A conflict of this kind is also known as domain fronting. It is resolved by the proxy on Web Gateway, which prefers one of the conflicting host names over the other, depending on what is configured.

By querying the value of this property in the criteria of a rule or by logging it, you can detect a host name conflict. If no conflict arises, the value of the property is an empty string.

Conflicting host names might occur in the following scenarios:

  • Under HTTP(S): The first-line part of the communication does not match the host header that is sent with a request.

    This conflict does not arise under HTTPS2, where no first-line part is sent in any single stream.

  • Under SSL: The host name sent in a CONNECT request does not match the host information read from a client hello.

 

The proxy unifies the URL from the firstline and the Host header before the rule engine is called, this ensures that the policy decision is made based on the same data that the proxy is using to determine the destination. Whether or not the firstline or  the host header wins can be configured in the advanced section of the proxy configuration.

The ruleset is not needed on versions after 7.8.2. Action (log or block) can be based on DiscardedHost property. “URL.DiscardedHost” will be filled if  there was an instance of domain fronting that was allowed to override the firstline. 

Was my reply helpful?

If this information was helpful in any way or answered your question, will you please select Accept as a Solution and/or Kudo my reply so we can help other community participants?

View solution in original post

jebeling
Employee
Employee
Report Inappropriate Content
Message 6 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

Attached is a much improved ruleset for detecting and blocking DF attempts using both the DiscardedHosts property and Connection Variables. The rulset saves the connected domain and compares that to the URL.Host domain of any subsequent GETs.

Domain Fronting Blocking and Logging
[✔] Enabled [✘] Disabled in Cloud
Applies to: [] Requests [] Responses [] Embedded Objects
1: URL.DiscardedHost does not equal ""
2: OR Command.Name equals "CONNECT"
3: OR Connection.Variables.HasString("ConnectedDomain") equals true
Enabled Rule Action Events Comments
[✔] Enabled Save Connected Host
1: Command.Name equals "CONNECT"
Continue Connection.Variables.AddString("ConnectedDomain",URL.Domain)  
[✔] Enabled Bypass if URL.Host is Not Resolvable
1: URL.Destination.IP equals 255.255.255.255
Stop Rule Set    
[✔] Enabled Bypass if Discarded Host is Not Resolvable
1: URL.DiscardedHost does not equal ""
2: AND List.OfIP.IsEmpty(DNS.Lookup(URL.DiscardedHost)) equals true
Stop Rule Set    
[✔] Enabled Bypass if Destination Host has Local Address
1: URL.Destination.IP is in range list Domain Fronting Bypass IP Ranges
Stop Rule Set    
[✔] Enabled Bypass if Discarded Host SmartMatches Domain Fronting SmartMatch Whitelist
1: URL.SmartMatch(Domain Fronting Whitelist) equals true
Stop Rule Set    
[✘] Disabled Discarded Host Mismatch Log Only
1: URL.DiscardedHost does not equal ""
2: AND URL.DiscardedHost does not equal URL.Host
Stop Rule Set Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
[✔] Enabled Discarded Host Mismatch Block and Log
1: URL.DiscardedHost does not equal ""
2: AND URL.DiscardedHost does not equal URL.Host
Block<Domain Fronting Block> Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
[✘] Disabled Connected Domain Mismatch Log Only
1: Connection.Variables.HasString("ConnectedDomain") equals true
2: AND URL.Domain does not equal Connection.Variables.GetStringValue("ConnectedDomain")
Stop Rule Set Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
[✔] Enabled Connected Domain Mismatch Block and Log
1: Connection.Variables.HasString("ConnectedDomain") equals true
2: AND URL.Domain does not equal Connection.Variables.GetStringValue("ConnectedDomain")
Block<Domain Fronting Block> Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
Was my reply helpful?

If this information was helpful in any way or answered your question, will you please select Accept as a Solution and/or Kudo my reply so we can help other community participants?

View solution in original post

5 Replies
Former Member
Not applicable
Report Inappropriate Content
Message 2 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

Hi John,

So, MWG has a configuration option called "Host header has priority over original destination address (transparent proxy", this prevents situations where there is a mismatch between the Host header and the Request line. 7.8.2 brings a property called URL.DiscardedHost which is meant to help detect Domain Fronting whereby you can access the host that was discarded from the scenario above.

For the scenario you described MWG would connect to the Host from the CONNECT request, and if inside the tunnel requests are made for separate domains, MWG would see those requests assuming that SSL inspection is enabled.

So if the CONNECT was for facebook.com, and you've got something making requests to malware.com (inside the tunnel), MWG will see those requests and treat them according to your policy.

Having said this I'm not sure if we'd have the "facebook.com" context available for the requests inside the tunnel (to make sure the hosts match). Did you have a script you were using to try and recreate this scenario? This might be something I could test really quick if you did.

Best Regards,

Jon

Former Member
Not applicable
Report Inappropriate Content
Message 3 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

I found a good test for this as well as a means to detect it on MWG.

To test, here is a curl command which opens a tunnel for cnn.com, and once the tunnel is opened, requests are sent for mcafee.com instead.

curl --insecure -v -s -o /dev/null --proxy http://yourmwg:9090 -H "Host: mcafee.com" -H "Connection: close" "https://cnn.com/"

In the Web Gateway we can make use of the Connection.Variables.* events and properties to store the originally requested domain from the CONNECT request, and recall it once we're inside the tunnel to perform a test to see if the original domain matches the domain requested in the tunnel.

Now this might have some caveats, specifically related to transparent proxy. So by default these rules only apply to Explicit proxy requests. For transparent proxy requests, the MWG relies on the SNI header in order to determine the originally requested domain, so if that is not present, then the MWG would only know the destination IP, and in most cases that will result in a mismatch.

2018-08-29_094418.png2018-08-29_094450.png2018-08-29_094505.pngLet me know if you have any questions on the rules and if this helps at all. At first it might be good to just monitor to these things, then block (in case there is false positives).

 

Best Regards,

Jon

jebeling
Employee
Employee
Report Inappropriate Content
Message 4 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

A bug was discovered in v2. Thanks Aaron. The v2 ruleset works if you enable the first rule and disable the second.

front1.jpg

 

Or if you change the logic of the second rule to stop ruleset if Connection.SSLTransparentNameHandling equals true.

front2.jpg

 

Was my reply helpful?

If this information was helpful in any way or answered your question, will you please select Accept as a Solution and/or Kudo my reply so we can help other community participants?
jebeling
Employee
Employee
Report Inappropriate Content
Message 5 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

The URL.DiscardedHost property was added in 7.8.2. From the interface reference guide:

URL.DiscardedHost String

Name of a host that was discarded when conflicting host names occurred in a request sent in HTTP(S) or SSL communication.

A conflict of this kind is also known as domain fronting. It is resolved by the proxy on Web Gateway, which prefers one of the conflicting host names over the other, depending on what is configured.

By querying the value of this property in the criteria of a rule or by logging it, you can detect a host name conflict. If no conflict arises, the value of the property is an empty string.

Conflicting host names might occur in the following scenarios:

  • Under HTTP(S): The first-line part of the communication does not match the host header that is sent with a request.

    This conflict does not arise under HTTPS2, where no first-line part is sent in any single stream.

  • Under SSL: The host name sent in a CONNECT request does not match the host information read from a client hello.

 

The proxy unifies the URL from the firstline and the Host header before the rule engine is called, this ensures that the policy decision is made based on the same data that the proxy is using to determine the destination. Whether or not the firstline or  the host header wins can be configured in the advanced section of the proxy configuration.

The ruleset is not needed on versions after 7.8.2. Action (log or block) can be based on DiscardedHost property. “URL.DiscardedHost” will be filled if  there was an instance of domain fronting that was allowed to override the firstline. 

Was my reply helpful?

If this information was helpful in any way or answered your question, will you please select Accept as a Solution and/or Kudo my reply so we can help other community participants?
jebeling
Employee
Employee
Report Inappropriate Content
Message 6 of 6

Re: Domain Fronting, Vulnerabilities and Detection, Part II

Jump to solution

Attached is a much improved ruleset for detecting and blocking DF attempts using both the DiscardedHosts property and Connection Variables. The rulset saves the connected domain and compares that to the URL.Host domain of any subsequent GETs.

Domain Fronting Blocking and Logging
[✔] Enabled [✘] Disabled in Cloud
Applies to: [] Requests [] Responses [] Embedded Objects
1: URL.DiscardedHost does not equal ""
2: OR Command.Name equals "CONNECT"
3: OR Connection.Variables.HasString("ConnectedDomain") equals true
Enabled Rule Action Events Comments
[✔] Enabled Save Connected Host
1: Command.Name equals "CONNECT"
Continue Connection.Variables.AddString("ConnectedDomain",URL.Domain)  
[✔] Enabled Bypass if URL.Host is Not Resolvable
1: URL.Destination.IP equals 255.255.255.255
Stop Rule Set    
[✔] Enabled Bypass if Discarded Host is Not Resolvable
1: URL.DiscardedHost does not equal ""
2: AND List.OfIP.IsEmpty(DNS.Lookup(URL.DiscardedHost)) equals true
Stop Rule Set    
[✔] Enabled Bypass if Destination Host has Local Address
1: URL.Destination.IP is in range list Domain Fronting Bypass IP Ranges
Stop Rule Set    
[✔] Enabled Bypass if Discarded Host SmartMatches Domain Fronting SmartMatch Whitelist
1: URL.SmartMatch(Domain Fronting Whitelist) equals true
Stop Rule Set    
[✘] Disabled Discarded Host Mismatch Log Only
1: URL.DiscardedHost does not equal ""
2: AND URL.DiscardedHost does not equal URL.Host
Stop Rule Set Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
[✔] Enabled Discarded Host Mismatch Block and Log
1: URL.DiscardedHost does not equal ""
2: AND URL.DiscardedHost does not equal URL.Host
Block<Domain Fronting Block> Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
[✘] Disabled Connected Domain Mismatch Log Only
1: Connection.Variables.HasString("ConnectedDomain") equals true
2: AND URL.Domain does not equal Connection.Variables.GetStringValue("ConnectedDomain")
Stop Rule Set Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
[✔] Enabled Connected Domain Mismatch Block and Log
1: Connection.Variables.HasString("ConnectedDomain") equals true
2: AND URL.Domain does not equal Connection.Variables.GetStringValue("ConnectedDomain")
Block<Domain Fronting Block> Set User-Defined.logLine =
     DateTime.ToWebReporterString +
     " "" +
     Authentication.UserName +
     "" " +
     String.ReplaceIfEquals(IP.ToString(Client.IP),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(Response.StatusCode),"","-") +
     " "" +
     Request.Header.FirstLine +
     "" "" +
     IP.ToString(URL.Destination.IP) +
     "" "" +
     MediaType.ToString(MediaType.FromHeader) +
     "" " +
     String.ReplaceIfEquals(Number.ToString(BytesToClient),"","-") +
     " " +
     String.ReplaceIfEquals(Number.ToString(BytesFromClient),"","-") +
     " "" +
     Header.Request.Get("User-Agent") +
     "" "" +
     Number.ToString(Block.ID) +
     "" "" +
     Application.ToString(Application.Name) +
     "" "" +
     URL.DiscardedHost +
     "" "" +
     List.OfIP.ToString(DNS.Lookup(URL.DiscardedHost),",") +
     """
FileSystemLogging.WriteLogEntry(User-Defined.logLine)<Domain Fronting Log>
 
Was my reply helpful?

If this information was helpful in any way or answered your question, will you please select Accept as a Solution and/or Kudo my reply so we can help other community participants?
You Deserve an Award
Don't forget, when your helpful posts earn a kudos or get accepted as a solution you can unlock perks and badges. Those aren't the only badges, either. How many can you collect? Click here to learn more.

Community Help Hub

    New to the forums or need help finding your way around the forums? There's a whole hub of community resources to help you.

  • Find Forum FAQs
  • Learn How to Earn Badges
  • Ask for Help
Go to Community Help

Join the Community

    Thousands of customers use our Community for peer-to-peer and expert product support. Enjoy these benefits with a free membership:

  • Get helpful solutions from product experts.
  • Stay connected to product conversations that matter to you.
  • Participate in product groups led by employees.
Join the Community
Join the Community