Advertisement
RussX9

ssl-heartbleed.nse

Aug 21st, 2014
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.98 KB | None | 0 0
  1. local bin = require('bin')
  2. local match = require('match')
  3. local nmap = require('nmap')
  4. local shortport = require('shortport')
  5. local sslcert = require('sslcert')
  6. local stdnse = require('stdnse')
  7. local string = require('string')
  8. local table = require('table')
  9. local vulns = require('vulns')
  10. local have_tls, tls = pcall(require,'tls')
  11. assert(have_tls, "This script requires the tls.lua library from http://nmap.org/nsedoc/lib/tls.html")
  12.  
  13. description = [[
  14. Detects whether a server is vulnerable to the OpenSSL Heartbleed bug (CVE-2014-0160).
  15. The code is based on the Python script ssltest.py authored by Jared Stafford (jspenguin@jspenguin.org)
  16. ]]
  17.  
  18. ---
  19. -- @usage
  20. -- nmap -p 443 --script ssl-heartbleed <target>
  21. --
  22. -- @output
  23. -- PORT STATE SERVICE
  24. -- 443/tcp open https
  25. -- | ssl-heartbleed:
  26. -- | VULNERABLE:
  27. -- | The Heartbleed Bug is a serious vulnerability in the popular OpenSSL cryptographic software library. It allows for stealing information intended to be protected by SSL/TLS encryption.
  28. -- | State: VULNERABLE
  29. -- | Risk factor: High
  30. -- | Description:
  31. -- | OpenSSL versions 1.0.1 and 1.0.2-beta releases (including 1.0.1f and 1.0.2-beta1) of OpenSSL are affected by the Heartbleed bug. The bug allows for reading memory of systems protected by the vulnerable OpenSSL versions and could allow for disclosure of otherwise encrypted confidential information as well as the encryption keys themselves.
  32. -- |
  33. -- | References:
  34. -- | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160
  35. -- | http://www.openssl.org/news/secadv_20140407.txt
  36. -- |_ http://cvedetails.com/cve/2014-0160/
  37. --
  38. --
  39. -- @args ssl-heartbleed.protocols (default tries all) TLS 1.0, TLS 1.1, or TLS 1.2
  40. --
  41.  
  42. author = "Patrik Karlsson <patrik@cqure.net>"
  43. license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
  44. categories = { "vuln", "safe" }
  45.  
  46. local arg_protocols = stdnse.get_script_args(SCRIPT_NAME .. ".protocols") or {'TLSv1.0', 'TLSv1.1', 'TLSv1.2'}
  47.  
  48. portrule = function(host, port)
  49. return shortport.ssl(host, port) or sslcert.isPortSupported(port)
  50. end
  51.  
  52. local function recvhdr(s)
  53. local status, hdr = s:receive_buf(match.numbytes(5), true)
  54. if not status then
  55. stdnse.debug3('Unexpected EOF receiving record header - server closed connection')
  56. return
  57. end
  58. local pos, typ, ver, ln = bin.unpack('>CSS', hdr)
  59. return status, typ, ver, ln
  60. end
  61.  
  62. local function recvmsg(s, len)
  63. local status, pay = s:receive_buf(match.numbytes(len), true)
  64. if not status then
  65. stdnse.debug3('Unexpected EOF receiving record payload - server closed connection')
  66. return
  67. end
  68. return true, pay
  69. end
  70.  
  71. local function keys(t)
  72. local ret = {}
  73. for k, _ in pairs(t) do
  74. ret[#ret+1] = k
  75. end
  76. return ret
  77. end
  78.  
  79. local function testversion(host, port, version)
  80.  
  81. local hello = tls.client_hello({
  82. ["protocol"] = version,
  83. -- Claim to support every cipher
  84. -- Doesn't work with IIS, but IIS isn't vulnerable
  85. ["ciphers"] = keys(tls.CIPHERS),
  86. ["compressors"] = {"NULL"},
  87. ["extensions"] = {
  88. -- Claim to support every elliptic curve
  89. ["elliptic_curves"] = tls.EXTENSION_HELPERS["elliptic_curves"](keys(tls.ELLIPTIC_CURVES)),
  90. -- Claim to support every EC point format
  91. ["ec_point_formats"] = tls.EXTENSION_HELPERS["ec_point_formats"](keys(tls.EC_POINT_FORMATS)),
  92. ["heartbeat"] = "\x01", -- peer_not_allowed_to_send
  93. },
  94. })
  95.  
  96. local payload = "Nmap ssl-heartbleed"
  97. local hb = tls.record_write("heartbeat", version, bin.pack("C>SA",
  98. 1, -- HeartbeatMessageType heartbeat_request
  99. 0x4000, -- payload length (falsified)
  100. -- payload length is based on 4096 - 16 bytes padding - 8 bytes packet
  101. -- header + 1 to overflow
  102. payload -- less than payload length.
  103. )
  104. )
  105.  
  106. local s
  107. local specialized = sslcert.getPrepareTLSWithoutReconnect(port)
  108. if specialized then
  109. local status
  110. status, s = specialized(host, port)
  111. if not status then
  112. stdnse.debug3("Connection to server failed")
  113. return
  114. end
  115. else
  116. s = nmap.new_socket()
  117. local status = s:connect(host, port)
  118. if not status then
  119. stdnse.debug3("Connection to server failed")
  120. return
  121. end
  122. end
  123.  
  124. s:set_timeout(5000)
  125.  
  126. -- Send Client Hello to the target server
  127. local status, err = s:send(hello)
  128. if not status then
  129. stdnse.debug1("Couldn't send Client Hello: %s", err)
  130. s:close()
  131. return nil
  132. end
  133.  
  134. -- Read response
  135. local done = false
  136. local supported = false
  137. local i = 1
  138. local response
  139. repeat
  140. status, response, err = tls.record_buffer(s, response, i)
  141. if err == "TIMEOUT" then
  142. -- Timed out while waiting for server_hello_done
  143. -- Could be client certificate required or other message required
  144. -- Let's just drop out and try sending the heartbeat anyway.
  145. done = true
  146. break
  147. elseif not status then
  148. stdnse.debug1("Couldn't receive: %s", err)
  149. s:close()
  150. return nil
  151. end
  152.  
  153. local record
  154. i, record = tls.record_read(response, i)
  155. if record == nil then
  156. stdnse.debug1("Unknown response from server")
  157. s:close()
  158. return nil
  159. elseif record.protocol ~= version then
  160. stdnse.debug1("Protocol version mismatch")
  161. s:close()
  162. return nil
  163. end
  164.  
  165. if record.type == "handshake" then
  166. for _, body in ipairs(record.body) do
  167. if body.type == "server_hello" then
  168. if body.extensions and body.extensions["heartbeat"] == "\x01" then
  169. supported = true
  170. end
  171. elseif body.type == "server_hello_done" then
  172. stdnse.debug1("we're done!")
  173. done = true
  174. end
  175. end
  176. end
  177. until done
  178. if not supported then
  179. stdnse.debug1("Server does not support TLS Heartbeat Requests.")
  180. s:close()
  181. return nil
  182. end
  183.  
  184. status, err = s:send(hb)
  185. if not status then
  186. stdnse.debug1("Couldn't send heartbeat request: %s", err)
  187. s:close()
  188. return nil
  189. end
  190. while(true) do
  191. local status, typ, ver, len = recvhdr(s)
  192. if not status then
  193. stdnse.debug1('No heartbeat response received, server likely not vulnerable')
  194. break
  195. end
  196. if typ == 24 then
  197. local pay
  198. status, pay = recvmsg(s, 0x0fe9)
  199. s:close()
  200. if #pay > 3 then
  201. return true
  202. else
  203. stdnse.debug1('Server processed malformed heartbeat, but did not return any extra data.')
  204. break
  205. end
  206. elseif typ == 21 then
  207. stdnse.debug1('Server returned error, likely not vulnerable')
  208. break
  209. end
  210. end
  211.  
  212. end
  213.  
  214. action = function(host, port)
  215. local vuln_table = {
  216. title = "The Heartbleed Bug is a serious vulnerability in the popular OpenSSL cryptographic software library. It allows for stealing information intended to be protected by SSL/TLS encryption.",
  217. state = vulns.STATE.NOT_VULN,
  218. risk_factor = "High",
  219. description = [[
  220. OpenSSL versions 1.0.1 and 1.0.2-beta releases (including 1.0.1f and 1.0.2-beta1) of OpenSSL are affected by the Heartbleed bug. The bug allows for reading memory of systems protected by the vulnerable OpenSSL versions and could allow for disclosure of otherwise encrypted confidential information as well as the encryption keys themselves.
  221. ]],
  222.  
  223. references = {
  224. 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160',
  225. 'http://www.openssl.org/news/secadv_20140407.txt ',
  226. 'http://cvedetails.com/cve/2014-0160/'
  227. }
  228. }
  229.  
  230. local report = vulns.Report:new(SCRIPT_NAME, host, port)
  231. local test_vers = arg_protocols
  232.  
  233. if type(test_vers) == 'string' then
  234. test_vers = { test_vers }
  235. end
  236.  
  237. for _, ver in ipairs(test_vers) do
  238. if nil == tls.PROTOCOLS[ver] then
  239. return "\n Unsupported protocol version: " .. ver
  240. end
  241. local status = testversion(host, port, ver)
  242. if ( status ) then
  243. vuln_table.state = vulns.STATE.VULN
  244. break
  245. end
  246. end
  247.  
  248. return report:make_output(vuln_table)
  249. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement