summaryrefslogtreecommitdiffstats
path: root/scripts/socks-open-proxy.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/socks-open-proxy.nse')
-rw-r--r--scripts/socks-open-proxy.nse191
1 files changed, 191 insertions, 0 deletions
diff --git a/scripts/socks-open-proxy.nse b/scripts/socks-open-proxy.nse
new file mode 100644
index 0000000..f5fcc0c
--- /dev/null
+++ b/scripts/socks-open-proxy.nse
@@ -0,0 +1,191 @@
+local proxy = require "proxy"
+local shortport = require "shortport"
+local stdnse = require "stdnse"
+local string = require "string"
+local url = require "url"
+
+description=[[
+Checks if an open socks proxy is running on the target.
+
+The script attempts to connect to a proxy server and send socks4 and
+socks5 payloads. It is considered an open proxy if the script receives
+a Request Granted response from the target port.
+
+The payloads try to open a connection to www.google.com port 80. A
+different test host can be passed as <code>proxy.url</code>
+argument.
+]]
+---
+--@output
+-- PORT STATE SERVICE
+-- 1080/tcp open socks
+-- | socks-open-proxy:
+-- | status: open
+-- | versions:
+-- | socks4
+-- |_ socks5
+--
+--@xmloutput
+--<elem key="status">open</elem>
+--<table key="versions">
+-- <elem>socks4</elem>
+-- <elem>socks5</elem>
+--</table>
+--@usage
+-- nmap --script=socks-open-proxy \
+-- --script-args proxy.url=<host>,proxy.pattern=<pattern>
+
+author = "Joao Correa"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"default", "discovery", "external", "safe"}
+
+
+--- Performs the custom test, with user's arguments
+-- @param host The host table
+-- @param port The port table
+-- @param test_url The url to request
+-- @param pattern The pattern to check for valid result
+-- @return status If any request succeeded
+-- @return response Table with supported methods
+local function custom_test(host, port, test_url, pattern)
+ local status4, status5, fstatus, cstatus4, cstatus5
+ local get_r4, get_r5
+ local methods
+ local response = {}
+
+ -- strip hostname
+ if not string.match(test_url, "^http://.*") then
+ test_url = "http://" .. test_url
+ stdnse.debug1("URL missing scheme. URL concatenated to http://")
+ end
+ local url_table = url.parse(test_url)
+ local hostname = url_table.host
+ test_url = url_table.path
+
+ -- make requests
+ 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)
+
+ fstatus = status4 or status5
+ if(cstatus4) then response[#response+1]="socks4" end
+ if(cstatus5) then response[#response+1]="socks5" end
+ if(fstatus) then return fstatus, response end
+
+ -- Nothing works...
+ if not (cstatus4 or cstatus5) then
+ return false, nil
+ else
+ return "pattern not matched", response
+ end
+end
+
+--- Performs the default test
+-- First: Default google request and checks for Server: gws
+-- Second: 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 successful, 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 succeeded
+-- @return response Table 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 = {}
+
+ local test_url = "/"
+ 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)
+
+ fstatus = status4 or status5
+ if(cstatus4) then response[#response+1]="socks4" end
+ if(cstatus5) then response[#response+1]="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.debug1("Test 1 - Google Web Server: Received valid status codes, but pattern does not match")
+
+ test_url = "/"
+ 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+1]="socks4" end
+ if(status5) then fstatus = true; response[#response+1]="socks5" end
+ if(fstatus) then return fstatus, response end
+
+ if not (cstatus4 or cstatus5) then return false, nil end
+ stdnse.debug1("Test 2 - Wikipedia.org: Received valid status codes, but pattern does not match")
+
+ local redir_check_get = get_r4 or get_r5
+
+ test_url = "/"
+ 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+1]="socks4" end
+ if(status5) then fstatus = true; response[#response+1]="socks5" end
+ if(fstatus) then return fstatus, response end
+
+ if not (cstatus4 or cstatus5) then return false, nil end
+ stdnse.debug1("Test 3 - Computer History: Received valid status codes, but pattern does not match")
+
+ -- Check if GET is being redirected
+ if proxy.redirectCheck(get_r4 or get_r5, redir_check_get) then
+ return "redirecting", response
+ end
+
+ -- Protocol works, but nothing matches
+ return "pattern not matched", response
+
+end
+
+portrule = shortport.port_or_service({1080, 9050},
+ {"socks", "socks4", "socks5", "tor-socks"})
+
+action = function(host, port)
+ local supported_versions
+ local fstatus = false
+ local pattern, test_url
+ local def_test = true
+ local hostname
+ local retval = stdnse.output_table()
+
+ 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_versions = default_test(host, port)
+ else fstatus, supported_versions = custom_test(host, port, test_url, pattern)
+ end
+
+ -- If any of the tests were OK, then the proxy is potentially open
+ if fstatus == true then
+ retval["status"] = "open"
+ retval["versions"] = supported_versions
+ return retval
+ elseif fstatus and supported_versions then
+ retval["status"] = fstatus
+ retval["versions"] = supported_versions
+ return retval
+ end
+
+end