Hackerman's Hacking Tutorials

The knowledge of anything, since all things have causes, is not acquired or complete unless it is known by its causes. - Avicenna

Apr 28, 2019 - 5 minute read - Comments - Thick client proxying

Thick Client Proxying - Part 9 - The Windows DNS Cache

This post explains a trick that I have been using for a few years to discover application endpoints on Windows quickly.

It's a simple trick:

  1. Clear the DNS cache.
  2. Take a snapshot of the cache.
  3. Run the application and use different functionalities.
  4. Take another snapshot of the cache.
  5. Compare these two snapshots.
  6. ???
  7. Discover (most) endpoints.

Code is at:

Update May 2020: If you are doing this in a Hyper-V guest virtual machine, it will not work. The default DNS server for a Hyper-V guest is the server. And it does not populate the local DNS cache (I do not know the reason). The fix is to manually configure a DNS server (e.g., 8.8.8.8) in the guest's network adapter.

Results in a Hyper-V guest with the default DNS server Results in a Hyper-V guest with the default DNS server

Discovering Endpoints

Discovering application endpoints is one of the starting steps in thick client proxying. I have written about it so many times that I will just make a list here. Off the top of my head I can think of:

  1. Netmon or Microsoft Message Analyzer
    • These tools isolate traffic by pid.
  2. Procmon (Process Monitor)
    • Filter by process name and then TCP/UDP Connect/Send/Receive.
  3. Procexp (Process Explorer)
    • The TCP/IP tab.
  4. TCP Catcher or 3rd party other tools.

The DNS Cache

You can interact with the DNS cache in different ways. Most common ways are:

Creating a PasteOps Prototype

We will use PowerShell because the output of commands are objects. We can format the output at-will.

PasteOps v1.0

The first iteration of our commands is completely manual. We copy/paste the following command into the PowerShell console (or ISE during development):

  1. Clear-DnsClientCache
  2. Start Google Chrome or ping google.com
    • I will explaint the reason for this step below.
  3. $dns1 = Get-DnsClientCache
  4. Navigate to https://example.net.
  5. $dns2 = Get-DnsClientCache
  6. Compare-Object -ReferenceObject $dns2 -DifferenceObject $dns1
Results of PasteOps Results of PasteOps

We have successfully discovered that the thick client (browser) has contacted example.net.

The Ping Step

In a real scenario, we want to clear the cache just right before starting the application. In our PasteOps, $dns1 might be empty if we call it just right after clearing the cache and that will return an error when doing the compare.

Error when comparing with a null result Error when comparing with a null result

What does Get-DnsClientCache Return?

Looking at the Get-DnsClientCache documentation, we can see it returns MSFT_DnsClientCache:

class MSFT_DNSClientCache : CIM_ManagedElement
{
  string InstanceId;
  string Caption;
  string Description;
  string ElementName;
  string Entry;
  string Name;
  uint16 Type;
  uint32 TimeToLive;
  uint16 DataLength;
  uint8  Section;
  string Data;
  uint32 Status;
};

As we will see later, not all fields are populated for every record.

Output Format

Table output in PowerShell is usually truncated but we can format the output as objects unlike Bash1.

Using Format Commands to Change Output View is a good introduction to different output formats.

We can use Format-Table to get the output in a table and see truncated results (it's fixable):

  • Get-DnsClientCache | Format-Table
Truncated results Truncated results

We probably don't need to see all the fields, let's modify our command:

  • Get-DnsClientCache | Format-Table -Property Entry,RecordName,Data
RecordName does not exist RecordName does not exist

Wait, what? RecordName column is in the original output but does not exist here. You might have also observed that you could use tab-complete for the other two field names (e.g., -Pro [tab] Ent [tab] to get -Property Entry) but not RecordName.

We have to use field names based on the return value which is MSFT_DNSClientCache.

  • Get-DnsClientCache | Format-Table -Property Entry,Name,Type,Data
Columns based on object fields Columns based on object fields

Some field values like Type are different from the original command output. Objects have some default printing formats. See the following link for a similar command:

Compare-Object Output

We have enough to write a PowerShell script to do the job. We can get the output of both commands and then remove the duplicates with Compare-Object.

The output of Compare-Object is a PSCustomObject that wraps the original object with a slide indicator.

$ Compare-Object -ReferenceObject $dns2 -DifferenceObject $dns1

InputObject                                                        SideIndicator
-----------                                                        -------------
MSFT_DNSClientCache (Entry = "example.net", Name = "example.net")  <=

The -PassThru switch will spit out the unwrapped objects.

$ Compare-Object -ReferenceObject $dns2 -DifferenceObject $dns1 -PassThru

Entry           RecordName      Record Status    Section TimeTo Data   Data
                                Type                     Live   Length
-----           ----------      ------ ------    ------- ------ ------ ----
example.net     example.net     A      Success   Answer   77102      4 93.184.216.34

PasteOps v2.0

Wrapped objects are not useful here. Let's add -PassThru to our PasteOps.

PasteOps v2.0
1
2
3
4
5
6
7
Clear-DnsClientCache
# Obviously replace this if you are looking to trace example.net
ping example.net
$dns1 = Get-DnsClientCache
# Run the application.
$dns2 = Get-DnsClientCache
Compare-Object -ReferenceObject $dns2 -DifferenceObject $dns1 -PassThru

We can directly work on objects and format the output in different ways or export them with something like Export-Csv for later use.

PowerShell Script

The next step after PasteOps is combining all these commands into a PowerShell script.

Endpoint-Discovery v1.0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Write-Output "Clearing the DNS cache"
Clear-DnsClientCache
Write-Output "Pinging example.net to populate the DNS cache"
Invoke-Expression "ping example.net" | Out-Null
Write-Output "Creating a snapshot of the DNS cache"
$dns_before = Get-DnsClientCache
Read-Host "Start the application and interact with it. Press Enter when done"
Write-Output "Creating a snapshot of the DNS cache"
$dns_after = Get-DnsClientCache
Compare-Object -ReferenceObject $dns2 -DifferenceObject $dns1 -PassThru

If we run the script and open up Google Chrome when prompted, we can see:

Endpoints used by Google Chrome Endpoints used by Google Chrome

We can pass the command output (which is a list of objects) to pipes and manipulate it:

Manipulating command output Manipulating command output

Limitations

Any connection method that does not end up in the DNS cache is not discoverable by this method. This usually happens when the application:

  • Does its own DNS lookup.
  • Contacts the endpoint by IP.

Full automation might be an issue. It's definitely feasible to integrate the script into an automation framework and harvest the endpoints. It will miss endpoints unless you know that your framework can call all application functionality.

What Did We Learn Here Today?

  1. We can use the Windows DNS cache to do endpoint discovery.
  2. A simple PowerShell script allows us to collect this endpoints and spits out objects that can be manipulated however you want.

  1. Bash bashing. ↩︎