mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41:29 +00:00
Scripts now use fallback requests when valid codes are received but pattern was not found.
Scripts now use the lib proxy.lua to perform similar tasks
This commit is contained in:
@@ -11,8 +11,8 @@ web page from www.google.com.
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @args openproxy.url Url that will be requested to the proxy
|
-- @args proxy.url Url that will be requested to the proxy
|
||||||
-- @args openproxy.pattern Pattern that will be searched inside the request results
|
-- @args proxy.pattern Pattern that will be searched inside the request results
|
||||||
-- @output
|
-- @output
|
||||||
-- Interesting ports on scanme.nmap.org (64.13.134.52):
|
-- Interesting ports on scanme.nmap.org (64.13.134.52):
|
||||||
-- PORT STATE SERVICE
|
-- PORT STATE SERVICE
|
||||||
@@ -35,8 +35,7 @@ web page from www.google.com.
|
|||||||
--
|
--
|
||||||
-- @usage
|
-- @usage
|
||||||
-- nmap --script http-open-proxy.nse \
|
-- nmap --script http-open-proxy.nse \
|
||||||
-- --script-args 'openproxy={url=<url>,pattern=<pattern>}'
|
-- --script-args proxy.url=<url>,proxy.pattern=<pattern>
|
||||||
|
|
||||||
|
|
||||||
author = "Arturo 'Buanzo' Busleiman <buanzo@buanzo.com.ar>"
|
author = "Arturo 'Buanzo' Busleiman <buanzo@buanzo.com.ar>"
|
||||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
@@ -45,112 +44,179 @@ require "comm"
|
|||||||
require "shortport"
|
require "shortport"
|
||||||
require "stdnse"
|
require "stdnse"
|
||||||
require "url"
|
require "url"
|
||||||
|
require "proxy"
|
||||||
|
|
||||||
--- check function, makes checkings for all valid returned status
|
--- Performs the custom test, with user's arguments
|
||||||
--- If any of the HTTP status below is found, the proxy is potentially open
|
-- @param host The host table
|
||||||
--@param result connection result
|
-- @param port The port table
|
||||||
--@return true if any of the status is found, otherwise false
|
-- @param test_url The url te send the request
|
||||||
function check_code(result)
|
-- @param pattern The pattern to check for valid result
|
||||||
if string.match(result:lower(),"^http/%d\.%d%s*200") then return true end
|
-- @return status (if any request was succeded
|
||||||
if string.match(result:lower(),"^http/%d\.%d%s*30[12]") then return true end
|
-- @return response String with supported methods
|
||||||
return false
|
function custom_test(host, port, test_url, pattern)
|
||||||
end
|
local lstatus = false
|
||||||
|
local response = ""
|
||||||
|
-- if pattern is not used, result for test is code check result.
|
||||||
|
-- otherwise it is pattern check result.
|
||||||
|
|
||||||
--- check pattern, searches a pattern inside a response with multiple lines
|
-- strip hostname
|
||||||
--@param result Connection result
|
|
||||||
--@param pattern The pattern to be searched
|
|
||||||
--@return true if pattern is found, otherwise false
|
|
||||||
function check_pattern(result, pattern)
|
|
||||||
local lines = stdnse.strsplit("\n", result)
|
|
||||||
local i = 1
|
|
||||||
local n = table.getn(lines)
|
|
||||||
while true do
|
|
||||||
if i > n then return false end
|
|
||||||
if string.match(lines[i]:lower(),pattern) then return true end
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- check, decides what kind of check should be done on the response,
|
|
||||||
--- depending if a specific pattern is being used
|
|
||||||
--@param result Connection result
|
|
||||||
--@param pattern The pattern that should be checked (must be false, in case of
|
|
||||||
--code check)
|
|
||||||
--@return true, if the performed check returns true, otherwise false
|
|
||||||
function check(result, pattern)
|
|
||||||
if pattern
|
|
||||||
then return check_pattern(result, pattern)
|
|
||||||
else return check_code(result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
portrule = shortport.port_or_service({8123,3128,8000,8080},{'polipo','squid-http','http-proxy'})
|
|
||||||
|
|
||||||
action = function(host, port)
|
|
||||||
local retval
|
|
||||||
local supported_methods = "\nMethods successfully tested: "
|
|
||||||
local fstatus = false
|
|
||||||
local test_url = "http://www.google.com"
|
|
||||||
local hostname = "www.google.com"
|
|
||||||
local pattern = "^server: gws"
|
|
||||||
|
|
||||||
-- If arg url exists, use it as test url
|
|
||||||
if(nmap.registry.args.openproxy and nmap.registry.args.openproxy.url) then
|
|
||||||
test_url = nmap.registry.args.openproxy.url
|
|
||||||
pattern = false
|
|
||||||
if not string.match(test_url, "^http://.*") then
|
if not string.match(test_url, "^http://.*") then
|
||||||
test_url = "http://" .. test_url
|
test_url = "http://" .. test_url
|
||||||
stdnse.print_debug("URL missing scheme. URL concatenated to http://")
|
stdnse.print_debug("URL missing scheme. URL concatenated to http://")
|
||||||
end
|
end
|
||||||
url_table = url.parse(test_url)
|
local url_table = url.parse(test_url)
|
||||||
hostname = url_table.host
|
local hostname = url_table.host
|
||||||
end
|
|
||||||
if(nmap.registry.args.openproxy and nmap.registry.args.openproxy.pattern) then pattern = ".*" .. nmap.registry.args.openproxy.pattern .. ".*" end
|
|
||||||
|
|
||||||
-- Trying GET method!
|
local get_status = proxy.test_get(host, port, "http", test_url, hostname, pattern)
|
||||||
req = "GET " .. test_url .. " HTTP/1.0\r\nHost: " .. hostname .. "\r\n\r\n"
|
local head_status = proxy.test_head(host, port, "http", test_url, hostname, pattern)
|
||||||
stdnse.print_debug("GET Request: " .. req)
|
local conn_status = proxy.test_connect(host, port, "http", hostname)
|
||||||
local status, result = comm.exchange(host, port, req, {lines=1,proto=port.protocol, timeout=10000})
|
if get_status then
|
||||||
|
lstatus = true
|
||||||
if status then
|
response = response .. " GET"
|
||||||
lstatus = check(result, pattern)
|
|
||||||
if lstatus then
|
|
||||||
supported_methods = supported_methods .. "GET "
|
|
||||||
fstatus = true
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
-- Trying HEAD method
|
if fstatus then return fstatus, "Methods supported: " .. response end
|
||||||
req = "HEAD " .. test_url .. " HTTP/1.0\r\nHost: " .. hostname .. "\r\n\r\n"
|
|
||||||
stdnse.print_debug("HEAD Request: " .. req)
|
|
||||||
local status, result = comm.exchange(host, port, req, {lines=1,proto=port.protocol, timeout=10000})
|
|
||||||
|
|
||||||
if status then
|
-- same valid code checking as above
|
||||||
lstatus = check(result, pattern)
|
if not (get_cstatus or head_cstatus or conn_status) then return false, nil end
|
||||||
if lstatus then
|
stdnse.print_debug("Test 2 - Wikipedia.org\nReceived valid status codes, but pattern does not match")
|
||||||
supported_methods = supported_methods .. "HEAD "
|
|
||||||
fstatus = true
|
test_url = "http://www.computerhistory.org"
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
-- Trying CONNECT method
|
if fstatus then return fstatus, "Methods supported:" .. response end
|
||||||
req = "CONNECT " .. hostname .. ":80 HTTP/1.0\r\n\r\n"
|
if not get_cstatus then
|
||||||
stdnse.print_debug("CONNECT Request: " .. req)
|
stdnse.print_debug("Test 3 - Computer History\nReceived valid status codes, but pattern does not match")
|
||||||
local status, result = comm.exchange(host, port, req, {lines=1,proto=port.protocol, timeout=10000})
|
|
||||||
|
|
||||||
if status then
|
|
||||||
lstatus = check(result, false);
|
|
||||||
if lstatus then
|
|
||||||
supported_methods = supported_methods .. "CONNECT"
|
|
||||||
fstatus = true
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
-- If any of the tests were OK, then the proxy is potentially open
|
-- If any of the tests were OK, then the proxy is potentially open
|
||||||
if fstatus then
|
if fstatus then
|
||||||
retval = "Potentially OPEN proxy.\n" .. supported_methods
|
retval = "Potentially OPEN proxy.\n" .. supported_methods
|
||||||
return retval
|
return retval
|
||||||
|
elseif not fstatus and supported_methods then
|
||||||
|
return supported_methods
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ The payloads try to open a connection to www.google.com port 80. A
|
|||||||
different test host can be passed as openproxy.host (note the table
|
different test host can be passed as openproxy.host (note the table
|
||||||
syntax in the example) argument, as described below.
|
syntax in the example) argument, as described below.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
---
|
---
|
||||||
--@args openproxy.host Host that will be requested to the proxy
|
--@args proxy.url Url that will be requested to the proxy
|
||||||
|
--@args proxy.pattern Pattern that will be searched inside the request results
|
||||||
--@output
|
--@output
|
||||||
-- Interesting ports on scanme.nmap.org (64.13.134.52):
|
-- Interesting ports on scanme.nmap.org (64.13.134.52):
|
||||||
-- PORT STATE SERVICE
|
-- PORT STATE SERVICE
|
||||||
@@ -20,144 +20,148 @@ syntax in the example) argument, as described below.
|
|||||||
-- |_ Versions succesfully tested: Socks4 Socks5
|
-- |_ Versions succesfully tested: Socks4 Socks5
|
||||||
--@usage
|
--@usage
|
||||||
-- nmap --script=socks-open-proxy \
|
-- nmap --script=socks-open-proxy \
|
||||||
-- --script-args openproxy={host=<host>}
|
-- --script-args proxy.url=<host>,proxy.pattern=<pattern>
|
||||||
|
|
||||||
author = "Joao Correa <joao@livewire.com.br>"
|
author = "Joao Correa <joao@livewire.com.br>"
|
||||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
categories = {"default", "discovery", "external", "intrusive"}
|
categories = {"default", "discovery", "external", "intrusive"}
|
||||||
|
|
||||||
require "shortport"
|
require "shortport"
|
||||||
require "bin"
|
|
||||||
require "nmap"
|
|
||||||
require "stdnse"
|
require "stdnse"
|
||||||
require "dns"
|
require "url"
|
||||||
|
require "proxy"
|
||||||
|
|
||||||
--- Function that resolves IP address for hostname and
|
--- Performs the custom test, with user's arguments
|
||||||
--- returns it as hex values
|
-- @param host The host table
|
||||||
--@param hostname Hostname to resolve
|
-- @param port The port table
|
||||||
--@return Ip address of hostname in hex
|
-- @param test_url The url te send the request
|
||||||
function hex_resolve(hostname)
|
-- @param pattern The pattern to check for valid result
|
||||||
local a, b, c, d;
|
-- @return status (if any request was succeded
|
||||||
local dns_status, ip = dns.query(hostname)
|
-- @return response String with supported methods
|
||||||
if not dns_status then
|
local function custom_test(host, port, test_url, pattern)
|
||||||
return false
|
local status4, status5, fstatus
|
||||||
|
local get_r4, get_r5
|
||||||
|
local methods
|
||||||
|
local response = "Versions succesfully tested:"
|
||||||
|
|
||||||
|
-- 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
|
end
|
||||||
local t, err = ipOps.get_parts_as_number(ip)
|
local url_table = url.parse(test_url)
|
||||||
if t and not err
|
local hostname = url_table.host
|
||||||
then a, b, c, d = unpack(t)
|
|
||||||
else return false
|
-- make requests
|
||||||
|
status4, get_r4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
|
||||||
|
status5, get_r5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
|
||||||
|
|
||||||
|
if(status4) then fstatus = true; response = response .. " Socks4" end
|
||||||
|
if(status5) then fstatus = true; response = response .. " Socks5" end
|
||||||
|
if(fstatus) then return fstatus, response end
|
||||||
|
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 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
|
||||||
|
local function default_test(host, port)
|
||||||
|
local status4, status5, fstatus
|
||||||
|
local cstatus4, cstatus5
|
||||||
|
local get_r4, get_r5
|
||||||
|
local methods
|
||||||
|
local response = "Versions succesfully tested:"
|
||||||
|
|
||||||
|
local test_url = "http://www.google.com"
|
||||||
|
local hostname = "www.google.com"
|
||||||
|
local pattern = "^server: gws"
|
||||||
|
status4, get_r4, cstatus4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
|
||||||
|
status5, get_r5, cstatus5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
|
||||||
|
|
||||||
|
if(status4) then fstatus = true; response = response .. " Socks4" end
|
||||||
|
if(status5) then fstatus = true; response = response .. " Socks5" end
|
||||||
|
if(fstatus) then return fstatus, 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 (cstatus4 or cstatus5) then return false, nil end
|
||||||
|
stdnse.print_debug("Test 1 - Google Web Server: Received valid status codes, but pattern does not match")
|
||||||
|
|
||||||
|
test_url = "http://www.wikipedia.org"
|
||||||
|
hostname = "www.wikipedia.org"
|
||||||
|
pattern = "wikimedia"
|
||||||
|
status4, get_r4, cstatus4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
|
||||||
|
status5, get_r5, cstatus5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
|
||||||
|
|
||||||
|
if(status4) then fstatus = true; response = response .. " Socks4" end
|
||||||
|
if(status5) then fstatus = true; response = response .. " Socks5" end
|
||||||
|
if(fstatus) then return fstatus, response end
|
||||||
|
|
||||||
|
if not (cstatus4 or cstatus5) then return false, nil end
|
||||||
|
stdnse.print_debug("Test 2 - Wikipedia.org: Received valid status codes, but pattern does not match")
|
||||||
|
|
||||||
|
test_url = "http://www.computerhistory.org"
|
||||||
|
hostname = "www.computerhistory.org"
|
||||||
|
pattern = "museum"
|
||||||
|
status4, get_r4, cstatus4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
|
||||||
|
status5, get_r5, cstatus5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
|
||||||
|
|
||||||
|
if(status4) then fstatus = true; response = response .. " Socks4" end
|
||||||
|
if(status5) then fstatus = true; response = response .. " Socks5" end
|
||||||
|
if(fstatus) then return fstatus, response end
|
||||||
|
|
||||||
|
if not (cstatus4 or cstatus5) then return false, nil end
|
||||||
|
stdnse.print_debug("Test 3 - Computer History: Received valid status codes, but pattern does not match")
|
||||||
|
|
||||||
|
-- Check if GET is being redirected
|
||||||
|
if proxy.redirectCheck(get_r4, get_r5) then
|
||||||
|
return false, "Proxy might be redirecting requests"
|
||||||
end
|
end
|
||||||
local sip = string.format("%.2x ", a) .. string.format("%.2x ", b) .. string.format("%.2x ", c) .. string.format("%.2x ",d)
|
|
||||||
return true, sip
|
-- Nothing works...
|
||||||
|
return false, nil
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
portrule = shortport.port_or_service({1080},{"socks","socks4","socks5"})
|
portrule = shortport.port_or_service({1080},{"socks","socks4","socks5"})
|
||||||
|
|
||||||
action = function(host, port)
|
action = function(host, port)
|
||||||
local response
|
|
||||||
local retval
|
|
||||||
local supported_versions = "\nVersions succesfully tested: "
|
local supported_versions = "\nVersions succesfully tested: "
|
||||||
local fstatus = false
|
local fstatus = false
|
||||||
local test_host = "www.google.com"
|
local pattern, test_url
|
||||||
|
local def_test = true
|
||||||
|
local hostname
|
||||||
|
local retval
|
||||||
|
|
||||||
-- If arg open-proxy.host exists, query dns for IP number and convert it to hex
|
test_url, pattern = proxy.return_args()
|
||||||
if (nmap.registry.args.openproxy and nmap.registry.args.openproxy.host) then test_host = nmap.registry.args.openproxy.host end
|
|
||||||
local status, sip = hex_resolve(test_host)
|
if(test_url) then def_test = false end
|
||||||
if not status then
|
if(pattern) then pattern = ".*" .. pattern .. ".*" end
|
||||||
stdnse.print_debug("Failed to resolve IP Address")
|
|
||||||
return
|
if def_test
|
||||||
|
then fstatus, supported_versions = default_test(host, port)
|
||||||
|
else fstatus, supported_versions = custom_test(host, port, test_url, pattern)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Attempting Socks 4 connection
|
-- If any of the tests were OK, then the proxy is potentially open
|
||||||
-- Socks 4 payload: Version, Command, Null, Port, Ip Address, User (nmap), Null
|
|
||||||
-- Default port is always 80, different ports means different services, with different results
|
|
||||||
paystring = '04 01 00 50 ' .. sip .. ' 6e 6d 61 70 00'
|
|
||||||
payload = bin.pack("H",paystring)
|
|
||||||
|
|
||||||
local socket = nmap.new_socket()
|
|
||||||
socket:set_timeout(10000)
|
|
||||||
try = nmap.new_try(function() socket:close() end)
|
|
||||||
try(socket:connect(host.ip, port.number))
|
|
||||||
try(socket:send(payload))
|
|
||||||
response = try(socket:receive())
|
|
||||||
request_status = string.byte(response, 2)
|
|
||||||
|
|
||||||
-- Send Socks4 payload to estabilish connection
|
|
||||||
-- If did not receive Request Granted byte from server, skip next test
|
|
||||||
if(request_status == 0x5b) then
|
|
||||||
stdnse.print_debug("Socks4: Received \"Request rejected or failed\" from proxy server")
|
|
||||||
elseif (request_status == 0x5c) then
|
|
||||||
stdnse.print_debug("Socks4: Received \"request failed because client is not running identd\" from proxy server")
|
|
||||||
elseif (request_status == 0x5d) then
|
|
||||||
stdnse.print_debug("Socks4: Received \"request failed because client's identd could not confirm the user ID string in the request\n from proxy server")
|
|
||||||
|
|
||||||
-- If received Request Granted byte from server, proxy is considered open
|
|
||||||
elseif (request_status == 0x5a) then
|
|
||||||
stdnse.print_debug("Socks4: Received \"Request Granted\" from proxy server")
|
|
||||||
supported_versions = supported_versions .. "Socks4 "
|
|
||||||
fstatus = true
|
|
||||||
end
|
|
||||||
socket:close()
|
|
||||||
|
|
||||||
-- Attempting Socks 5 connection
|
|
||||||
-- Socks5 payload: Version, Auths Length, Auths methods required
|
|
||||||
payload = bin.pack("H",'05 01 00')
|
|
||||||
|
|
||||||
-- Send first Socks5 payload to estabilish connection without authentication
|
|
||||||
local socket2 = nmap.new_socket()
|
|
||||||
socket2:set_timeout(10000)
|
|
||||||
try = nmap.new_try(function() socket2:close() end)
|
|
||||||
try(socket2:connect(host.ip, port.number))
|
|
||||||
try(socket2:send(payload))
|
|
||||||
auth = try(socket2:receive())
|
|
||||||
r2 = string.byte(auth,2)
|
|
||||||
|
|
||||||
-- If Auth is required, proxy is closed, skip next test
|
|
||||||
if(r2 ~= 0x00) then
|
|
||||||
stdnse.print_debug("Socks5: Authentication required")
|
|
||||||
|
|
||||||
-- If no Auth is required, try to estabilish connection
|
|
||||||
else
|
|
||||||
stdnse.print_debug("Socks5: No authentication required")
|
|
||||||
|
|
||||||
-- Socks5 second payload: Version, Command, Null, Address type, Ip-Address, Port number
|
|
||||||
paystring = '05 01 00 01 ' .. sip .. '00 50'
|
|
||||||
payload = bin.pack("H",paystring)
|
|
||||||
try(socket2:send(payload))
|
|
||||||
z = try(socket2:receive())
|
|
||||||
request_status = string.byte(z, 2)
|
|
||||||
|
|
||||||
-- If did not received Request Granted byte from server, skip next test
|
|
||||||
if(request_status == 0x01) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"General failure\" from proxy server")
|
|
||||||
elseif (request_status == 0x02) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"Connection not allowed by ruleset\" from proxy server")
|
|
||||||
elseif (request_status == 0x03) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"Network unreachable\" from proxy server")
|
|
||||||
elseif (request_status == 0x04) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"Host unreachable\" from proxy server")
|
|
||||||
elseif (request_status == 0x05) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"Connection refused by destination host\" from proxy server")
|
|
||||||
elseif (request_status == 0x06) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"TTL Expired\" from proxy server")
|
|
||||||
elseif (request_status == 0x07) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"command not supported / protocol error\" from proxy server")
|
|
||||||
elseif (request_status == 0x08) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"Address type not supported\" from proxy server")
|
|
||||||
|
|
||||||
-- If received request granted byte from server, the proxy is considered open
|
|
||||||
elseif (request_status == 0x00) then
|
|
||||||
stdnse.print_debug("Socks5: Received \"Request granted\" from proxy server")
|
|
||||||
supported_versions = supported_versions .. "Socks5"
|
|
||||||
fstatus = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
socket2:close()
|
|
||||||
|
|
||||||
-- show results
|
|
||||||
if fstatus then
|
if fstatus then
|
||||||
retval = "Potentially OPEN proxy." .. supported_versions
|
retval = "Potentially OPEN proxy.\n" .. supported_versions
|
||||||
return retval
|
return retval
|
||||||
|
elseif not fstatus and supported_versions then
|
||||||
|
return supported_versions
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user