Blocking a TLD because you know… zipicious

As a blue teamer I’m working on daily basis with security and network engineers to help improve the overall posture of our customers. Thing is, I don’t have my hands in a NGFW very often, so I needed an excuse to deep dive a bit more.

What better excuse than hearing a CISO shouting at engineers that they need to block the .zip TLD because he saw a tweet while eating his corn flakes in the morning?

There are already some nice blog post about the concerns of the security community around this new TLD. For example, this great blog from @bobbyrsec highlighting how it can be combine with an interesting phishing link building technique: The Dangers of Google’s .zip TLD

SANS Internet Storm Center also has a good blog post around this topic by @johullrich: The zip gTLD Risks and Opportunities

The approaches

Now that we have a reason to tackle this risk, we must find the best way to mitigate it.

There are several approaches that we could use to block the .zip TLD. In my case, I’ll be using Palo Alto NGFW, which brings me to the following possibilities:

  1. URL Filtering
  2. Custom spyware signature
  3. DNS sinkholing with External Dynamic List

While URL filtering is a great feature, its name implies it works with URL, so we might end up matching on URL that contains a “.zip” within the URI. Think about something like hXXp:// We could argue that it’s pretty rare and that managing an exception list is acceptable, but I decided not to explore this approach.

In the next sections, I will present the other two approaches.

Custom spyware signature

PAN has different threat signature profiles that we can apply to our security policies. One of them is called Anti-Spyware and aims at blocking spyware and call-home malware to C2. It is divided into:

  • Signature
  • DNS Security

Here we will explore the first part “Signature”. By default there are many signatures enabled but the firewall also allows us to create custom rules. If we go to Objects > Custom Objects > Spyware, we can add a custom signature. For that, we need to define a name and select an ID. I’d recommend following this reference for creating the rule: create-a-custom-threat-signature

Then, we need to select a condition (AND or OR), an operator and context, and we also need to define the pattern.

Again here is a reference on the usage of regular expression for the pattern section: syntax-for-regular-expression-data-patterns

I tried to use a more precise pattern such as \.zip without any luck. So there’s still some to learn around how to build the pattern with proper regular expression in PAN firewall. Here, a simple .zip pattern is enough as the firewall automatically add wildcards around it. And yes the dot is interpreted as the character dot.

My idea is to block any attempts to communicate with a .zip domain at the DNS level. So we have to select dns-req-section in the context section. We could also select dns-req-protocol-payload, which contains the whole payload of the DNS request, but it would be worse in terms of performance (didn’t test it though). Again, here is a reference on the custom signature contexts: custom-signature-contexts

Then, we just need to enable our custom rule within our Anti-Spyware profile and attach the profile to our security policies. For performance reason, I’d suggest creating a custom profile containing our custom rule and attach this profile only to the DNS security policy.

After commit, we got a warning from the firewall mentioning “Warning: one or more custom signatures have big performance impact.“. Again this is a indication that our rule might not be the most efficient #wildcard.

In addition to that, the custom signature must be aligned to a signature policy. The latter doesn’t allow the “sinkhole” action. Indeed, we can only pick between allow, alert, drop or reset. And because sinkhole is awesome this is just not acceptable, so we need to find another solution.

DNS Sinkholing with External Dynamic List

The second part of Anti-Spyware is DNS security, which enables us to use custom inputs with the sinkhole action.

Here comes the EDL, aka External Dynamic List. EDL is a great feature that allows the firewall to be fed with indicators, or more precisely the firewall will pull a dynamic list that is sitting somewhere on the network. Once the firewall collect the indicators, we can leverage the DNS policies to sinkhole any DNS requests matching our indicators. With the action set to sinkhole, the firewall will forge a DNS response as if it was the destination, pointing the client towards our predefined sinkhole IP.

Common architecture issue

I just wanted to stop here for a short architecture comment. For a SOC, this kind of threat alerts can be great to investigate, but might difficult depending on the architecture of the network.

Indeed, this DNS request might be observed between, let’s say, a Domain Controller (acting as DNS for workstations) and our DMZ DNS server. It is very likely that the source of this DNS request is not our domain controller (let’s hope) so we need to identify the real source, which represents a potentially infected device. Depending on the architecture, we might not see the DNS requests initiated from the workstations to the Domain Controller… We have here a blindspot.

Many solutions can solved this problem, such as a NIDS (Suricata, Zeek). They would capture DNS traffic between the workstations and the Domain Controller. Sysmon or an EDR could capture DNS requests on the workstation itself. Finally, having a sinkhole is another quick win that will allow us to identify the source of potential infections.

Moving down that road, we could simply define the sinkhole IP as non-used internal IP. By doing so we would be able to see in our firewall logs the workstations attempting to reach the sinkhole IP, even though this IP is not used by anyone. In fact, this is called a blackhole as the traffic is sent and lost towards this “ghost” IP. However, a limitation in that case is that while we can identify the computers attempting to reach the blackhole, we lack visibility regarding the specific domain they were trying to access. Imagine we have several workstations trying to reach that blackhole IP it would be difficult to correlate which workstations correspond to which malicious DNS requests…

