description = [[
Determines whether the server supports obsolete and less secure SSLv2, and discovers which ciphers it
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
author = "Matthew Boyle"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"default", "safe"}
require "shortport"
local portfunction = shortport.port_or_service({443,993,995},{'https','imaps','pop3s'})
portrule = function( host, port )
return portfunction( host, port ) or port.version.service_tunnel == 'ssl'
end
hex2dec = function(hex)
local byte1, byte2;
byte1 = string.byte(hex, 1);
byte2 = string.byte(hex, 2);
if (byte1 == nil or byte2 == nil) then return 0; end;
return (byte1 * 256) + byte2;
end
cyphers = function(cypher_list, len)
-- returns names of cyphers supported by the server
local cypher;
local cypher_name;
local byte1, byte2, byte3;
local available_cyphers = "";
local idx = 0;
local ssl_cyphers = {
-- (cut down) table of codes with their corresponding cyphers.
-- inspired by Wireshark's 'epan/dissectors/packet-ssl-utils.h'
[0x010080] = "SSL2_RC4_128_WITH_MD5",
[0x020080] = "SSL2_RC4_128_EXPORT40_WITH_MD5",
[0x030080] = "SSL2_RC2_CBC_128_CBC_WITH_MD5",
[0x040080] = "SSL2_RC2_CBC_128_CBC_WITH_MD5",
[0x050080] = "SSL2_IDEA_128_CBC_WITH_MD5",
[0x060040] = "SSL2_DES_64_CBC_WITH_MD5",
[0x0700c0] = "SSL2_DES_192_EDE3_CBC_WITH_MD5",
[0x080080] = "SSL2_RC4_64_WITH_MD5",
};
if (len == 0) then return "none"; end
-- something's got broken along the way if these aren't equal
if (len ~= string.len(cypher_list)) then
return "";
end
for idx = 1, len, 3 do
cypher = string.sub(cypher_list, idx, idx + 2);
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)"
end
-- Check for duplicate cyphers
if not available_cyphers:match("\t" .. cypher_name .. "\n") then
available_cyphers = available_cyphers .. "\t" .. cypher_name .. "\n";
end
end
return available_cyphers
end
give_n_bytes = function(idx, n, str)
-- returns the next n bytes of a string
if (idx + (n - 1) > string.len(str)) then
return (idx + n), string.rep(string.char(0x00), n);
end
return (idx + n), string.sub(str, idx, (idx + (n - 1)) );
end
action = function(host, port)
local socket = nmap.new_socket();
local status = true;
local tmp;
local idx = 3; -- start reading after the end of the length record
local return_string = "";
local available_cyphers = "";
local ssl_v2_hello;
local server_hello;
local server_hello_len;
local message_type;
local SID_hit;
local certificate_type;
local ssl_version;
local certificate_len;
local cyphers_len;
local certificate;
local connection_ID_len;
local cypher_list;
local connection_ID;
-- build client hello packet (contents inspired by
-- http://mail.nessus.org/pipermail/plugins-writers/2004-October/msg00041.html )
local t = {};
table.insert(t, string.char(0x80, 0x31));
table.insert(t, string.char(0x01));
table.insert(t, string.char(0x00, 0x02));
table.insert(t, string.char(0x00, 0x18));
table.insert(t, string.char(0x00, 0x00));
table.insert(t, string.char(0x00, 0x10));
table.insert(t, string.char(0x07, 0x00, 0xc0));
table.insert(t, string.char(0x05, 0x00, 0x80));
table.insert(t, string.char(0x03, 0x00, 0x80));
table.insert(t, string.char(0x01, 0x00, 0x80));
table.insert(t, string.char(0x08, 0x00, 0x80));
table.insert(t, string.char(0x06, 0x00, 0x40));
table.insert(t, string.char(0x04, 0x00, 0x80));
table.insert(t, string.char(0x02, 0x00, 0x80));
table.insert(t, string.char(0xe4, 0xbd, 0x00, 0x00));
table.insert(t, string.char(0xa4, 0x41, 0xb6, 0x74));
table.insert(t, string.char(0x71, 0x2b, 0x27, 0x95));
table.insert(t, string.char(0x44, 0xc0, 0x3d, 0xc0));
ssl_v2_hello = table.concat(t, "")
socket:connect(host, port, "tcp");
socket:send(ssl_v2_hello);
status, server_hello = socket:receive_bytes(2);
if (not status) then
socket:close();
return;
end
server_hello_len = string.sub(server_hello, 1, 2);
server_hello_len = hex2dec(server_hello_len);
-- length record doesn't include its own length, and is "broken".
server_hello_len = server_hello_len - (128 * 256) + 2;
-- the hello needs to be at least 13 bytes long to be of any use
if (server_hello_len < 13) then
socket:close();
return;
end
--try to get entire hello, if we don't already
if (string.len(server_hello) < server_hello_len) then
status, tmp = socket:receive_bytes(server_hello_len - string.len(server_hello));
if (not status) then
socket:close();
return;
end
server_hello = server_hello .. tmp;
end;
socket:close();
-- split up server hello into components
idx, message_type = give_n_bytes(idx, 1, server_hello);
idx, SID_hit = give_n_bytes(idx, 1, server_hello);
idx, certificate_type = give_n_bytes(idx, 1, server_hello);
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, 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, connection_ID = give_n_bytes(idx, connection_ID_len, server_hello);
-- some sanity checks:
-- is response a server hello?
if (message_type ~= string.char(0x04)) then
return;
end
-- is certificate in X.509 format?
if (certificate_type ~= string.char(0x01)) then
return;
end
-- get a list of cyphers offered
available_cyphers = cyphers(cypher_list, cyphers_len);
-- actually run some tests:
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
end
return return_string;
end
Copyright 2K16 - 2K18 Indonesian Hacker Rulez