Threat Level: green Handler on Duty: Brad Duncan

SANS ISC: SANS Internet Storm Center SANS Internet Storm Center

Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

Latest Diaries

Fun with NMAP NSE Scripts and DOH (DNS over HTTPS)

Published: 2021-01-25
Last Updated: 2021-01-25 17:49:00 UTC
by Rob VandenBrink (Version: 1)
0 comment(s)

DOH (DNS over HTTPS) has been implemented into the various browsers over the last year or so, and there's a fair amount of support for it on public DNS services.  Because it's encrypted and over TCP, the mantra of "because privacy" has carried the day it looks like.  But why do network and system admins hate it so?

First of all, any name resolution that goes outside the organization, especially if it's encrypted, can't be easily logged.  I get that this is the entire point, but there are several attacks that can be prevented with simple DNS monitoring and sink-holing (blocking known malicious domains), and several attacks that can be mounted using just DNS (delivering malware via DNS TXT records for instance).   

What about DNS Tunneling you ask?  DNS tunnelling over DOH seems like a bit of a silly exercise - unless you're decrypting at your perimeter, DNS tunnelling over DOH is just going to look like HTTPS - you might as well just use HTTPS.

Why do privacy advocates tend to lose this debate at work?

For starters, the expecation of 100% privacy, but then the desire to hold IT and Security folks accountable for any breach or security incident, while you've got their hands tied doesn't hold water.  Especially for decryption, most organizations have broad exceptions by category - for instance, most organizations will not decrypt or inspect banking or financial information, interaction with government sites (taxes and so on), or healthcare sites of any kind.  Believe me, we don't want your banking password any more than we want your AD password!  So out of the gate, both the written and technical policies around decryption for most organizations focus on the individual's privacy, the goal is normally to protect against malware and attacks, HR violations (adult sites for instance), and illegal activity that could put the organization in jeopardy.

Also, the phrase "epxectation of privacy" is key here.  If you are at work, you don't usually have that - you're using the organizations systems and resources, and going about the business of the organization, and you've likely signed an Acceptable Use Policy (or something that covers that same ground) to that effect.  This protects you in that it defines what monitoring the company has, and protects the company in case any of it's employees do anything illegal while at work.  Note that I am not a Lawyer, nor do I play one on TV .. but I have been involved in more than a few "illegal stuff at work" cases over the years (thankfully not as a direct participant) - this stuff is important for both the company and the individuals!

So, with all the politics done, what does a DOH request look like?  The simple approach is to use the dns-json method, as outlined below - it'll save you base64 encoding the requests.  Let's start with a raw request in curl, then refine it a bit:

json formatted data:

curl -s -H 'accept: application/dns-json' ''

Looks pretty straightforward - very much like any API that you might be used to.  DOH is an HTTPS request like any other, but with a specific user-agent string and a specific path on the target server (dns-query).  This raw output is great if you're a python script, but let's fix up the formatting a bit so it's a bit more "human readable"