Therefore, the best option is to create an actual sinkhole page to allow the TCP three-way handshake communication to be established. With URL filtering (or the sinkhole web access logs), we would be able to capture the domain (and/or URL) from the first HTTP request or within the Client Hello packet.

There are different ways of creating an EDL but in my case, I will be using Cortex XSOAR which acts as my Threat Intelligence Platform (TIP). It contains a database of indicators that I can add, modify, remove manually or through API and integrations.

In Cortex XSOAR, we can use the integration called “Generic Export Indicators Service”, which let us create an EDL. In order to expose an EDL that the firewall will pull regularly, we need to configure the integration. For that purpose, we can utilize the integration’s query field to specify which indicators to pull from the database and specify a port that will serve the EDL to the firewall. Our query will take the following format:

type:Domain verdict:Malicious expirationStatus:active

This will retrieve all domain indicators that are malicious and active. The latter is important as we might have expired indicators that we don’t want to be actively blocked by the firewall. Also it is not recommended to mix indicator types within the same list, it is better to have a separate EDL for IP on one port and another EDL for domains on another port.

Now that the EDL is ready, we can add our malicious TLD .zip to our TIP. Please note here that we are “cheating” a little because we are adding a TLD into a domain list, but we will talk about this in a bit. In Cortex XSOAR, it would look like the following.

We can verify that the EDL is accessible by browsing to the XSOAR IP and port mentioned in the “Generic Export Indicators Service” integration. With other domain indicators it should look like this.

Let’s head back to the firewall to configure the EDL pulling. For that we need to go to Object > External Dynamic List and create our very first EDL. We will select the type Domain List and enter our XSOAR IP and port mentioned in the integration. We also need to check the box Automatically expand to include subdomains, otherwise it will not work. Indeed, this checkbox simply add a “wildcard and dot” (*.) before each domain of the EDL in order to match subdomains as well. And because we “cheated” by entering a TLD into a domain list, we need that pattern “*.” before in order to match any .zip domain.

Also make sure to change the EDL update frequency to Every five minutes, so we don’t have to wait too much and click the Test Source URL button to validate that the EDL is accessible by the firewall.

Now we need to go back to our Anti-Spyware security profile. We will see that a new item has been added in the tab DNS Policies named External Dynamic List containing the EDL we just created. Here, we can change the policy action to sinkhole (yeepee!) and alternatively, we can select single-packet in the Packet Capture field, at least to begin with, just to validate. And of course, we must not forget to change the sinkhole settings to our sinkhole IP at the bottom of the wizard.

Because our security profile is already attached to our DNS security policy, we’re all set and we can start testing!

Through CLI, we got the same result.

Let’s now check in our firewall Threat logs, just to make sure. We should see the sinkhole action being applied for our domain EDL and more specifically for a .zip domain. By clicking on the green arrow at the left of the log, we can observe the packet captured by the firewall before sinkhole.


Final note

While this is working fine and is a great way to show off in front of the CISO, there are ways to improve our current setup in order to get more information about the client connecting to our sinkhole, such as:

  • We could enhance the sinkhole to catch more information about the client like the User-Agent. This could guide us towards the process/application responsible for the connection.
  • While listening on 443 to catch HTTPS requests, we need to serve a certificate that will not match the hostname that the malware tries to reach, hence failing the TLS handshake. Still we could catch and parse the Client Hello and calculate a JA3 fingerprint that, again, might help to identify the process/application responsible for the connection.
  • Of course, the EDR/XDR path is also something to consider for correlation.

Finally, I just wanted to share another interesting finding. I noticed that all my attempts to reach a .zip domain through the browser were made through HTTPS even though I’d specify HTTP. At first I thought I had a redirection on my sinkhole but no… So I checked in Wireshark but found no HTTP traffic, my machine was directly attempting to reach the sinkhole in HTTPS. Also, I notice that through CLI I could reach the sinkhole with HTTP, so it must come from the browser.

And indeed, I opened the dev tools in my browser to find out that there was a 307 redirection.

This is a typical case of HSTS, where the browser will simulate a 307 redirect to itself so that the HTTP request will be changed into HTTPS. This is done for some built-in hardcoded value that we can check by using this URL in our Google Chrome browser: chrome://net-internals/#hsts

By searching for “zip” we can find an entry forcing the use of HTTPS for all .zip domains.

Therefore, if we’re using a recent browser, any .zip link that we click will be forced to HTTPS as the TLD is HSTS-preloaded within the browser. There are other TLDs that are HSTS-preloaded such as .dev, .mov or .app.

Finally, as suggested by @bobbyrsec, we could carry on this deep dive to try blocking/detecting the usage Unicode characters U+2044 and U+2215, which can be used to build good looking phishing links.

Happy to discuss further and to hear any kind of feedback on my twitter account Sam0x90.

See you next time!

PS: If you need a quick’n’dirty python web server to test a sinkhole, checkout this:

Leave a Reply