Didier Stevens

Tuesday 27 December 2022

Combining dns-pydivert And dnsresolver

Filed under: Malware,My Software,Networking — Didier Stevens @ 0:00

I use my tools dns-pydivert and dnsresolver.py for dynamic analysis of software (malware and benign software).

On the virtual machine where I’m doing dynamic analysis, I disable IPv6 support.

I install dnslib and run dnsresolver.py with a command like this, for example:

dnsresolver.py "type=resolve,label=example.com,answer=. 1 IN A 127.0.0.1" "type=forwarder,server=8.8.8.8"

The first command is a resolve command: DNS A queries for example.com will be resolved to IPv4 address 127.0.0.1 with TTL 1 minute.

The second command is a forwarder command: all DNS requests not handled by other commands, are forwarded to 8.8.8.8. Make sure that the IPv4 address of the DNS server you forward requests to, is different from the VM’s default DNS server, otherwise this forwarding will be redirected by dns-pydivert too.

I don’t use this second resolver command if the VM is isolated from the Internet, I only use it when I want to allow some interaction with the Internet.

Then I install pydivert and run dns-pydivert.py as administrator.

You can’t run dns-pydivert.py properly without administrative permissions:

When dns-pydivert.py and dnsresolver.py are running, DNS traffic is altered according to our settings.

For example (picture above), when I issue a “ping google.com” command inside the VM, dns-pydivert sees this first DNS packet and configures itself with the addresses in this packet: 192.168.32.129 is the IPv4 address of the Windows VM and 192.168.32.2 is the IPv4 address of this Windows VM’s DNS server.

It alters this first request to be redirected to the VM itself (192.168.32.2 -> 192.168.32.129).

Then dnsresolver receives this packet, and forwards it to DNS server 8.8.8.8. It receives a reply from DNS server 8.8.8.8, and forwards it to the Windows VM (192.168.32.129).

Then dns-pydivert sees this reply, and changes its source from 192.168.32.129 to 192.168.32.2, so that it appears to come from the Windows VM’s default DNS server.

When I do the same (picture above) for example.com (ping example.com), the query is redirected to dnsresolver, which resolves this to 127.0.0.1 with a TTL of 1 minute (per resolve commands configuration).

Thus the ping command pings the localhost, instead of example.com’s web server.

And when I kill dns-pydivert (picture above) and issue a “ping example.com” again after waiting for 1 minute, the query is no longer redirected and example.com’s web server is pinged this time.

I used ping here to illustrate the process, but often it’s HTTP(S) traffic that I want to redirect, and then I also use my simple-listener.py tool to emulate simple web servers.

Remark that this will only redirect DNS traffic (per the configuration). This does not redirect traffic “directed” at IPv4 addresses (as opposed to hostnames).

This can be done too with pydivert, and I will probably release a tool for that too.

Thursday 31 March 2022

spring4shell Capture File

Filed under: Networking,Vulnerabilities — Didier Stevens @ 19:13

If you are interested, I’ve put a spring4shell exploit capture file on my GitHub.

It might trigger your AV, like Defender (Defender triggers on the webshell code).

First HTTP request in the capture file, is just a test query.

Second HTTP request is the exploit that drops a webshell.

Third HTTP request is using that webshell.

Figure 1: just a test request
Figure 2: exploit dropping a webshell
Figure 3: using the webshell

Sunday 3 October 2021

New Tool: onion-connect-service-detection.py

Filed under: My Software,Networking — Didier Stevens @ 0:00

To better understand how nmap does service detection, I implemented a tool in Python that tries to do (more or less) the same. nmap detects what service is listening on a port, by sending it probes (particular byte sequences) and matching it with expected replies. These probes and replies can be found in file nmap-service-probes.

It allows me to experiment with service detection.

By default onion-connect-service-detection.py connects to service ports over the Tor network.

Here is an example where I use the tool to detect services on the 10 most popular ports (top:10) of example.com. With a time-out of 5 seconds.

onion-connect-service-detection_V0_0_1.zip (https)
MD5: 8C6D94E1CEE4747E18807CB95FCB1EE9
SHA256: ADC8D937522F55CC47C91E5DC01B2B7D22372E5726542DAF84134279643F8297

Wednesday 11 August 2021

dnsresolver.py: Videos For Each Command

Filed under: My Software,Networking,video — Didier Stevens @ 0:00

I did record 8 videos explaining the different commands of my dnsresolver.py tool.

This is a tool that can serve files, facilitate exfiltration, do tracking, answer wildcard requests, do rcode testing and also simple resolving.

