1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-25 08:59:01 +00:00

Update http-slowloris-check

Summary of changes:
* Clarified LIKELY_VULN status, since actual DoS may not be possible
  (false positive)
* Made worker threads closures to simplify/fix testing multiple servers
  at once.
* Added debug statements at script exit locations to clarify status when
  script terminates early.
* Added CVE reference.
This commit is contained in:
dmiller
2015-01-23 15:37:09 +00:00
parent e94f22e0a3
commit 179e42a9c6

View File

@@ -21,6 +21,11 @@ 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.
@@ -41,15 +46,17 @@ Idea from Qualys blogpost:
-- | http-slowloris-check:
-- | VULNERABLE:
-- | Slowloris DOS attack
-- | State: VULNERABLE
-- | 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.
-- | 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://ha.ckers.org/slowloris/
-- |_ http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-6750
author = "Aleksandar Nikolic"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
@@ -58,63 +65,19 @@ categories = {"vuln", "safe"}
portrule = shortport.http
local HalfHTTP
local Bestopt
local TimeWithout -- time without additional headers
local TimeWith -- time with additional headers
-- does a half http request and waits until timeout
local function slowThread1(host,port)
-- if no response was received when determining SSL
if ( Bestopt == "none" ) then
return
end
local socket,status
local catch = function()
TimeWithout = nmap.clock()
end
local try = nmap.new_try(catch)
socket = nmap.new_socket()
socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP)
try(socket:receive())
TimeWithout = nmap.clock()
end
-- does a half http request but sends another
-- header value after 10 seconds
local function slowThread2(host,port)
-- if no response was received when determining SSL
if ( Bestopt == "none" ) then
return
end
local socket,status
local catch = function()
-- note the time the socket timedout
TimeWith = nmap.clock()
stdnse.debug1("2 try")
end
local try = nmap.new_try(catch)
socket = nmap.new_socket()
socket:set_timeout(500 * 1000)
socket:connect(host.ip, port, Bestopt)
socket:send(HalfHTTP)
stdnse.sleep(10)
socket:send("X-a: b\r\n")
try(socket:receive())
TimeWith = nmap.clock()
end
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.
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/',
},
@@ -127,15 +90,55 @@ so, it starves the http server's resources causing Denial Of Service.
local report = vulns.Report:new(SCRIPT_NAME, host, port)
slowloris.state = vulns.STATE.NOT_VULN
local _
_, _, Bestopt = comm.tryssl(host, port, "GET / \r\n\r\n", {}) -- first determine if we need ssl
HalfHTTP = "POST /" .. tostring(math.random(100000, 900000)) .. " HTTP/1.1\r\n" ..
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; " ..
"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, host, port)
local thread2 = stdnse.new_thread(slowThread2, host, port)
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
@@ -144,7 +147,8 @@ so, it starves the http server's resources causing Denial Of Service.
end
-- compare times
if ( not(TimeWith) or not(TimeWithout) ) then
return
stdnse.debug1("Unable to time responses: thread died early.")
return nil
end
local diff = TimeWith - TimeWithout
stdnse.debug1("Time difference is: %d",diff)
@@ -152,8 +156,7 @@ so, it starves the http server's resources causing Denial Of Service.
-- it means that sending additional data prolonged the connection's time
-- and the server is vulnerable to slowloris attack
if diff >= 10 then
stdnse.debug1("Difference is greater or equal to 10 seconds.")
slowloris.state = vulns.STATE.VULN
slowloris.state = vulns.STATE.LIKELY_VULN
end
return report:make_output(slowloris)
end