Nmap Development mailing list archives

Re: [NSE Script] SSLv2 support detection


From: Matthew Boyle <mb2263 () bristol ac uk>
Date: Wed, 23 Aug 2006 19:00:10 +0100

sorry about that, the file was filtered out.  here it is (hopefully).

--matt

--
et je triche, et je mens, et je m'éclate, et je touche à tout.

id = "ssl-v2"
description = "determines whether the server (still) supports SSL-v2, and what cyphers it offers."

tags = {"intrusive"}

portrule = function(host, port)
        if      (       port.number == 443
                or      port.service == "ssl/http"
                or      port.service == "https")

                and     port.protocol == "tcp"
        then
                return true
        else
                return false
        end

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.
-- stolen from 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 "\tthe server didn't offer any cyphers"; 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
        
                available_cyphers = available_cyphers .. "\t" .. cypher_name .. "\n";
        
        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 stolen from
-- 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.ip, port.number, "tcp");
        socket:send(ssl_v2_hello);

        status, server_hello = socket:receive_bytes(2);

        if (status == false) 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 (status == false) 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

-- actually run some tests:
        if (ssl_version == string.char(0x00, 0x02)) then
                return_string = "server still supports SSLv2\n";
        end

        available_cyphers = cyphers(cypher_list, cyphers_len);

        if (    string.len(return_string) > 0
        or      string.len(available_cyphers) > 0) then
                        return return_string .. available_cyphers;
        else
                        return;
        end

end

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: