diff --git a/scripts/sslv2.nse b/scripts/sslv2.nse index 9975c11c7..98ddb5131 100644 --- a/scripts/sslv2.nse +++ b/scripts/sslv2.nse @@ -2,6 +2,8 @@ local nmap = require "nmap" local shortport = require "shortport" local string = require "string" local table = require "table" +local bin = require "bin" +local stdnse = require "stdnse" description = [[ Determines whether the server supports obsolete and less secure SSLv2, and discovers which ciphers it @@ -11,13 +13,28 @@ supports. --- --@output -- 443/tcp open https syn-ack --- | sslv2: server still supports SSLv2 --- | SSL2_RC4_128_WITH_MD5 --- | SSL2_DES_192_EDE3_CBC_WITH_MD5 --- | SSL2_RC2_CBC_128_CBC_WITH_MD5 --- | SSL2_DES_64_CBC_WITH_MD5 --- | SSL2_RC4_128_EXPORT40_WITH_MD5 --- |_ SSL2_RC2_CBC_128_CBC_WITH_MD5 +-- | sslv2: +-- | SSLv2 supported +-- | ciphers: +-- | SSL2_DES_192_EDE3_CBC_WITH_MD5 +-- | SSL2_IDEA_128_CBC_WITH_MD5 +-- | SSL2_RC2_CBC_128_CBC_WITH_MD5 +-- | SSL2_RC4_128_WITH_MD5 +-- | SSL2_DES_64_CBC_WITH_MD5 +-- | SSL2_RC2_CBC_128_CBC_WITH_MD5 +-- |_ SSL2_RC4_128_EXPORT40_WITH_MD5 +--@xmloutput +--SSLv2 supported +-- +-- SSL2_DES_192_EDE3_CBC_WITH_MD5 +-- SSL2_IDEA_128_CBC_WITH_MD5 +-- SSL2_RC2_CBC_128_CBC_WITH_MD5 +-- SSL2_RC4_128_WITH_MD5 +-- SSL2_DES_64_CBC_WITH_MD5 +-- SSL2_RC2_CBC_128_CBC_WITH_MD5 +-- SSL2_RC4_128_EXPORT40_WITH_MD5 +--
+ author = "Matthew Boyle" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" @@ -27,7 +44,7 @@ categories = {"default", "safe"} portrule = shortport.ssl -hex2dec = function(hex) +local hex2dec = function(hex) local byte1, byte2; @@ -40,18 +57,16 @@ hex2dec = function(hex) end -cyphers = function(cypher_list, len) +local ciphers = function(cipher_list, len) --- returns names of cyphers supported by the server +-- returns names of ciphers supported by the server - local cypher; - local cypher_name; - local byte1, byte2, byte3; - local available_cyphers = ""; + local seen = {} + local available_ciphers = {} local idx = 0; - local ssl_cyphers = { --- (cut down) table of codes with their corresponding cyphers. + local ssl_ciphers = { +-- (cut down) table of codes with their corresponding ciphers. -- inspired by Wireshark's 'epan/dissectors/packet-ssl-utils.h' [0x010080] = "SSL2_RC4_128_WITH_MD5", [0x020080] = "SSL2_RC4_128_EXPORT40_WITH_MD5", @@ -65,36 +80,30 @@ cyphers = function(cypher_list, len) if (len == 0) then return "none"; end -- something's got broken along the way if these aren't equal - if (len ~= #cypher_list) then - return ""; + if (len ~= #cipher_list) then + return nil end for idx = 1, len, 3 do - cypher = string.sub(cypher_list, idx, idx + 2); + local _, cipher = bin.unpack(">I", "\x00" .. string.sub(cipher_list, idx, idx + 2)) + local cipher_name = ssl_ciphers[cipher]; - byte1 = string.byte(cypher, 1); - byte2 = string.byte(cypher, 2); - byte3 = string.byte(cypher, 3); - - cypher = (byte1 * 256 * 256) + (byte2 * 256) + byte3; - - cypher_name = ssl_cyphers[cypher]; - - if (cypher_name == nil) then - cypher_name = "unknown cypher (" .. byte1 .. "-" .. byte2 .. "-" .. byte3 .. " dec)" + if (cipher_name == nil) then + cipher_name = string.format("0x%06x", cipher) end - -- Check for duplicate cyphers - if not available_cyphers:match("\t" .. cypher_name .. "\n") then - available_cyphers = available_cyphers .. "\t" .. cypher_name .. "\n"; + -- Check for duplicate ciphers + if not seen[cipher] then + table.insert(available_ciphers, cipher_name) + seen[cipher] = true end end - return available_cyphers + return available_ciphers end -give_n_bytes = function(idx, n, str) +local give_n_bytes = function(idx, n, str) -- returns the next n bytes of a string @@ -116,7 +125,7 @@ action = function(host, port) local idx = 3; -- start reading after the end of the length record local return_string = ""; - local available_cyphers = ""; + local available_ciphers; local ssl_v2_hello; local server_hello; @@ -127,10 +136,10 @@ action = function(host, port) local certificate_type; local ssl_version; local certificate_len; - local cyphers_len; + local ciphers_len; local certificate; local connection_ID_len; - local cypher_list; + local cipher_list; local connection_ID; -- build client hello packet (contents inspired by @@ -197,12 +206,12 @@ action = function(host, port) idx, ssl_version = give_n_bytes(idx, 2, server_hello); idx, certificate_len = give_n_bytes(idx, 2, server_hello); certificate_len = hex2dec(certificate_len); - idx, cyphers_len = give_n_bytes(idx, 2, server_hello); - cyphers_len = hex2dec(cyphers_len); + idx, ciphers_len = give_n_bytes(idx, 2, server_hello); + ciphers_len = hex2dec(ciphers_len); idx, connection_ID_len = give_n_bytes(idx, 2, server_hello); connection_ID_len = hex2dec(connection_ID_len); idx, certificate = give_n_bytes(idx, certificate_len, server_hello); - idx, cypher_list = give_n_bytes(idx, cyphers_len, server_hello); + idx, cipher_list = give_n_bytes(idx, ciphers_len, server_hello); idx, connection_ID = give_n_bytes(idx, connection_ID_len, server_hello); -- some sanity checks: @@ -215,20 +224,15 @@ action = function(host, port) return; end --- get a list of cyphers offered - available_cyphers = cyphers(cypher_list, cyphers_len); +-- get a list of ciphers offered + available_ciphers = ciphers(cipher_list, ciphers_len); -- actually run some tests: + o = stdnse.output_table() if (ssl_version == string.char(0x00, 0x02)) then - if (available_cyphers == "none") then - return_string = "server supports SSLv2 protocol, but no SSLv2 cyphers\n"; - else - return_string = "server still supports SSLv2\n"; - if (nmap.verbosity() > 1 or nmap.debugging() > 0) then - return_string = return_string .. available_cyphers; - end - end + table.insert(o, "SSLv2 supported") + o["ciphers"] = available_ciphers end - return return_string; + return o; end