iagox86 / dnscat2

BSD 3-Clause "New" or "Revised" License
3.4k stars 599 forks source link

Query Name Minimisation - RFC 7816 #144

Open kazkansouh opened 5 years ago

kazkansouh commented 5 years ago

Hello, I have trying out dnscat2 in a lab environment and have observed when an iterative query is performed by bind (9.14.3 installed from Alpine 3.10) the client will fail to establish a tunnel.

After looking into the problem, it appears that bind 9.14 ships with Query Name Minimisation feature as defined by RFC 7816 enabled by default. More information.

Essentially, bind is making a number of A queries of the form _.example.com (where dnscat server it authoritative for example.com). E.g. if the client wants 1234.1234.1234.example.com, bind will make the following requests for A and AAAA RRs

Sadly, dnscat2 does not expect this and results only rejecting the first query that it is authoritative for (_.example.com) as not found and ignoring later requests.

A non invasive workaround to the problem is adding a dummy dns server that is authoritative for the same domain as dnscat2 but with no RRs and configuring dnscat2 to proxy requests to it (i.e. it will reject anything that dnscat2 can process). Alternatively, disabling qname minimisation on the server would be acceptable.

iagox86 commented 5 years ago

Interesting, I hadn't heard of this before!

On Wed, Jul 17, 2019 at 5:39 AM Karim Kanso notifications@github.com wrote:

Hello, I have trying out dnscat2 in a lab environment and have observed when an iterative query is performed by bind (9.14.3 installed from Alpine 3.10) the client will fail to establish a tunnel.

After looking into the problem, it appears that bind 9.14 ships with Query Name Minimisation feature as defined by RFC 7816 enabled by default. More information https://www.isc.org/blogs/qname-minimization-and-privacy/.

Essentially, bind is making a number of A queries of the form _. example.com (where dnscat server it authoritative for example.com). E.g. if the client wants 1234.1234.1234.example.com, bind will make the following requests for A and AAAA RRs

  • _.com
  • _.example.com
  • _.1234.example.com
  • etc

Sadly, dnscat2 does not expect this and results only rejecting the first query that it is authoritative for (_.example.com) as not found and ignoring later requests.

A non invasive workaround to the problem is adding a dummy dns server that is authoritative for the same domain as dnscat2 but with no RRs and configuring dnscat2 to proxy requests to it (i.e. it will reject anything that dnscat2 can process). Alternatively, disabling qname minimisation on the server would be acceptable.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/iagox86/dnscat2/issues/144?email_source=notifications&email_token=AAEAQTEUBPYACMDSI7J427LP74HGLA5CNFSM4IEP4W4KYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4G7W6PDA, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEAQTAIGU2VYT7DERJEGWLP74HGLANCNFSM4IEP4W4A .

kazkansouh commented 5 years ago

I've taken a deeper look into this issue. It appears what is needed in dnscat2 for it to work reliably with latest versions of bind is for it to:

  1. Reply to NS requests for its domain with its own address.
  2. Send "Not Found" reply for A/AAAA requests within the domain its authoritative for instead of silently ignoring them or using the passthrough function.
  3. Include an authoritative nameserver in the "Not Found" reply (I guess this would not hurt being in all replies).

It might be possible to ignore point 3 and instead change point 1 to "reply to NS requests for any sub domain with its own address". This is because the algorithm presented in RFC 7816 does not distinguish between these two.

Alas, I dont have any experience with ruby so I am not sure whether I have the time to put together a PR. Instead, I have included some analysis below in the hope that it will be of some use and is not lost.

Examples

To better demonstrate the issue a topology was created in GNS3 which was used for Wireshark captures. The Topology is as below (dns-C1 will be performing the iterative query and dns-isp is the authoritative root):

dnscat2-topology

The FQDN of the dnscat server is dnscat2.c2.site.

In the following, all captures were performed on the link between dns-C1 and SW1 with the cache on dns-C1 empty. The colouring of the captures shows the remote party:

Scenario 1

The first scenario is when dns-C1 is configured with qname-minimization disabled. It works as expected:

dnscat2-working

Scenario 2 (nominal)

The second scenario is when dns-C1 is configured with qname-minimization relxed (the default configuration). The dnscat2 server fails to answer any but the first request for A _.domain. bind will end up sending ServFail to the dnscat2 client after a timeout.

dnscat2-qname-min

Scenario 3 (dummy passthrough)

Third scenario is when dnscat server is configured to pass through requests to a 3rd dns server that has no resource records configured. I.e. it will send "Not Found" for any request. This appears to work, however it will fail when qname-minimization strict is configured.

dnscat2-working-passthrough

Scenario 4 (strict RFC 7816)

When qname-minimization strict is configured in bind it will not request the A _.domain records, and instead request NS resource records or reading the nameserver from the SOA in cases where the NS is not defined for a given domain. This is important as is the bind manual suggest this option may become the default in the future.

I was unable to configure a dummy bind server that is used as a pass through for dnscat to provide the correct responses as the authoritative name servers section of the response is not copied across. Thus I believe there is no workaround in this case.

dnscat2-strict-passthrough