curl -s -H 'accept: application/dns-json' '' | jq
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": false,
  "CD": false,
  "Question": [
      "name": "",
      "type": 28
  "Answer": [
      "name": "",
      "type": 5,
      "TTL": 3597,
      "data": ""
      "name": "",
      "type": 5,
      "TTL": 297,
      "data": ""
      "name": "",
      "type": 5,
      "TTL": 21597,
      "data": ""
      "name": "",
      "type": 5,
      "TTL": 3597,
      "data": ""
      "name": "",
      "type": 28,
      "TTL": 17,
      "data": "2600:1408:5c00:388::b33"
      "name": "",
      "type": 28,
      "TTL": 17,
      "data": "2600:1408:5c00:3bc::b33"

now with just the data values parsed out:

curl -s -H 'accept: application/dns-json' '' | jq | grep data | tr -s " " | cut -d " " -f 3 | tr -d \"

This is all well and good for a shell script, but if you need to test more servers, what other tools can you use?  With the emphasis on script and multiple, I wrote a short NSE script for NMAP that will make arbitrary DOH requests:

First of all, the syntax is:

nmap -p433 <target> --script=dns-doh <DNS server> --script-args query=<query type>,target=<DNS lookup value>

>nmap -p 443 --script=dns-doh --script-args query=A,

Starting Nmap 7.80 ( ) at 2021-01-25 12:04 Eastern Standard Time

Nmap scan report for (

Host is up (0.027s latency).



443/tcp open  https

| dns-doh:

|   Answer:


|       type: 1

|       name:

|       TTL: 7

|       data:


|       type: 1

|       name:

|       TTL: 7

|       data:

|   AD: false

|   Status: 0

|   RA: true

|   Question:


|       type: 1

|       name:
|   CD: false
|   RD: true
|_  TC: false

Nmap done: 1 IP address (1 host up) scanned in 9.08 seconds

Looking at the code (comments are in-line), after all the setup and syntax checking, this is essentially a 3 line script:

local nmap = require "nmap"

local shortport = require "shortport"

local http = require "http"

local stdnse = require "stdnse"

local string = require "string"

local table = require "table"

local json = require "json"

local strbuf = require "strbuf"


description = [[

Performs a DOH lookup against the target site

variables: t = <target of dns query>

           q = <dns query type>



-- @usage

-- nmap <target> --script=doh <DNS server> --script-args query=<query type>,target=<DNS lookup value>


-- @output

-- 443/tcp open   https

-- | results of query



author = {"Rob VandenBrink",""}

license = "Creative Commons"

categories = { "discovery" }

portrule = shortport.http

action = function(host,port)

     -- collect the command line arguments

     local query = stdnse.get_script_args('query')

     local target = stdnse.get_script_args('target')

     -- input checking - check that both arg values are present and non-zero

     if(query==nil or query == '') then

         return "DNS query operation is not defined (A,AAAA,MX,PTR,TXT etc)"


     if(target==nil or target=='') then

         return "DNS target is not defined (host, domain, IP address etc)"


     -- construct the query string, the path in the DOH HTTPS GET

     local qstring = '/dns-query?name=''&type='..query

     -- define the header value (which defines the output type)

     local options = {header={}}

     options['header']['accept'] = 'application/dns-json'

     -- Get some DOH answers!

     local response = http.get(host.ip, port.number, qstring, options)

     -- convert results to JSON for more legible output

     local stat, resp =json.parse(response.body)

     return resp



The dns-doh.nse script is available and is maintained at:

If you find any issues with this code, by all means use our comment section to report them, or ping me via git

Rob VandenBrink

0 comment(s)

If you have more information or corrections regarding our diary, please share.

Recent Diaries

Video: Doc & RTF Malicious Document
Jan 24th 2021
1 day ago by DidierStevens (0 comments)

CyberChef: Analyzing OOXML Files for URLs
Jan 23rd 2021
2 days ago by DidierStevens (0 comments)

Another File Extension to Block in your MTA: .jnlp
Jan 22nd 2021
3 days ago by Xme (0 comments)

Powershell Dropping a REvil Ransomware
Jan 21st 2021
4 days ago by Xme (0 comments)

Qakbot activity resumes after holiday break
Jan 20th 2021
5 days ago by Brad (0 comments)

Gordon for fast cyber reputation checks
Jan 19th 2021
6 days ago by Russ McRee (0 comments)

View All Diaries →

Latest Discussions

created Dec 23rd 2020
1 month ago by (3 replies)

Port 23 & 2323
created Nov 15th 2020
2 months ago by Anonymous (0 replies)

Gmail hacked vis MS Outlook / virus/malware
created Oct 13th 2020
3 months ago by Anonymous (3 replies)

Why is the entire community so... I don't know the words...
created Sep 8th 2020
4 months ago by Everseeker (0 replies)

I can not find the Bluetooth channel!
created Aug 31st 2020
4 months ago by Martin (0 replies)

View All Forums →

Latest News

Top Diaries

An infection from Rig exploit kit
Jun 17th 2019
1 year ago by Brad (0 comments)

Old Worm But New Obfuscation Technique
Nov 13th 2020
2 months ago by Xme (0 comments)

Is IP testing Access to
Dec 5th 2020
1 month ago by Guy (0 comments)

AV Cleaned Maldoc
Nov 2nd 2020
2 months ago by DidierStevens (0 comments)

Traffic Analysis Quiz:
Oct 16th 2020
3 months ago by Brad (0 comments)