1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 06:01:28 +00:00

o Added dns-safe-recursion-port and dns-safe-recursion-txid (non

default NSE scripts) which use the 3rd party dns-oarc.net to test
  the source port and transaction ID randomness of a discovered DNS
  server (assuming it allows recursion at all).  These scripts were
  contributed by Brandon Enright.
This commit is contained in:
fyodor
2008-09-05 02:04:07 +00:00
parent 1db6d9a977
commit 2ba3a3878d
4 changed files with 358 additions and 0 deletions

View File

@@ -1,5 +1,11 @@
# Nmap Changelog ($Id$); -*-text-*- # Nmap Changelog ($Id$); -*-text-*-
o Added dns-safe-recursion-port and dns-safe-recursion-txid (non
default NSE scripts) which use the 3rd party dns-oarc.net to test
the source port and transaction ID randomness of a discovered DNS
server (assuming it allows recursion at all). These scripts were
contributed by Brandon Enright.
o Added some Windows and MinGW compatibility patches submitted by o Added some Windows and MinGW compatibility patches submitted by
Gisle Vanem. Gisle Vanem.

View File

@@ -0,0 +1,172 @@
id = "DNS source port randomness"
description = "Queries porttest.dns-oarc.net to check for the predictable-port DNS recursion vulnerability. Predictable source ports can make a DNS server vulnerable to cache poisoning attacks (CVE-2008-1447)"
license = "Script: Same as Nmap--See http://nmap.org/book/man-legal.html\n" ..
"porttest.dns-oarc.net: https://www.dns-oarc.net/oarc/services/porttest"
author = "Script: Brandon Enright <bmenrigh@ucsd.edu>\n" ..
"porttest.dns-oarc.net: Duane Wessels <wessels@dns-oarc.net>"
-- This script uses (with permission) Duane Wessels' porttest.dns-oarc.net
-- service. Duane/OARC believe the service is valuable to the community
-- and have no plans to ever turn the service off.
-- The likely long-term availability makes this script a good candidate
-- for inclusion in Nmap proper.
categories = {"intrusive"}
require "bit"
require "comm"
require "shortport"
portrule = shortport.portnumber(53, "udp")
action = function(host, port)
-- TXID: 0xbeef
-- Flags: 0x0100
-- Questions: 1
-- Answer RRs: 0
-- Authority RRs: 0
-- Additional RRs: 0
-- Query:
-- Name: porttest, dns-oarc, net
-- Type: TXT (0x0010)
-- Class: IN (0x0001)
local query = string.char( 0xbe, 0xef, -- TXID
0x01, 0x00, -- Flags
0x00, 0x01, -- Questions
0x00, 0x00, -- Answer RRs
0x00, 0x00, -- Authority RRs
0x00, 0x00, -- Additional RRs
0x08) .. "porttest" ..
string.char( 0x08) .. "dns-oarc" ..
string.char( 0x03) .. "net" ..
string.char( 0x00, -- Name terminator
0x00, 0x10, -- Type (TXT)
0x00, 0x01) -- Class (IN)
-- This doesn't work without the bytes= setting...
local status, result = comm.exchange(host, port, query, {proto="udp",
bytes=1,
timeout=20000})
-- Fail gracefully
if not status then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: TIMEOUT"
else
return
end
end
-- Update the port
nmap.set_port_state(host, port, "open")
-- Now we need to "parse" the results to check to see if they are good
-- We need a minimum of 5 bytes...
if (string.len(result) < 5) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Malformed response"
else
return
end
end
-- Check TXID
if (string.byte(result, 1) ~= 0xbe
or string.byte(result, 2) ~= 0xef) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Invalid Transaction ID"
else
return
end
end
-- Check response flag and recursion
if not (bit.band(string.byte(result, 3), 0x80) == 0x80
and bit.band(string.byte(result, 4), 0x80) == 0x80) then
if (nmap.verbosity() >= 1 or nmap.debugging() >= 1) then
return "ERROR: Server refused recursion"
else
return
end
end
-- Check error flag
if (bit.band(string.byte(result, 4), 0x0F) ~= 0x00) then
if (nmap.verbosity() >= 1 or nmap.debugging() >= 1) then
return "ERROR: Server failure"
else
return
end
end
-- Check for two Answer RRs and 1 Authority RR
if (string.byte(result, 5) ~= 0x00
or string.byte(result, 6) ~= 0x01
or string.byte(result, 7) ~= 0x00
or string.byte(result, 8) ~= 0x02) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Response did not include expected answers"
else
return
end
end
-- We need a minimum of 128 bytes...
if (string.len(result) < 128) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Truncated response"
else
return
end
end
-- Here is the really fragile part. If the DNS response changes
-- in any way, this won't work and will fail.
-- Jump to second answer and check to see that it is TXT, IN
-- then grab the length and display that text...
-- Check for TXT
if (string.byte(result, 118) ~= 0x00
or string.byte(result, 119) ~= 0x10)
then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Answer record not of type TXT"
else
return
end
end
-- Check for IN
if (string.byte(result, 120) ~= 0x00
or string.byte(result, 121) ~= 0x01) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Answer record not of type IN"
else
return
end
end
-- Get TXT length
local txtlen = string.byte(result, 128)
-- We now need a minimum of 128 + txtlen bytes + 1...
if (string.len(result) < 128 + txtlen) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Truncated response"
else
return
end
end
-- GET TXT record
local txtrd = string.sub(result, 129, 128 + txtlen)
return txtrd
end

View File

@@ -0,0 +1,172 @@
id = "DNS TXID randomness"
description = "Queries txidtest.dns-oarc.net to check for the predictable-TXID DNS recursion vulnerability. Predictable TXID values can make a DNS server vulnerable to cache poisoning attacks (CVE-2008-1447)"
license = "Script: Same as Nmap--See http://nmap.org/book/man-legal.html\n" ..
"txidtest.dns-oarc.net: https://www.dns-oarc.net/oarc/services/txidtest"
author = "Script: Brandon Enright <bmenrigh@ucsd.edu>\n" ..
"txidtest.dns-oarc.net: Duane Wessels <wessels@dns-oarc.net>"
-- This script uses (with permission) Duane Wessels' txidtest.dns-oarc.net
-- service. Duane/OARC believe the service is valuable to the community
-- and have no plans to ever turn the service off.
-- The likely long-term availability makes this script a good candidate
-- for inclusion in Nmap proper.
categories = {"intrusive"}
require "bit"
require "comm"
require "shortport"
portrule = shortport.portnumber(53, "udp")
action = function(host, port)
-- TXID: 0xbabe
-- Flags: 0x0100
-- Questions: 1
-- Answer RRs: 0
-- Authority RRs: 0
-- Additional RRs: 0
-- Query:
-- Name: txidtest, dns-oarc, net
-- Type: TXT (0x0010)
-- Class: IN (0x0001)
local query = string.char( 0xba, 0xbe, -- TXID
0x01, 0x00, -- Flags
0x00, 0x01, -- Questions
0x00, 0x00, -- Answer RRs
0x00, 0x00, -- Authority RRs
0x00, 0x00, -- Additional RRs
0x08) .. "txidtest" ..
string.char( 0x08) .. "dns-oarc" ..
string.char( 0x03) .. "net" ..
string.char( 0x00, -- Name terminator
0x00, 0x10, -- Type (TXT)
0x00, 0x01) -- Class (IN)
-- This doesn't work without the bytes= setting...
local status, result = comm.exchange(host, port, query, {proto="udp",
bytes=1,
timeout=20000})
-- Fail gracefully
if not status then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: TIMEOUT"
else
return
end
end
-- Update the port
nmap.set_port_state(host, port, "open")
-- Now we need to "parse" the results to check to see if they are good
-- We need a minimum of 5 bytes...
if (string.len(result) < 5) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Malformed response"
else
return
end
end
-- Check TXID
if (string.byte(result, 1) ~= 0xba
or string.byte(result, 2) ~= 0xbe) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Invalid Transaction ID"
else
return
end
end
-- Check response flag and recursion
if not (bit.band(string.byte(result, 3), 0x80) == 0x80
and bit.band(string.byte(result, 4), 0x80) == 0x80) then
if (nmap.verbosity() >= 1 or nmap.debugging() >= 1) then
return "ERROR: Server refused recursion"
else
return
end
end
-- Check error flag
if (bit.band(string.byte(result, 4), 0x0F) ~= 0x00) then
if (nmap.verbosity() >= 1 or nmap.debugging() >= 1) then
return "ERROR: Server failure"
else
return
end
end
-- Check for two Answer RRs and 1 Authority RR
if (string.byte(result, 5) ~= 0x00
or string.byte(result, 6) ~= 0x01
or string.byte(result, 7) ~= 0x00
or string.byte(result, 8) ~= 0x02) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Response did not include expected answers"
else
return
end
end
-- We need a minimum of 128 bytes...
if (string.len(result) < 128) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Truncated response"
else
return
end
end
-- Here is the really fragile part. If the DNS response changes
-- in any way, this won't work and will fail.
-- Jump to second answer and check to see that it is TXT, IN
-- then grab the length and display that text...
-- Check for TXT
if (string.byte(result, 118) ~= 0x00
or string.byte(result, 119) ~= 0x10)
then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Answer record not of type TXT"
else
return
end
end
-- Check for IN
if (string.byte(result, 120) ~= 0x00
or string.byte(result, 121) ~= 0x01) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Answer record not of type IN"
else
return
end
end
-- Get TXT length
local txtlen = string.byte(result, 128)
-- We now need a minimum of 128 + txtlen bytes + 1...
if (string.len(result) < 128 + txtlen) then
if (nmap.verbosity() >= 2 or nmap.debugging() >= 1) then
return "ERROR: Truncated response"
else
return
end
end
-- GET TXT record
local txtrd = string.sub(result, 129, 128 + txtlen)
return txtrd
end

View File

@@ -3,6 +3,9 @@ Entry{ category = "intrusive", filename = "dns-test-open-recursion.nse" }
Entry{ category = "default", filename = "RealVNC_auth_bypass.nse" } Entry{ category = "default", filename = "RealVNC_auth_bypass.nse" }
Entry{ category = "malware", filename = "RealVNC_auth_bypass.nse" } Entry{ category = "malware", filename = "RealVNC_auth_bypass.nse" }
Entry{ category = "vuln", filename = "RealVNC_auth_bypass.nse" } Entry{ category = "vuln", filename = "RealVNC_auth_bypass.nse" }
Entry{ category = "intrusive", filename = "dns-safe-recursion-port.nse" }
Entry{ category = "intrusive", filename = "SNMPcommunitybrute.nse" }
Entry{ category = "auth", filename = "SNMPcommunitybrute.nse" }
Entry{ category = "default", filename = "showOwner.nse" } Entry{ category = "default", filename = "showOwner.nse" }
Entry{ category = "safe", filename = "showOwner.nse" } Entry{ category = "safe", filename = "showOwner.nse" }
Entry{ category = "default", filename = "SSLv2-support.nse" } Entry{ category = "default", filename = "SSLv2-support.nse" }
@@ -18,6 +21,7 @@ Entry{ category = "safe", filename = "rpcinfo.nse" }
Entry{ category = "discovery", filename = "rpcinfo.nse" } Entry{ category = "discovery", filename = "rpcinfo.nse" }
Entry{ category = "auth", filename = "bruteTelnet.nse" } Entry{ category = "auth", filename = "bruteTelnet.nse" }
Entry{ category = "intrusive", filename = "bruteTelnet.nse" } Entry{ category = "intrusive", filename = "bruteTelnet.nse" }
Entry{ category = "intrusive", filename = "dns-safe-recursion-txid.nse" }
Entry{ category = "default", filename = "SMTPcommands.nse" } Entry{ category = "default", filename = "SMTPcommands.nse" }
Entry{ category = "discovery", filename = "SMTPcommands.nse" } Entry{ category = "discovery", filename = "SMTPcommands.nse" }
Entry{ category = "safe", filename = "SMTPcommands.nse" } Entry{ category = "safe", filename = "SMTPcommands.nse" }
@@ -31,6 +35,7 @@ Entry{ category = "demo", filename = "chargenTest.nse" }
Entry{ category = "malware", filename = "strangeSMTPport.nse" } Entry{ category = "malware", filename = "strangeSMTPport.nse" }
Entry{ category = "version", filename = "iax2Detect.nse" } Entry{ category = "version", filename = "iax2Detect.nse" }
Entry{ category = "demo", filename = "showSMTPVersion.nse" } Entry{ category = "demo", filename = "showSMTPVersion.nse" }
Entry{ category = "discovery", filename = "ASN.nse" }
Entry{ category = "default", filename = "showHTMLTitle.nse" } Entry{ category = "default", filename = "showHTMLTitle.nse" }
Entry{ category = "demo", filename = "showHTMLTitle.nse" } Entry{ category = "demo", filename = "showHTMLTitle.nse" }
Entry{ category = "safe", filename = "showHTMLTitle.nse" } Entry{ category = "safe", filename = "showHTMLTitle.nse" }
@@ -56,6 +61,9 @@ Entry{ category = "discovery", filename = "finger.nse" }
Entry{ category = "demo", filename = "showHTTPVersion.nse" } Entry{ category = "demo", filename = "showHTTPVersion.nse" }
Entry{ category = "default", filename = "SSHv1-support.nse" } Entry{ category = "default", filename = "SSHv1-support.nse" }
Entry{ category = "safe", filename = "SSHv1-support.nse" } Entry{ category = "safe", filename = "SSHv1-support.nse" }
Entry{ category = "default", filename = "popcapa.nse" }
Entry{ category = "intrusive", filename = "brutePOP3.nse" }
Entry{ category = "auth", filename = "brutePOP3.nse" }
Entry{ category = "default", filename = "MySQLinfo.nse" } Entry{ category = "default", filename = "MySQLinfo.nse" }
Entry{ category = "discovery", filename = "MySQLinfo.nse" } Entry{ category = "discovery", filename = "MySQLinfo.nse" }
Entry{ category = "safe", filename = "MySQLinfo.nse" } Entry{ category = "safe", filename = "MySQLinfo.nse" }