I have a YouTube playlist with all 8 videos: dnsresolver playlist.

Friday 16 July 2021

sysmon’s DNS QueryStatus Field

Filed under: Networking — Didier Stevens @ 0:00

A friend asked me for more info on the QueryStatus field in sysmon‘s DNS events.

When a DNS query succeeds, e.g., when there’s a DNS reply with an answer, that status field is 0.

But what can cause it to be different from 0?

A bit of testing revealed that a query for an unknown domain gives a QueryStatus value of 9003. 9003 is a Windows System Error Code for DNS. And the rcode for NXDOMAIN is 3. So maybe the QueryStatus value is the rcode value plus 9000.

I added a feature to my dnsresolver.py script, that allows me to choose the rcode I want to receive. It works with this command-line:

dnsresolver.py “type=rcode,label=rcodetest”

And then I can just do DNS queries for a hostname like this:

4.rcodetest.example.com.

When my dnsresolver replies to such a query, it will send a reply without answer and with rcode equal to 4 (because the first label of the DNS query is 4). This allows me to quickly test different rcodes:

And this does indeed confirm that QueryStatus is equal to the rcode (greater than 0) plus 9000.

If the rcode is 0, the QueryStatus is 0, unless there is no answer in the DNS reply. Then the QueryStatus is 9501:

FYI: to test this, I configured a Windows VM with DNS server IP = 127.0.0.1, ran sysmon and dnsresolver.py inside that VM and did ping requests (I didn’t use nslookup, because that tool talks directly to the DNS server, it doesn’t use the Windows DNS client service).

Thursday 15 July 2021

New Tool: dnsresolver.py

Filed under: My Software,Networking — Didier Stevens @ 0:00

I’ve done several experiments with DNS, which has lead me over the last couple of years to develop a DNS resolver tool.

By no way is it a full fledged DNS server: it implements particular features that I’ve needed for different experiments I conducted.

It can serve files, facilitate exfiltration, do tracking, answer wildcard requests, do rcode testing and also simple resolving.

Upcoming blog posts will go into more details for some of these features.

Example of payload command: serving a file over DNS TXT records
dnsresolver_V0_0_1.zip (https)
MD5: 340C7324EB66EB4F567B38F374DD2564
SHA256: 56AD87585FDCC20C219BF4A27D9640ECD563E4155816990AB4E7B85AAFA5F047

Monday 19 April 2021

Lua CSV Wireshark Dissector

Filed under: My Software,Networking,Wireshark — Didier Stevens @ 0:00

In December 2020 I provided online Wireshark training to one of our NVISO clients. During the second day, when we cover the development of custom dissectors written in Lua, a question about CSV data came up. When the data exchanged over TCP, for example, has the CSV format (fields separated by a separator), how can I write a dissector for that?

While answering the question, I realized that this is a case that could be solved with a generic dissector. And the same night, I developed the first version.

Say you have a packet capture with a TCP connection. And the data exchanged over TCP consists of different fields, separated by a separator character.

Like this example:

Because Wireshark does not recognize the protocol used in this TCP connection, the content is just displayed as data.

With Lua dissector csv-dissector.lua, the data is dissected into different fields:

The separator character (pipe character | in this example) is something that can be configured:

Other changes can be made, but these have to be made in the code of the dissector itself:

  • Changing the port
  • Changing the number of fields
  • Change the name of the fields

 

Download:

csv_dissector_V0_0_2.zip (https)

MD5: E8CCE089FB0574775AB39DADED3B7AA2

SHA256: 5C8DC0F2BB97AA660E2576B23379B6F12FB88126F0EFC7A2F69E76EBA8E782BD

Saturday 27 March 2021

FileZilla Uses PuTTY’s Registry Fingerprint Cache

Filed under: Encryption,Forensics,Networking — Didier Stevens @ 10:01

Today I figured out that FileZilla uses PuTTY‘s registry key (HKCU\SOFTWARE\SimonTatham\PuTTY\SshHostKeys) to cache SSH fingerprints.

This morning, I connected to my server over SFTP with FileZilla, and got this prompt:

That’s unusual. I logged in over SSH, and my SSH client did not show a warning. I checked the fingerprint on my server, and it matched the one presented by FileZilla.

What’s going on here? I started to search through FileZilla configuration files (XML files) looking for the cached fingerprints, and found nothing. Then I went to the registry, but there’s no FileZilla entry under my HKCU Software key.

Then I’m taking a look with ProcMon to figure out where FileZilla caches its fingerprints. After some searching, I found the answer:

FileZilla uses PuTTY’s registry keys!

