mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41:29 +00:00
223 lines
8.1 KiB
Lua
223 lines
8.1 KiB
Lua
description=[[
|
|
Checks if an HTTP proxy is open.
|
|
|
|
The script attempts to connect to www.google.com through the (possible) proxy and checks
|
|
for a valid HTTP response code.
|
|
|
|
Valid HTTP response codes are actually: 200, 301, 302.
|
|
|
|
If the target is an open proxy, this script causes the target to retrieve a
|
|
web page from www.google.com.
|
|
]]
|
|
|
|
---
|
|
-- @args proxy.url Url that will be requested to the proxy
|
|
-- @args proxy.pattern Pattern that will be searched inside the request results
|
|
-- @output
|
|
-- Interesting ports on scanme.nmap.org (64.13.134.52):
|
|
-- PORT STATE SERVICE
|
|
-- 8080/tcp open http-proxy
|
|
-- | proxy-open-http: Potentially OPEN proxy.
|
|
-- |_ Methods succesfully tested: GET HEAD CONNECT
|
|
|
|
-- Arturo 'Buanzo' Busleiman <buanzo@buanzo.com.ar> / www.buanzo.com.ar / linux-consulting.buanzo.com.ar
|
|
-- Changelog: Added explode() function. Header-only matching now works.
|
|
-- * Fixed set_timeout
|
|
-- * Fixed some \r\n's
|
|
-- 2008-10-02 Vlatko Kosturjak <kost@linux.hr>
|
|
-- * Match case-insensitively against "^Server: gws" rather than
|
|
-- case-sensitively against "^Server: GWS/".
|
|
-- 2009-05-14 Joao Correa <joao@livewire.com.br>
|
|
-- * Included tests for HEAD and CONNECT methods
|
|
-- * Included url and pattern arguments
|
|
-- * Script now checks for http response status code, when url is used
|
|
-- * If google is used, script checks for Server: gws
|
|
--
|
|
-- @usage
|
|
-- nmap --script http-open-proxy.nse \
|
|
-- --script-args proxy.url=<url>,proxy.pattern=<pattern>
|
|
|
|
author = "Arturo 'Buanzo' Busleiman"
|
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
|
categories = {"default", "discovery", "external", "intrusive"}
|
|
require "comm"
|
|
require "shortport"
|
|
require "stdnse"
|
|
require "url"
|
|
require "proxy"
|
|
|
|
--- Performs the custom test, with user's arguments
|
|
-- @param host The host table
|
|
-- @param port The port table
|
|
-- @param test_url The url te send the request
|
|
-- @param pattern The pattern to check for valid result
|
|
-- @return status (if any request was succeded
|
|
-- @return response String with supported methods
|
|
function custom_test(host, port, test_url, pattern)
|
|
local lstatus = false
|
|
local response = ""
|
|
-- if pattern is not used, result for test is code check result.
|
|
-- otherwise it is pattern check result.
|
|
|
|
-- strip hostname
|
|
if not string.match(test_url, "^http://.*") then
|
|
test_url = "http://" .. test_url
|
|
stdnse.print_debug("URL missing scheme. URL concatenated to http://")
|
|
end
|
|
local url_table = url.parse(test_url)
|
|
local hostname = url_table.host
|
|
|
|
local get_status = proxy.test_get(host, port, "http", test_url, hostname, pattern)
|
|
local head_status = proxy.test_head(host, port, "http", test_url, hostname, pattern)
|
|
local conn_status = proxy.test_connect(host, port, "http", hostname)
|
|
if get_status then
|
|
lstatus = true
|
|
response = response .. " GET"
|
|
end
|
|
if head_status then
|
|
lstatus = true
|
|
response = response .. " HEAD"
|
|
end
|
|
if conn_status then
|
|
lstatus = true
|
|
response = response .. " CONNECTION"
|
|
end
|
|
if lstatus then response = "Methods supported: " .. response end
|
|
return lstatus, response
|
|
end
|
|
|
|
--- Performs the default test
|
|
-- First: Default google request and checks for Server: gws
|
|
-- Seconde: Request to wikipedia.org and checks for wikimedia pattern
|
|
-- Third: Request to computerhistory.org and checks for museum pattern
|
|
--
|
|
-- If any of the requests is succesful, the proxy is considered open
|
|
-- If all get requests return the same result, the user is alerted that
|
|
-- the proxy might be redirecting his requests (very common on wi-fi
|
|
-- connections at airports, cafes, etc.)
|
|
--
|
|
-- @param host The host table
|
|
-- @param port The port table
|
|
-- @return status (if any request was succeded
|
|
-- @return response String with supported methods
|
|
function default_test(host, port)
|
|
local fstatus = false
|
|
local response = ""
|
|
local get_status, head_status, conn_status
|
|
local get_r1, get_r2, get_r3
|
|
local get_cstatus, head_cstatus
|
|
local _
|
|
|
|
-- Start test n1 -> google.com
|
|
-- making requests
|
|
local test_url = "http://www.google.com"
|
|
local hostname = "www.google.com"
|
|
local pattern = "^server: gws"
|
|
get_status, get_r1, get_cstatus = proxy.test_get(host, port, "http", test_url, hostname, pattern)
|
|
head_status, _, head_cstatus = proxy.test_head(host, port, "http", test_url, hostname, pattern)
|
|
conn_status = proxy.test_connect(host, port, "http", hostname)
|
|
|
|
-- checking results
|
|
-- conn_status use a different flag (cstatus)
|
|
-- because test_connection does not use patterns, so it is unable to detect
|
|
-- cases where you receive a valid code, but the response does not match the
|
|
-- pattern.
|
|
-- if it was using the same flag, program could return without testing GET/HEAD
|
|
-- once more before returning
|
|
|
|
if get_status then fstatus = true; response = response .. " GET" end
|
|
if head_status then fstatus = true; response = response .. " HEAD" end
|
|
if conn_status then cstatus = true; response = response .. " CONNECTION" end
|
|
|
|
-- if proxy is open, return it!
|
|
if fstatus then return fstatus, "Methods supported: " .. response end
|
|
|
|
-- if we receive a invalid response, but with a valid
|
|
-- response code, we should make a next attempt.
|
|
-- if we do not receive any valid status code,
|
|
-- there is no reason to keep testing... the proxy is probably not open
|
|
if not (get_cstatus or head_cstatus or conn_status) then return false, nil end
|
|
stdnse.print_debug("Test 1 - Google Web Server\nReceived valid status codes, but pattern does not match")
|
|
|
|
test_url = "http://www.wikipedia.org"
|
|
hostname = "www.wikipedia.org"
|
|
pattern = "wikimedia"
|
|
get_status, get_r2, get_cstatus = proxy.test_get(host, port, "http", test_url, hostname, pattern)
|
|
head_status, _, head_cstatus = proxy.test_head(host, port, "http", test_url, hostname, pattern)
|
|
conn_status = proxy.test_connect(host, port, "http", hostname)
|
|
|
|
if get_status then fstatus = true; response = response .. " GET" end
|
|
if head_status then fstatus = true; response = response .. " HEAD" end
|
|
if conn_status then
|
|
if not cstatus then response = response .. " CONNECTION" end
|
|
cstatus = true
|
|
end
|
|
|
|
if fstatus then return fstatus, "Methods supported: " .. response end
|
|
|
|
-- same valid code checking as above
|
|
if not (get_cstatus or head_cstatus or conn_status) then return false, nil end
|
|
stdnse.print_debug("Test 2 - Wikipedia.org\nReceived valid status codes, but pattern does not match")
|
|
|
|
test_url = "http://www.computerhistory.org"
|
|
hostname = "www.computerhistory.org"
|
|
pattern = "museum"
|
|
get_status, get_r3, get_cstatus = proxy.test_get(host, port, "http", test_url, hostname, pattern)
|
|
conn_status = proxy.test_connect(host, port, "http", hostname)
|
|
|
|
if get_status then fstatus = true; response = response .. " GET" end
|
|
if conn_status then
|
|
if not cstatus then response = response .. " CONNECTION" end
|
|
cstatus = true
|
|
end
|
|
|
|
if fstatus then return fstatus, "Methods supported:" .. response end
|
|
if not get_cstatus then
|
|
stdnse.print_debug("Test 3 - Computer History\nReceived valid status codes, but pattern does not match")
|
|
end
|
|
|
|
-- Check if GET is being redirected
|
|
if proxy.redirectCheck(get_r1, get_r2) and proxy.redirectCheck(get_r2, get_r3) then
|
|
return false, "Proxy might be redirecting requests"
|
|
end
|
|
|
|
-- Check if at least CONNECTION worked
|
|
if cstatus then return true, "Methods supported:" .. response end
|
|
|
|
-- Nothing works...
|
|
return false, nil
|
|
end
|
|
|
|
portrule = shortport.port_or_service({8123,3128,8000,8080},{'polipo','squid-http','http-proxy'})
|
|
|
|
action = function(host, port)
|
|
local response
|
|
local i
|
|
local retval
|
|
local supported_methods = "\nMethods succesfully tested: "
|
|
local fstatus = false
|
|
local def_test = true
|
|
local test_url, pattern
|
|
local hostname
|
|
|
|
test_url, pattern = proxy.return_args()
|
|
|
|
if(test_url) then def_test = false end
|
|
if(pattern) then pattern = ".*" .. pattern .. ".*" end
|
|
|
|
if def_test
|
|
then fstatus, supported_methods = default_test(host, port)
|
|
else fstatus, supported_methods = custom_test(host, port, test_url, pattern);
|
|
end
|
|
|
|
-- If any of the tests were OK, then the proxy is potentially open
|
|
if fstatus then
|
|
retval = "Potentially OPEN proxy.\n" .. supported_methods
|
|
return retval
|
|
elseif not fstatus and supported_methods then
|
|
return supported_methods
|
|
end
|
|
return
|
|
|
|
end
|