1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-11 02:09:03 +00:00

Tabs to spaces in ssl-enum-ciphers.

This commit is contained in:
david
2013-11-27 04:59:48 +00:00
parent 0f5e87c8be
commit 8ab92b3214

View File

@@ -123,10 +123,10 @@ categories = {"discovery", "intrusive"}
-- Most of the values in the tables below are from: -- Most of the values in the tables below are from:
-- http://www.iana.org/assignments/tls-parameters/ -- http://www.iana.org/assignments/tls-parameters/
PROTOCOLS = { PROTOCOLS = {
["SSLv3"] = 0x0300, ["SSLv3"] = 0x0300,
["TLSv1.0"] = 0x0301, ["TLSv1.0"] = 0x0301,
["TLSv1.1"] = 0x0302, ["TLSv1.1"] = 0x0302,
["TLSv1.2"] = 0x0303 ["TLSv1.2"] = 0x0303
} }
-- --
@@ -135,75 +135,75 @@ PROTOCOLS = {
TLS_RECORD_HEADER_LENGTH = 5 TLS_RECORD_HEADER_LENGTH = 5
TLS_CONTENTTYPE_REGISTRY = { TLS_CONTENTTYPE_REGISTRY = {
["change_cipher_spec"] = 20, ["change_cipher_spec"] = 20,
["alert"] = 21, ["alert"] = 21,
["handshake"] = 22, ["handshake"] = 22,
["application_data"] = 23 ["application_data"] = 23
} }
-- --
-- TLS Alert Levels -- TLS Alert Levels
-- --
TLS_ALERT_LEVELS = { TLS_ALERT_LEVELS = {
["warning"] = 1, ["warning"] = 1,
["fatal"] = 2, ["fatal"] = 2,
} }
-- --
-- TLS Alert Record Types -- TLS Alert Record Types
-- --
TLS_ALERT_REGISTRY = { TLS_ALERT_REGISTRY = {
["close_notify"] = 0, ["close_notify"] = 0,
["unexpected_message"] = 10, ["unexpected_message"] = 10,
["bad_record_mac"] = 20, ["bad_record_mac"] = 20,
["decryption_failed"] = 21, ["decryption_failed"] = 21,
["record_overflow"] = 22, ["record_overflow"] = 22,
["decompression_failure"] = 30, ["decompression_failure"] = 30,
["handshake_failure"] = 40, ["handshake_failure"] = 40,
["no_certificate"] = 41, ["no_certificate"] = 41,
["bad_certificate"] = 42, ["bad_certificate"] = 42,
["unsupported_certificate"] = 43, ["unsupported_certificate"] = 43,
["certificate_revoked"] = 44, ["certificate_revoked"] = 44,
["certificate_expired"] = 45, ["certificate_expired"] = 45,
["certificate_unknown"] = 46, ["certificate_unknown"] = 46,
["illegal_parameter"] = 47, ["illegal_parameter"] = 47,
["unknown_ca"] = 48, ["unknown_ca"] = 48,
["access_denied"] = 49, ["access_denied"] = 49,
["decode_error"] = 50, ["decode_error"] = 50,
["decrypt_error"] = 51, ["decrypt_error"] = 51,
["export_restriction"] = 60, ["export_restriction"] = 60,
["protocol_version"] = 70, ["protocol_version"] = 70,
["insufficient_security"] = 71, ["insufficient_security"] = 71,
["internal_error"] = 80, ["internal_error"] = 80,
["user_canceled"] = 90, ["user_canceled"] = 90,
["no_renegotiation"] = 100, ["no_renegotiation"] = 100,
["unsupported_extension"] = 110, ["unsupported_extension"] = 110,
["certificate_unobtainable"] = 111, ["certificate_unobtainable"] = 111,
["unrecognized_name"] = 112, ["unrecognized_name"] = 112,
["bad_certificate_status_response"] = 113, ["bad_certificate_status_response"] = 113,
["bad_certificate_hash_value"] = 114, ["bad_certificate_hash_value"] = 114,
["unknown_psk_identity"] = 115 ["unknown_psk_identity"] = 115
} }
-- --
-- TLS Handshake Record Types -- TLS Handshake Record Types
-- --
TLS_HANDSHAKETYPE_REGISTRY = { TLS_HANDSHAKETYPE_REGISTRY = {
["hello_request"] = 0, ["hello_request"] = 0,
["client_hello"] = 1, ["client_hello"] = 1,
["server_hello"] = 2, ["server_hello"] = 2,
["hello_verify_request"] = 3, ["hello_verify_request"] = 3,
["NewSessionTicket"] = 4, ["NewSessionTicket"] = 4,
["certificate"] = 11, ["certificate"] = 11,
["server_key_exchange"] = 12, ["server_key_exchange"] = 12,
["certificate_request"] = 13, ["certificate_request"] = 13,
["server_hello_done"] = 14, ["server_hello_done"] = 14,
["certificate_verify"] = 15, ["certificate_verify"] = 15,
["client_key_exchange"] = 16, ["client_key_exchange"] = 16,
["finished"] = 20, ["finished"] = 20,
["certificate_url"] = 21, ["certificate_url"] = 21,
["certificate_status"] = 22, ["certificate_status"] = 22,
["supplemental_data"] = 23 ["supplemental_data"] = 23
} }
-- --
@@ -211,9 +211,9 @@ TLS_HANDSHAKETYPE_REGISTRY = {
-- http://www.iana.org/assignments/comp-meth-ids -- http://www.iana.org/assignments/comp-meth-ids
-- --
COMPRESSORS = { COMPRESSORS = {
["NULL"] = 0, ["NULL"] = 0,
["DEFLATE"] = 1, ["DEFLATE"] = 1,
["LZS"] = 64 ["LZS"] = 64
} }
-- --
@@ -585,10 +585,10 @@ CIPHERS = {
} }
cipherstrength = { cipherstrength = {
["broken"] = 0, ["broken"] = 0,
["weak"] = 1, ["weak"] = 1,
["unknown strength"] = 2, ["unknown strength"] = 2,
["strong"] = 3 ["strong"] = 3
} }
local rankedciphers={} local rankedciphers={}
@@ -597,222 +597,222 @@ local rankedciphersfilename=false
local policy=true local policy=true
local function record_read(buffer, i) local function record_read(buffer, i)
local b, h, j, len local b, h, j, len
local function find_key(t, value) local function find_key(t, value)
local k, v local k, v
for k, v in pairs(t) do for k, v in pairs(t) do
if v == value then if v == value then
return k return k
end end
end end
return nil return nil
end end
------------ ------------
-- Header -- -- Header --
------------ ------------
-- Ensure we have enough data for the header. -- Ensure we have enough data for the header.
if #buffer - i < TLS_RECORD_HEADER_LENGTH then if #buffer - i < TLS_RECORD_HEADER_LENGTH then
return i, nil return i, nil
end end
-- Parse header. -- Parse header.
h = {} h = {}
j, h["type"] = bin.unpack("C", buffer, i) j, h["type"] = bin.unpack("C", buffer, i)
j, h["protocol"] = bin.unpack(">S", buffer, j) j, h["protocol"] = bin.unpack(">S", buffer, j)
j, h["length"] = bin.unpack(">S", buffer, j) j, h["length"] = bin.unpack(">S", buffer, j)
-- Ensure we have enough data for the body. -- Ensure we have enough data for the body.
len = j + h["length"] - 1 len = j + h["length"] - 1
if #buffer < len then if #buffer < len then
return i, nil return i, nil
end end
-- Convert to human-readable form. -- Convert to human-readable form.
h["type"] = find_key(TLS_CONTENTTYPE_REGISTRY, h["type"]) h["type"] = find_key(TLS_CONTENTTYPE_REGISTRY, h["type"])
h["protocol"] = find_key(PROTOCOLS, h["protocol"]) h["protocol"] = find_key(PROTOCOLS, h["protocol"])
---------- ----------
-- Body -- -- Body --
---------- ----------
b = {} b = {}
h["body"] = b h["body"] = b
if h["type"] == "alert" then if h["type"] == "alert" then
-- Parse body. -- Parse body.
j, b["level"] = bin.unpack("C", buffer, j) j, b["level"] = bin.unpack("C", buffer, j)
j, b["description"] = bin.unpack("C", buffer, j) j, b["description"] = bin.unpack("C", buffer, j)
-- Convert to human-readable form. -- Convert to human-readable form.
b["level"] = find_key(TLS_ALERT_LEVELS, b["level"]) b["level"] = find_key(TLS_ALERT_LEVELS, b["level"])
b["description"] = find_key(TLS_ALERT_REGISTRY, b["description"]) b["description"] = find_key(TLS_ALERT_REGISTRY, b["description"])
elseif h["type"] == "handshake" then elseif h["type"] == "handshake" then
-- Parse body. -- Parse body.
j, b["type"] = bin.unpack("C", buffer, j) j, b["type"] = bin.unpack("C", buffer, j)
local _ local _
j, _ = bin.unpack("A3", buffer, j) j, _ = bin.unpack("A3", buffer, j)
-- Convert to human-readable form. -- Convert to human-readable form.
b["type"] = find_key(TLS_HANDSHAKETYPE_REGISTRY, b["type"]) b["type"] = find_key(TLS_HANDSHAKETYPE_REGISTRY, b["type"])
if b["type"] == "server_hello" then if b["type"] == "server_hello" then
-- Parse body. -- Parse body.
j, b["protocol"] = bin.unpack(">S", buffer, j) j, b["protocol"] = bin.unpack(">S", buffer, j)
j, b["time"] = bin.unpack(">I", buffer, j) j, b["time"] = bin.unpack(">I", buffer, j)
j, b["random"] = bin.unpack("A28", buffer, j) j, b["random"] = bin.unpack("A28", buffer, j)
j, b["session_id_length"] = bin.unpack("C", buffer, j) j, b["session_id_length"] = bin.unpack("C", buffer, j)
j, b["session_id"] = bin.unpack("A" .. b["session_id_length"], buffer, j) j, b["session_id"] = bin.unpack("A" .. b["session_id_length"], buffer, j)
j, b["cipher"] = bin.unpack(">S", buffer, j) j, b["cipher"] = bin.unpack(">S", buffer, j)
j, b["compressor"] = bin.unpack("C", buffer, j) j, b["compressor"] = bin.unpack("C", buffer, j)
-- Convert to human-readable form. -- Convert to human-readable form.
b["protocol"] = find_key(PROTOCOLS, b["protocol"]) b["protocol"] = find_key(PROTOCOLS, b["protocol"])
b["cipher"] = find_key(CIPHERS, b["cipher"]) b["cipher"] = find_key(CIPHERS, b["cipher"])
b["compressor"] = find_key(COMPRESSORS, b["compressor"]) b["compressor"] = find_key(COMPRESSORS, b["compressor"])
end end
end end
-- Ignore unparsed bytes. -- Ignore unparsed bytes.
j = len j = len
return j, h return j, h
end end
local function record_write(type, protocol, b) local function record_write(type, protocol, b)
local h local h
h = "" h = ""
-- Set the header as a handshake. -- Set the header as a handshake.
h = h .. bin.pack("C", TLS_CONTENTTYPE_REGISTRY[type]) h = h .. bin.pack("C", TLS_CONTENTTYPE_REGISTRY[type])
-- Set the protocol. -- Set the protocol.
h = h .. bin.pack(">S", PROTOCOLS[protocol]) h = h .. bin.pack(">S", PROTOCOLS[protocol])
-- Set the length of the header body. -- Set the length of the header body.
h = h .. bin.pack(">S", #b) h = h .. bin.pack(">S", #b)
return h .. b return h .. b
end end
local function client_hello(t) local function client_hello(t)
local b, cipher, ciphers, compressor, compressors, h, len local b, cipher, ciphers, compressor, compressors, h, len
---------- ----------
-- Body -- -- Body --
---------- ----------
b = "" b = ""
-- Set the protocol. -- Set the protocol.
b = b .. bin.pack(">S", PROTOCOLS[t["protocol"]]) b = b .. bin.pack(">S", PROTOCOLS[t["protocol"]])
-- Set the random data. -- Set the random data.
b = b .. bin.pack(">I", os.time()) b = b .. bin.pack(">I", os.time())
-- Set the random data. -- Set the random data.
b = b .. string.rep("nmap", 7) b = b .. string.rep("nmap", 7)
-- Set the session ID. -- Set the session ID.
b = b .. bin.pack("C", 0) b = b .. bin.pack("C", 0)
-- Cipher suites. -- Cipher suites.
ciphers = "" ciphers = ""
if t["ciphers"] ~= nil then if t["ciphers"] ~= nil then
-- Add specified ciphers. -- Add specified ciphers.
for _, cipher in pairs(t["ciphers"]) do for _, cipher in pairs(t["ciphers"]) do
ciphers = ciphers .. bin.pack(">S", CIPHERS[cipher]) ciphers = ciphers .. bin.pack(">S", CIPHERS[cipher])
end end
else else
-- Add all known ciphers. -- Add all known ciphers.
for _, cipher in pairs(CIPHERS) do for _, cipher in pairs(CIPHERS) do
ciphers = ciphers .. bin.pack(">S", cipher) ciphers = ciphers .. bin.pack(">S", cipher)
end end
end end
b = b .. bin.pack(">S", #ciphers) b = b .. bin.pack(">S", #ciphers)
b = b .. ciphers b = b .. ciphers
-- Compression methods. -- Compression methods.
compressors = "" compressors = ""
if t["compressors"] ~= nil then if t["compressors"] ~= nil then
-- Add specified compressors. -- Add specified compressors.
for _, compressor in pairs(t["compressors"]) do for _, compressor in pairs(t["compressors"]) do
if compressor ~= "NULL" then if compressor ~= "NULL" then
compressors = compressors .. bin.pack("C", COMPRESSORS[compressor]) compressors = compressors .. bin.pack("C", COMPRESSORS[compressor])
end end
end end
compressors = compressors .. bin.pack("C", 0) -- Always include NULL as last choice compressors = compressors .. bin.pack("C", 0) -- Always include NULL as last choice
else else
-- Add all known compressors. -- Add all known compressors.
for _, compressor in pairs(COMPRESSORS) do for _, compressor in pairs(COMPRESSORS) do
compressors = compressors .. bin.pack("C", compressor) compressors = compressors .. bin.pack("C", compressor)
end end
end end
b = b .. bin.pack("C", #compressors) b = b .. bin.pack("C", #compressors)
b = b .. compressors b = b .. compressors
------------ ------------
-- Header -- -- Header --
------------ ------------
h = "" h = ""
-- Set type to ClientHello. -- Set type to ClientHello.
h = h .. bin.pack("C", TLS_HANDSHAKETYPE_REGISTRY["client_hello"]) h = h .. bin.pack("C", TLS_HANDSHAKETYPE_REGISTRY["client_hello"])
-- Set the length of the body. -- Set the length of the body.
len = bin.pack(">I", #b) len = bin.pack(">I", #b)
h = h .. bin.pack("CCC", len:byte(2), len:byte(3), len:byte(4)) h = h .. bin.pack("CCC", len:byte(2), len:byte(3), len:byte(4))
return record_write("handshake", t["protocol"], h .. b) return record_write("handshake", t["protocol"], h .. b)
end end
local function try_params(host, port, t) local function try_params(host, port, t)
local buffer, err, i, record, req, resp, sock, status local buffer, err, i, record, req, resp, sock, status
-- Create socket. -- Create socket.
sock = nmap.new_socket() sock = nmap.new_socket()
sock:set_timeout(5000) sock:set_timeout(5000)
status, err = sock:connect(host, port, "tcp") status, err = sock:connect(host, port, "tcp")
if not status then if not status then
stdnse.print_debug(1, "Can't connect: %s", err) stdnse.print_debug(1, "Can't connect: %s", err)
sock:close() sock:close()
return nil return nil
end end
-- Send request. -- Send request.
req = client_hello(t) req = client_hello(t)
status, err = sock:send(req) status, err = sock:send(req)
if not status then if not status then
stdnse.print_debug(1, "Can't send: %s", err) stdnse.print_debug(1, "Can't send: %s", err)
sock:close() sock:close()
return nil return nil
end end
-- Read response. -- Read response.
i = 0 i = 0
buffer = "" buffer = ""
record = nil record = nil
while true do while true do
status, resp = sock:receive() status, resp = sock:receive()
if not status then if not status then
sock:close() sock:close()
return nil return nil
end end
buffer = buffer .. resp buffer = buffer .. resp
-- Parse response. -- Parse response.
i, record = record_read(buffer, i) i, record = record_read(buffer, i)
if record ~= nil then if record ~= nil then
sock:close() sock:close()
return record return record
end end
end end
end end
local function keys(t) local function keys(t)
@@ -859,42 +859,42 @@ local function find_ciphers(host, port, protocol)
protocol_worked = false protocol_worked = false
for _, group in ipairs(ciphers) do for _, group in ipairs(ciphers) do
while (next(group)) do while (next(group)) do
-- Create structure. -- Create structure.
t = { t = {
["ciphers"] = group, ["ciphers"] = group,
["protocol"] = protocol ["protocol"] = protocol
} }
record = try_params(host, port, t) record = try_params(host, port, t)
if record == nil then if record == nil then
if protocol_worked then if protocol_worked then
stdnse.print_debug(2, "%d ciphers rejected. (No handshake)", #group) stdnse.print_debug(2, "%d ciphers rejected. (No handshake)", #group)
else else
stdnse.print_debug(1, "%d ciphers and/or protocol %s rejected. (No handshake)", #group, protocol) stdnse.print_debug(1, "%d ciphers and/or protocol %s rejected. (No handshake)", #group, protocol)
end end
break break
elseif record["protocol"] ~= protocol then elseif record["protocol"] ~= protocol then
stdnse.print_debug(1, "Protocol %s rejected.", protocol) stdnse.print_debug(1, "Protocol %s rejected.", protocol)
protocol_worked = nil protocol_worked = nil
break
elseif record["type"] == "alert" and record["body"]["description"] == "handshake_failure" then
protocol_worked = true
stdnse.print_debug(2, "%d ciphers rejected.", #group)
break break
elseif record["type"] ~= "handshake" or record["body"]["type"] ~= "server_hello" then elseif record["type"] == "alert" and record["body"]["description"] == "handshake_failure" then
stdnse.print_debug(2, "Unexpected record received.") protocol_worked = true
stdnse.print_debug(2, "%d ciphers rejected.", #group)
break break
else elseif record["type"] ~= "handshake" or record["body"]["type"] ~= "server_hello" then
protocol_worked = true stdnse.print_debug(2, "Unexpected record received.")
name = record["body"]["cipher"] break
stdnse.print_debug(2, "Cipher %s chosen.", name) else
protocol_worked = true
name = record["body"]["cipher"]
stdnse.print_debug(2, "Cipher %s chosen.", name)
remove(group, name) remove(group, name)
-- Add cipher to the list of accepted ciphers. -- Add cipher to the list of accepted ciphers.
table.insert(results, name) table.insert(results, name)
end end
end end
if protocol_worked == nil then return nil end if protocol_worked == nil then return nil end
end end
if not protocol_worked then return nil end if not protocol_worked then return nil end
@@ -956,17 +956,17 @@ local function find_compressors(host, port, protocol, good_cipher)
end end
local function try_protocol(host, port, protocol, upresults) local function try_protocol(host, port, protocol, upresults)
local ciphers, compressors, results local ciphers, compressors, results
local condvar = nmap.condvar(upresults) local condvar = nmap.condvar(upresults)
results = stdnse.output_table() results = stdnse.output_table()
-- Find all valid ciphers. -- Find all valid ciphers.
ciphers = find_ciphers(host, port, protocol) ciphers = find_ciphers(host, port, protocol)
if ciphers == nil then if ciphers == nil then
condvar "signal" condvar "signal"
return nil return nil
end end
if #ciphers == 0 then if #ciphers == 0 then
results = {ciphers={},compressors={}} results = {ciphers={},compressors={}}
@@ -977,11 +977,11 @@ local function try_protocol(host, port, protocol, upresults)
condvar "signal" condvar "signal"
return nil return nil
end end
-- Find all valid compression methods. -- Find all valid compression methods.
compressors = find_compressors(host, port, protocol, ciphers[1]) compressors = find_compressors(host, port, protocol, ciphers[1])
-- Add rankings to ciphers -- Add rankings to ciphers
local cipherstr local cipherstr
for i, name in ipairs(ciphers) do for i, name in ipairs(ciphers) do
if rankedciphersfilename and rankedciphers[name] then if rankedciphersfilename and rankedciphers[name] then
cipherstr=rankedciphers[name] cipherstr=rankedciphers[name]
@@ -1000,12 +1000,12 @@ local function try_protocol(host, port, protocol, upresults)
ciphers[i]=outcipher ciphers[i]=outcipher
end end
-- Format the cipher table. -- Format the cipher table.
table.sort(ciphers, function(a, b) return a["name"] < b["name"] end) table.sort(ciphers, function(a, b) return a["name"] < b["name"] end)
results["ciphers"] = ciphers results["ciphers"] = ciphers
-- Format the compressor table. -- Format the compressor table.
table.sort(compressors) table.sort(compressors)
results["compressors"] = compressors results["compressors"] = compressors
upresults[protocol] = results upresults[protocol] = results
@@ -1015,37 +1015,37 @@ end
-- Shamelessly stolen from nselib/unpwdb.lua and changed a bit. (Gabriel Lawrence) -- Shamelessly stolen from nselib/unpwdb.lua and changed a bit. (Gabriel Lawrence)
local filltable = function(filename,table) local filltable = function(filename,table)
if #table ~= 0 then if #table ~= 0 then
return true return true
end end
local file = io.open(filename, "r") local file = io.open(filename, "r")
if not file then if not file then
return false return false
end end
while true do while true do
local l = file:read() local l = file:read()
if not l then if not l then
break break
end end
-- Comments takes up a whole line -- Comments takes up a whole line
if not l:match("#!comment:") then if not l:match("#!comment:") then
local lsplit=stdnse.strsplit("%s+", l) local lsplit=stdnse.strsplit("%s+", l)
if cipherstrength[lsplit[2]] then if cipherstrength[lsplit[2]] then
table[lsplit[1]] = lsplit[2] table[lsplit[1]] = lsplit[2]
else else
stdnse.print_debug(1,"Strength not defined, ignoring: %s:%s",lsplit[1],lsplit[2]) stdnse.print_debug(1,"Strength not defined, ignoring: %s:%s",lsplit[1],lsplit[2])
end end
end end
end end
file:close() file:close()
return true return true
end end
portrule = shortport.ssl portrule = shortport.ssl
@@ -1072,27 +1072,27 @@ function sorted_by_key(t)
end end
action = function(host, port) action = function(host, port)
local name, result, results local name, result, results
rankedciphersfilename=stdnse.get_script_args("ssl-enum-ciphers.rankedcipherlist") rankedciphersfilename=stdnse.get_script_args("ssl-enum-ciphers.rankedcipherlist")
if rankedciphersfilename then if rankedciphersfilename then
filltable(rankedciphersfilename,rankedciphers) filltable(rankedciphersfilename,rankedciphers)
else else
rankedciphersfilename = nmap.fetchfile( "nselib/data/ssl-ciphers" ) rankedciphersfilename = nmap.fetchfile( "nselib/data/ssl-ciphers" )
stdnse.print_debug(1, "Ranked ciphers filename: %s", rankedciphersfilename) stdnse.print_debug(1, "Ranked ciphers filename: %s", rankedciphersfilename)
filltable(rankedciphersfilename,rankedciphers) filltable(rankedciphersfilename,rankedciphers)
end end
results = {} results = {}
local condvar = nmap.condvar(results) local condvar = nmap.condvar(results)
local threads = {} local threads = {}
for name, _ in pairs(PROTOCOLS) do for name, _ in pairs(PROTOCOLS) do
stdnse.print_debug(1, "Trying protocol %s.", name) stdnse.print_debug(1, "Trying protocol %s.", name)
local co = stdnse.new_thread(try_protocol, host.ip, port.number, name, results) local co = stdnse.new_thread(try_protocol, host.ip, port.number, name, results)
threads[co] = true threads[co] = true
end end
repeat repeat
for thread in pairs(threads) do for thread in pairs(threads) do
@@ -1107,14 +1107,14 @@ action = function(host, port)
return nil return nil
end end
if rankedciphersfilename then if rankedciphersfilename then
for k, v in pairs(cipherstrength) do for k, v in pairs(cipherstrength) do
if v == mincipherstrength then if v == mincipherstrength then
-- Should sort before or after SSLv3, TLSv* -- Should sort before or after SSLv3, TLSv*
results["least strength"] = k results["least strength"] = k
end end
end end
end end
return sorted_by_key(results) return sorted_by_key(results)
end end