And indeed, when I start FileZilla again and allow it to cache the key, it appears in PuTTY’s registry keys.

One last check: I modified the registry entry and started FileZilla again:

And now FileZilla warns me that the key is different. That confirms that FileZilla reads and writes PuTTY’s registry fingerprint cache.

So that answered my question: “Why did FileZilla warn me this morning?” “Because the key was not cached”.

But then I was left with another question: “Why is the key no longer cached, because it was cached?”

Well, I started to remember that some days ago today, I had been experimenting with PuTTY’s registry keys. I most likely deleted that key (PuTTY is not my default SSH client). I verified the last-write timestamp for PuTTY’s registry key, and indeed, 4 days ago it was last written to.

Update:

Thanks to Nicolas for pointing out that fzsftp is based on PuTTY:

Friday 12 March 2021

Quickpost: “ProxyLogon PoC” Capture File

Filed under: Forensics,Networking,Quickpost,Vulnerabilities — Didier Stevens @ 18:43

I was able to get the “ProxyLogon PoC” Python script running against a vulnerable Exchange server in a VM. It required some tweaks to the code, and also a change in Exchange permissions, as explained in this tweet by @irsdl.

I created a capture file:

More details will follow.

Update: I added a second capture file (proxylogon-poc-capture-with-keys-and-webshell.pcapng), this one includes a request to the webshell that was installed.

proxylogon-poc-capture-with-keys_V2.zip (https)
MD5: A005AC9CCE0F833C99B5113E79005C7D
SHA256: AA092E099141F8A09F62C3529D8B27624CD11FF348738F78CA9A1E657F999755


Quickpost info


Monday 11 January 2021

Decrypting TLS Streams With Wireshark: Part 3

Filed under: Encryption,Networking — Didier Stevens @ 0:00

Say that you have to share a decrypted TLS stream, like the stream we decrypted in part 1.

You did a forensic investigation, and you need to included the decrypted TLS stream in your findings. Or you are troubleshooting an issue, and need need to share the decrypted TLS stream with a vendor.

I’m sure you don’t want to share the web server’s private key with a vendor (remember, in part 1, we used a web server’s private key to decrypt a TLS stream, while in part 2 we used a client’s SSLKEYLOGFILE).

If you would have the necessary secrets in a SSLKEYLOGFILE, you would be able to share that. Because those keys only apply to that particular TLS stream, they are useless for other TLS streams.

Such a file with secrets can be generated by Wireshark, when you have the capture file open together with the server’s private key file.

I use option “Export TLS Session Keys”:

The content of the file that was created (tls.keys) looks very similar to the SSLKEYLOGFILE we generated in part 2:

A small difference here, is that the RSA secret includes the master key in stead of the pre-master key.

This file can now be shared (together with the capture file) with third parties, without revealing the web server’s private key. They can then use it like explained in part 2.

 

To make life easier for the recipients of your capture file with secrets file, you can also merge both files together: embedding the secrets into the pcapng file. This way, they don’t have to configure secrets files in Wireshark, just opening the pcapng file is sufficient for the TLS traffic to be decrypted.

This embedding can be done with editcap’s –embed–secrets option:

The type of secret we want to inject is TLS. The tls.keys file (or the SSLKEYLOGFILE files from part 2) is injected like this into pcapng file capture-1.pcapng:

“c:\Program Files\Wireshark\editcap.exe” –inject-secrets tls,export.keys capture-1.pcapng capture-1-with-keys.pcapng

The resulting file, capture-1-with-keys.pcapng can then be opened in any instance of Wireshark, and the TLS traffic will be decrypted automatically, without having to change the configuration for the TLS protocol:

Embedding secrets is only possible with the pcapng format, because that format has a record type specific for secrets:

This is not possible with the older pcap format.

You can also created a pcap file with only the traffic you want to share, and nothing more. Use a display filter to select the traffic you want to share, and then export the specified packets:

And then you can open this filtered capture file, and generate TLS keys only for the traffic you want to share.

 

A typical Wireshark installation comes with a command-line version too: tshark. tshark uses the same settings as Wireshark. Thus if you defined a secrets file to decrypt TLS in Wireshark, tshark will also be able to do the decryption (-Y http is a display filter for http):

While if nothing is configured to do the decryption in Wireshark, tshark won’t be able to decrypt:

A final tip I want to share: starting with Python 3.8, python supports SSLKEYLOGFILE too (it uses a version of openssl that supports this).

 

Previous blog posts:

Decrypting TLS Streams With Wireshark: Part 1

Decrypting TLS Streams With Wireshark: Part 2

Next Page »

Blog at WordPress.com.