mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 13:11:28 +00:00
Sort ciphers according to server preference, when available
David's code, adapted to current script.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
local coroutine = require "coroutine"
|
local coroutine = require "coroutine"
|
||||||
local io = require "io"
|
local io = require "io"
|
||||||
|
local math = require "math"
|
||||||
local nmap = require "nmap"
|
local nmap = require "nmap"
|
||||||
local shortport = require "shortport"
|
local shortport = require "shortport"
|
||||||
local sslcert = require "sslcert"
|
local sslcert = require "sslcert"
|
||||||
@@ -224,6 +225,63 @@ local function remove(t, e)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function slice(t, i, j)
|
||||||
|
local output = {}
|
||||||
|
while i <= j do
|
||||||
|
output[#output+1] = t[i]
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
local function merge(a, b, cmp)
|
||||||
|
local output = {}
|
||||||
|
local i = 1
|
||||||
|
local j = 1
|
||||||
|
while i <= #a and j <= #b do
|
||||||
|
local winner, err = cmp(a[i], b[j])
|
||||||
|
if not winner then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
if winner == a[i] then
|
||||||
|
output[#output+1] = a[i]
|
||||||
|
i = i + 1
|
||||||
|
else
|
||||||
|
output[#output+1] = b[j]
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
while i <= #a do
|
||||||
|
output[#output+1] = a[i]
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
while j <= #b do
|
||||||
|
output[#output+1] = b[j]
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
local function merge_recursive(chunks, cmp)
|
||||||
|
if #chunks == 0 then
|
||||||
|
return {}
|
||||||
|
elseif #chunks == 1 then
|
||||||
|
return chunks[1]
|
||||||
|
else
|
||||||
|
local m = math.floor(#chunks / 2)
|
||||||
|
local a, b = slice(chunks, 1, m), slice(chunks, m+1, #chunks)
|
||||||
|
local am, err = merge_recursive(a, cmp)
|
||||||
|
if not am then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
local bm, err = merge_recursive(b, cmp)
|
||||||
|
if not bm then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
return merge(am, bm, cmp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function find_ciphers_group(host, port, protocol, group)
|
local function find_ciphers_group(host, port, protocol, group)
|
||||||
local name, protocol_worked, record, results
|
local name, protocol_worked, record, results
|
||||||
results = {}
|
results = {}
|
||||||
@@ -428,6 +486,32 @@ local function find_cipher_preference(host, port, protocol, ciphers)
|
|||||||
return "server", nil
|
return "server", nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Sort ciphers according to server preference with a modified merge sort
|
||||||
|
local function sort_ciphers(host, port, protocol, ciphers)
|
||||||
|
local chunks = {}
|
||||||
|
for _, group in ipairs(in_chunks(ciphers, CHUNK_SIZE)) do
|
||||||
|
local size = #group
|
||||||
|
local chunk = find_ciphers_group(host, port, protocol, group)
|
||||||
|
if not chunk then
|
||||||
|
return nil, "Network error"
|
||||||
|
end
|
||||||
|
if #chunk ~= size then
|
||||||
|
stdnse.debug1("%s warning: %d ciphers offered but only %d accepted", protocol, size, #chunk)
|
||||||
|
end
|
||||||
|
table.insert(chunks, chunk)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The comparison operator for the merge is a 2-cipher ClientHello.
|
||||||
|
local function cmp(cipher_a, cipher_b)
|
||||||
|
return compare_ciphers(host, port, protocol, cipher_a, cipher_b)
|
||||||
|
end
|
||||||
|
local sorted, err = merge_recursive(chunks, cmp)
|
||||||
|
if not sorted then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
return sorted
|
||||||
|
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)
|
||||||
@@ -456,6 +540,21 @@ local function try_protocol(host, port, protocol, upresults)
|
|||||||
-- Note the server's cipher preference algorithm.
|
-- Note the server's cipher preference algorithm.
|
||||||
local cipher_pref, cipher_pref_err = find_cipher_preference(host, port, protocol, ciphers)
|
local cipher_pref, cipher_pref_err = find_cipher_preference(host, port, protocol, ciphers)
|
||||||
|
|
||||||
|
-- Order ciphers according to server preference, if possible
|
||||||
|
if cipher_pref == "server" then
|
||||||
|
local sorted, err = sort_ciphers(host, port, protocol, ciphers)
|
||||||
|
if sorted then
|
||||||
|
ciphers = sorted
|
||||||
|
else
|
||||||
|
-- Can't sort, fall back to alphabetical order
|
||||||
|
table.sort(ciphers)
|
||||||
|
cipher_pref_err = err
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- fall back to alphabetical order
|
||||||
|
table.sort(ciphers)
|
||||||
|
end
|
||||||
|
|
||||||
-- 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
|
||||||
@@ -476,8 +575,6 @@ local function try_protocol(host, port, protocol, upresults)
|
|||||||
ciphers[i]=outcipher
|
ciphers[i]=outcipher
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Format the cipher table.
|
|
||||||
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user