1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 22:21:29 +00:00
Files
nmap/scripts/http-slowloris-check.nse
batrick 7f5ec526fe Merge branch 'nse-lua53'
Lua 5.3 adds several awesome features of particular interest to nmap including
bitwise operators and integers, a utf8 library, and standard binary pack/unpack
functions.

In addition to adding Lua 5.3, this branch changes:

o Complete removal of the NSE bit library (in C), It has been replaced with
  a new Lua library wrapping Lua 5.3's bit-wise operators.

o Complete removal of the NSE bin library (in C). It has been replaced with a
  new Lua library wrapping Lua 5.3's string.pack|unpack functions.

o The bin.pack "B" format specifier (which has never worked correctly) is
  unimplemented.  All scripts/libraries which use it have been updated. Most
  usage of this option was to allow string based bit-wise operations which are no
  longer necessary now that Lua 5.3 provides integers and bit-wise operators.

o The base32/base64 libraries have been reimplemented using Lua 5.3's new
  bitwise operators. (This library was the main user of the bin.pack "B" format
  specifier.)

o A new "bits" library has been added for common bit hacks. Currently only has
  a reverse function.

Thanks to David Fifield, Daniel Miller, Jacek Wielemborek, and  Paulino
Calderon for testing this branch.
2016-07-02 17:02:27 +00:00

162 lines
5.3 KiB
Lua

local coroutine = require "coroutine"
local math = require "math"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
local comm = require "comm"
local vulns = require "vulns"
local http = require "http"
description = [[
Tests a web server for vulnerability to the Slowloris DoS attack without
actually launching a DoS attack.
Slowloris was described at Defcon 17 by RSnake
(see http://ha.ckers.org/slowloris/).
This script opens two connections to the server, each without the final CRLF.
After 10 seconds, second connection sends additional header. Both connections
then wait for server timeout. If second connection gets a timeout 10 or more
seconds after the first one, we can conclude that sending additional header
prolonged its timeout and that the server is vulnerable to slowloris DoS
attack.
A "LIKELY VULNERABLE" result means a server is subject to timeout-extension
attack, but depending on the http server's architecture and resource limits, a
full denial-of-service is not always possible. Complete testing requires
triggering the actual DoS condition and measuring server responsiveness.
You can specify custom http User-agent field with <code>http.useragent</code>
script argument.
Idea from Qualys blogpost:
* https://community.qualys.com/blogs/securitylabs/2011/07/07/identifying-slow-http-attack-vulnerabilities-on-web-applications
]]
---
-- @usage
-- nmap --script http-slowloris-check <target>
--
-- @output
-- PORT STATE SERVICE REASON
-- 80/tcp open http syn-ack
-- | http-slowloris-check:
-- | VULNERABLE:
-- | Slowloris DOS attack
-- | State: LIKELY VULNERABLE
-- | IDs: CVE:CVE-2007-6750
-- | Slowloris tries to keep many connections to the target web server open and hold
-- | them open as long as possible. It accomplishes this by opening connections to
-- | the target web server and sending a partial request. By doing so, it starves
-- | the http server's resources causing Denial Of Service.
-- |
-- | Disclosure date: 2009-09-17
-- | References:
-- | http://ha.ckers.org/slowloris/
-- |_ http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-6750
author = "Aleksandar Nikolic"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"vuln", "safe"}
portrule = shortport.http
action = function(host,port)
local slowloris = {
title = "Slowloris DOS attack",
description = [[
Slowloris tries to keep many connections to the target web server open and hold
them open as long as possible. It accomplishes this by opening connections to
the target web server and sending a partial request. By doing so, it starves
the http server's resources causing Denial Of Service.
]],
IDS = {
CVE = 'CVE-2007-6750',
},
references = {
'http://ha.ckers.org/slowloris/',
},
dates = {
disclosure = {year = '2009', month = '09', day = '17'},
},
exploit_results = {},
}
local report = vulns.Report:new(SCRIPT_NAME, host, port)
slowloris.state = vulns.STATE.NOT_VULN
local sd, response, Bestopt = comm.tryssl(host, port, "GET / \r\n\r\n") -- first determine if we need ssl
if Bestopt == "none" then
stdnse.debug1("Error determining SSL: %s", response)
return nil
end
local HalfHTTP = (
"POST /" .. tostring(math.random(100000, 900000)) .. " HTTP/1.1\r\n" ..
"Host: " .. host.ip .. "\r\n" ..
"User-Agent: " .. http.USER_AGENT .. "\r\n" ..
"Content-Length: 42\r\n"
)
local TimeWithout -- time without additional headers
-- does a half http request and waits until timeout
local function slowThread1()
local socket = nmap.new_socket()
local try = nmap.new_try(function()
TimeWithout = nmap.clock()
socket:close()
end)
try(socket:connect(host, port, Bestopt))
try(socket:send(HalfHTTP))
socket:set_timeout(500 * 1000)
try(socket:receive())
TimeWithout = nmap.clock()
end
local TimeWith -- time with additional headers
-- does a half http request but sends another
-- header value after 10 seconds
local function slowThread2()
local socket = nmap.new_socket()
local try = nmap.new_try(function()
TimeWith = nmap.clock()
socket:close()
end)
try(socket:connect(host, port, Bestopt))
try(socket:send(HalfHTTP))
stdnse.sleep(10)
try(socket:send("X-a: b\r\n"))
socket:set_timeout(500 * 1000)
try(socket:receive())
TimeWith = nmap.clock()
end
-- both threads run at the same time
local thread1 = stdnse.new_thread(slowThread1)
local thread2 = stdnse.new_thread(slowThread2)
while true do -- wait for both threads to die
if coroutine.status(thread1) == "dead" and coroutine.status(thread2) == "dead" then
break
end
stdnse.sleep(1)
end
-- compare times
if ( not(TimeWith) or not(TimeWithout) ) then
stdnse.debug1("Unable to time responses: thread died early.")
return nil
end
local diff = TimeWith - TimeWithout
stdnse.debug1("Time difference is: %.f",diff)
-- if second connection died 10 or more seconds after the first
-- it means that sending additional data prolonged the connection's time
-- and the server is vulnerable to slowloris attack
if diff >= 10 then
slowloris.state = vulns.STATE.LIKELY_VULN
end
return report:make_output(slowloris)
end