mirror of
https://github.com/nmap/nmap.git
synced 2025-12-09 06:01:28 +00:00
Added tls-nextprotoneg, a script that enumerates a TLS server's supported protocols by using the next protocol negotiation extension.
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [NSE] Added tls-nextprotoneg script which enumerates a TLS server's supported
|
||||
protocols by using the next protocol negotiation extension.
|
||||
[Hani Benhabiles]
|
||||
|
||||
o [NSOCK] Fixed an epoll-engine-specific bug. The engine didn't recognized FDs
|
||||
that were internally closed and replaced by other ones. This happened during
|
||||
reconnect attempts. [Henri Doreau]
|
||||
|
||||
@@ -379,6 +379,7 @@ Entry { filename = "targets-traceroute.nse", categories = { "discovery", "safe",
|
||||
Entry { filename = "telnet-brute.nse", categories = { "brute", "intrusive", } }
|
||||
Entry { filename = "telnet-encryption.nse", categories = { "discovery", "safe", } }
|
||||
Entry { filename = "tftp-enum.nse", categories = { "discovery", "intrusive", } }
|
||||
Entry { filename = "tls-nextprotoneg.nse", categories = { "discovery", "safe", "default", } }
|
||||
Entry { filename = "traceroute-geolocation.nse", categories = { "discovery", "external", "safe", } }
|
||||
Entry { filename = "unusual-port.nse", categories = { "safe", } }
|
||||
Entry { filename = "upnp-info.nse", categories = { "default", "discovery", "safe", } }
|
||||
|
||||
171
scripts/tls-nextprotoneg.nse
Normal file
171
scripts/tls-nextprotoneg.nse
Normal file
@@ -0,0 +1,171 @@
|
||||
local shortport = require "shortport"
|
||||
local stdnse = require "stdnse"
|
||||
local table = require "table"
|
||||
local bin = require "bin"
|
||||
local os = require "os"
|
||||
|
||||
description = [[
|
||||
Enumerates a TLS server's supported protocols by using the next protocol negotiation extension.
|
||||
|
||||
This works by adding the next protocol negotiation extension in the client hello
|
||||
packet and looking for the presence of certain protocols in the server hello's
|
||||
NPN extension data.
|
||||
|
||||
For more information , see:
|
||||
* https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-03
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- nmap --script=tls-nextprotoneg <targets>
|
||||
--
|
||||
--@output
|
||||
-- 443/tcp open https
|
||||
-- | tls-nextprotoneg:
|
||||
-- | spdy/3
|
||||
-- | spdy/2
|
||||
-- |_ http/1.1
|
||||
|
||||
|
||||
author = "Hani Benhabiles"
|
||||
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
||||
categories = {"discovery", "safe", "default"}
|
||||
|
||||
portrule = shortport.ssl
|
||||
|
||||
|
||||
--- Function that sends a client hello packet with the TLS NPN extension to the
|
||||
-- target host and returns the response
|
||||
--@args host The target host table.
|
||||
--@args port The target port table.
|
||||
--@return status true if response, false else.
|
||||
--@return response if status is true.
|
||||
local client_hello = function(host, port)
|
||||
local sock, status, response, err, cli_h
|
||||
|
||||
-- Craft Client Hello
|
||||
-- Content Type: Client Handshake
|
||||
cli_h = bin.pack(">C", 0x16)
|
||||
-- Version: TLS 1.0
|
||||
cli_h = cli_h .. bin.pack(">S", 0x0301)
|
||||
-- Length, fixed
|
||||
cli_h = cli_h .. bin.pack(">S", 0x0037)
|
||||
-- Handshake protocol
|
||||
-- Handshake Type: Client Hello
|
||||
cli_h = cli_h .. bin.pack(">C", 0x01)
|
||||
-- Length, fixed
|
||||
cli_h = cli_h .. bin.pack(">CS", 0x00, 0x0033)
|
||||
-- Version: TLS 1.0
|
||||
cli_h = cli_h .. bin.pack(">S", 0x0301)
|
||||
-- Random: epoch time
|
||||
cli_h = cli_h .. bin.pack(">I", os.time())
|
||||
-- Random: random 28 bytes
|
||||
cli_h = cli_h .. stdnse.generate_random_string(28)
|
||||
-- Session ID length
|
||||
cli_h = cli_h .. bin.pack(">C", 0x00)
|
||||
-- Cipher Suites length
|
||||
cli_h = cli_h .. bin.pack(">S", 0x0006)
|
||||
-- Ciphers
|
||||
cli_h = cli_h .. bin.pack(">S", 0xc011)
|
||||
cli_h = cli_h .. bin.pack(">S", 0x0039)
|
||||
cli_h = cli_h .. bin.pack(">S", 0x0004)
|
||||
-- Compression Methods length
|
||||
cli_h = cli_h .. bin.pack(">C", 0x01)
|
||||
-- Compression Methods: null
|
||||
cli_h = cli_h .. bin.pack(">C", 0x00)
|
||||
-- Extensions length
|
||||
cli_h = cli_h .. bin.pack(">S", 0x0004)
|
||||
-- TLS NPN Extension
|
||||
cli_h = cli_h .. bin.pack(">I", 0x33740000)
|
||||
|
||||
-- Connect to the target server
|
||||
sock = nmap.new_socket()
|
||||
sock:set_timeout(5000)
|
||||
status, err = sock:connect(host, port)
|
||||
if not status then
|
||||
sock:close()
|
||||
stdnse.print_debug("Can't send: %s", err)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Send Client Hello to the target server
|
||||
status, err = sock:send(cli_h)
|
||||
if not status then
|
||||
stdnse.print_debug("Couldn't send: %s", err)
|
||||
sock:close()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Read response
|
||||
status, response = sock:receive()
|
||||
if not status then
|
||||
stdnse.print_debug("Couldn't receive: %s", err)
|
||||
sock:close()
|
||||
return false
|
||||
end
|
||||
|
||||
return true, response
|
||||
end
|
||||
|
||||
--- Function that checks for the returned protocols to a npn extension request.
|
||||
--@args response Response to parse.
|
||||
--@return results List of found protocols.
|
||||
local check_npn = function(response)
|
||||
local results = {}
|
||||
local shlength
|
||||
-- List of protocols supported by TLS NPN extension
|
||||
-- https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-03#section-7
|
||||
local protocols = {
|
||||
"spdy/3",
|
||||
"spdy/2",
|
||||
"spdy/1",
|
||||
"http/1.1",
|
||||
}
|
||||
|
||||
if not response then
|
||||
stdnse.print_debug(SCRIPT_NAME .. ": Didn't get response.")
|
||||
return results
|
||||
end
|
||||
-- If content type not handshake
|
||||
if string.sub(response,1,1) ~= string.char(22) then
|
||||
stdnse.print_debug(SCRIPT_NAME .. ": Response type not handshake.")
|
||||
return results
|
||||
end
|
||||
-- If handshake protocol not server hello
|
||||
if string.sub(response, 6, 6) ~= string.char(02) then
|
||||
stdnse.print_debug(SCRIPT_NAME .. ": Handshake response not server hello.")
|
||||
return results
|
||||
end
|
||||
|
||||
-- Get the server hello length
|
||||
_, shlength = bin.unpack(">S", response, 4)
|
||||
local serverhello = string.sub(response, 6, 6 + shlength)
|
||||
|
||||
-- If server didn't return TLS NPN extension
|
||||
if not string.find(serverhello, string.char(0x33) .. string.char(0x74)) then
|
||||
stdnse.print_debug(SCRIPT_NAME .. ": Server doesn't support TLS NPN extension.")
|
||||
return results
|
||||
end
|
||||
|
||||
-- Search for protocols in serverhello
|
||||
for _, protocol in pairs(protocols) do
|
||||
if string.find(serverhello, protocol) then
|
||||
table.insert(results, protocol)
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
local status, response
|
||||
|
||||
-- Send crafted client hello
|
||||
status, response = client_hello(host, port)
|
||||
if status and response then
|
||||
-- Analyze response
|
||||
local results = check_npn(response)
|
||||
return stdnse.format_output(true, results)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user