1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-10 09:49:05 +00:00

Revert r32789 in favor of lib-level fixes

nmap.new_try() shouldn't be used in libraries. It results in Lua errors
being thrown that the script can't recover from without resorting to
pcall(). It has been replaced in proxy.lua with proper error handling
which did not require any changes to the scripts (http-open-proxy and
socks-open-proxy) that used it.
This commit is contained in:
dmiller
2014-04-07 18:10:10 +00:00
parent 1332949c3d
commit 413bbf6e96
2 changed files with 100 additions and 64 deletions

View File

@@ -69,11 +69,18 @@ end
--@return result The result of the request --@return result The result of the request
--@return code_status True or false. If pattern was used, returns the result of code checking for the same result. If pattern was not used, is nil. --@return code_status True or false. If pattern was used, returns the result of code checking for the same result. If pattern was not used, is nil.
local function test(socket, req, pattern) local function test(socket, req, pattern)
local _, result, s_code, s_pattern local status, result = socket:send(req)
socket:send(req) if not status then
_, result = socket:receive() socket:close()
return false, result
end
status, result = socket:receive()
if not status then
socket:close()
return false, result
end
socket:close() socket:close()
s_code, s_pattern = check(result, pattern) local s_code, s_pattern = check(result, pattern)
if result and pattern then return s_pattern, result, s_code end if result and pattern then return s_pattern, result, s_code end
if result then return s_code, result, nil end if result then return s_code, result, nil end
return false, nil, nil return false, nil, nil
@@ -88,8 +95,10 @@ end
-- @param pattern The pattern to check for valid result -- @param pattern The pattern to check for valid result
-- @return the result of the function test (status and the request result) -- @return the result of the function test (status and the request result)
function test_get(host, port, proxyType, test_url, hostname, pattern) function test_get(host, port, proxyType, test_url, hostname, pattern)
local socket = connectProxy(host, port, proxyType, hostname) local status, socket = connectProxy(host, port, proxyType, hostname)
if not socket then return false end if not status then
return false, socket
end
local req = "GET " .. test_url .. " HTTP/1.0\r\nHost: " .. hostname .. "\r\n\r\n" local req = "GET " .. test_url .. " HTTP/1.0\r\nHost: " .. hostname .. "\r\n\r\n"
stdnse.print_debug("GET Request: " .. req) stdnse.print_debug("GET Request: " .. req)
return test(socket, req, pattern) return test(socket, req, pattern)
@@ -104,8 +113,10 @@ end
-- @param pattern The pattern to check for valid result -- @param pattern The pattern to check for valid result
-- @return the result of the function test (status and the request result) -- @return the result of the function test (status and the request result)
function test_head(host, port, proxyType, test_url, hostname, pattern) function test_head(host, port, proxyType, test_url, hostname, pattern)
local socket = connectProxy(host, port, proxyType, hostname) local status, socket = connectProxy(host, port, proxyType, hostname)
if not socket then return false end if not status then
return false, socket
end
local req = "HEAD " .. test_url .. " HTTP/1.0\r\nHost: " .. hostname .. "\r\n\r\n" local req = "HEAD " .. test_url .. " HTTP/1.0\r\nHost: " .. hostname .. "\r\n\r\n"
stdnse.print_debug("HEAD Request: " .. req) stdnse.print_debug("HEAD Request: " .. req)
return test(socket, req, pattern) return test(socket, req, pattern)
@@ -118,8 +129,10 @@ end
-- @param hostname The hostname of the server to send the request -- @param hostname The hostname of the server to send the request
-- @return the result of the function test (status and the request result) -- @return the result of the function test (status and the request result)
function test_connect(host, port, proxyType, hostname) function test_connect(host, port, proxyType, hostname)
local socket = connectProxy(host, port, proxyType, hostname) local status, socket = connectProxy(host, port, proxyType, hostname)
if not socket then return false end if not status then
return false, socket
end
local req = "CONNECT " .. hostname .. ":80 HTTP/1.0\r\n\r\n" local req = "CONNECT " .. hostname .. ":80 HTTP/1.0\r\n\r\n"
stdnse.print_debug("CONNECT Request: " .. req) stdnse.print_debug("CONNECT Request: " .. req)
return test(socket, req, false) return test(socket, req, false)
@@ -170,94 +183,127 @@ end
-- @param port The port table -- @param port The port table
-- @param proxyType A string with the proxy type. Might be "http","socks4" or "socks5" -- @param proxyType A string with the proxy type. Might be "http","socks4" or "socks5"
-- @param hostname The proxy destination hostname -- @param hostname The proxy destination hostname
-- @return socket A socket with the handshake already done -- @return status True if handshake succeeded, false otherwise
-- @return socket A socket with the handshake already done, or an error if
function connectProxy(host, port, proxyType, hostname) function connectProxy(host, port, proxyType, hostname)
local socket = nmap.new_socket() local socket = nmap.new_socket()
socket:set_timeout(10000) socket:set_timeout(10000)
local try = nmap.new_try(function() socket:close() return false end) local status, err = socket:connect(host, port)
try(socket:connect(host, port)) if not status then
if proxyType == "http" then return socket end socket:close()
return false, err
end
if proxyType == "http" then return true, socket end
if proxyType == "socks4" then return socksHandshake(socket, 4, hostname) end if proxyType == "socks4" then return socksHandshake(socket, 4, hostname) end
if proxyType == "socks5" then return socksHandshake(socket, 5, hostname) end if proxyType == "socks5" then return socksHandshake(socket, 5, hostname) end
return false socket:close()
return false, "Invalid proxyType"
end end
--- Performs a socks handshake on a socket and returns it --- Performs a socks handshake on a socket and returns it
-- @param socket The socket where the handshake will be performed -- @param socket The socket where the handshake will be performed
-- @param version The socks version (might be 4 or 5) -- @param version The socks version (might be 4 or 5)
-- @param hostname The proxy destination hostname -- @param hostname The proxy destination hostname
-- @return socket A socket with the handshake already done -- @return status True if handshake succeeded, false otherwise
-- @return socket A socket with the handshake already done, or an error if
-- status is false
function socksHandshake(socket, version, hostname) function socksHandshake(socket, version, hostname)
local resolve, sip, paystring, payload local resolve, sip, paystring, payload
resolve, sip = hex_resolve(hostname) resolve, sip = hex_resolve(hostname)
local try = nmap.new_try(function() socket:close() return false end)
if not resolve then if not resolve then
stdnse.print_debug("Unable to resolve hostname.") return false, "Unable to resolve hostname"
return false
end end
if version == 4 then if version == 4 then
paystring = '04 01 00 50 ' .. sip .. ' 6e 6d 61 70 00' paystring = '04 01 00 50 ' .. sip .. ' 6e 6d 61 70 00'
payload = bin.pack("H",paystring) payload = bin.pack("H",paystring)
try(socket:send(payload)) local status, response = socket:send(payload)
local response = try(socket:receive()) if not status then
socket:close()
return false, response
end
status, response = socket:receive()
if not status then
socket:close()
return false, response
end
if #response < 2 then
socket:close()
return false, "Invalid or unknown SOCKS response"
end
local request_status = string.byte(response, 2) local request_status = string.byte(response, 2)
local err = string.format("Unknown response (0x%02x)", request_status)
if(request_status == 0x5a) then if(request_status == 0x5a) then
stdnse.print_debug("Socks4: Received \"Request Granted\" from proxy server\n") stdnse.print_debug('Socks4: Received "Request Granted" from proxy server')
return socket return true, socket
end end
if(request_status == 0x5b) then if(request_status == 0x5b) then
stdnse.print_debug("Socks4: Received \"Request rejected or failed\" from proxy server") err = "Request rejected or failed"
elseif (request_status == 0x5c) then elseif (request_status == 0x5c) then
stdnse.print_debug("Socks4: Received \"request failed because client is not running identd\" from proxy server") err = "request failed because client is not running identd"
elseif (request_status == 0x5d) then elseif (request_status == 0x5d) then
stdnse.print_debug("Socks4: Received \"request failed because client's identd could not confirm" .. err = "request failed because client program and identd report different user-ids"
"\nthe user ID string in the request from proxy server")
end end
return false stdnse.print_debug('Socks4: Received "%s" from proxy server', err)
return false, err
end end
if version == 5 then if version == 5 then
local payload = bin.pack("H",'05 01 00') local payload = bin.pack("H",'05 01 00')
try(socket:send(payload)) local status, err = socket:send(payload)
local auth = try(socket:receive()) if not status then
socket:close()
return false, err
end
local auth
status, auth = socket:receive()
local r2 = string.byte(auth,2) local r2 = string.byte(auth,2)
-- If Auth is required, proxy is closed, skip next test -- If Auth is required, proxy is closed, skip next test
if(r2 ~= 0x00) then if(r2 ~= 0x00) then
stdnse.print_debug("Socks5: Authentication required") err = "Authentication Required"
else else
-- If no Auth is required, try to establish connection -- If no Auth is required, try to establish connection
stdnse.print_debug("Socks5: No authentication required") stdnse.print_debug("Socks5: No authentication required")
-- Socks5 second payload: Version, Command, Null, Address type, Ip-Address, Port number -- Socks5 second payload: Version, Command, Null, Address type, Ip-Address, Port number
paystring = '05 01 00 01 ' .. sip .. '00 50' paystring = '05 01 00 01 ' .. sip .. '00 50'
payload = bin.pack("H",paystring) payload = bin.pack("H",paystring)
try(socket:send(payload)) status, err = socket:send(payload)
local z = try(socket:receive()) if not status then
socket:close()
return false, err
end
local z
status, z = socket:receive()
if not status then
socket:close()
return false, z
end
local request_status = string.byte(z, 2) local request_status = string.byte(z, 2)
err = string.format("Unknown response (0x%02x)", request_status)
if (request_status == 0x00) then if (request_status == 0x00) then
stdnse.print_debug("Socks5: Received \"Request Granted\" from proxy server\n") stdnse.print_debug('Socks5: Received "Request Granted" from proxy server')
return socket return true, socket
elseif(request_status == 0x01) then elseif(request_status == 0x01) then
stdnse.print_debug("Socks5: Received \"General failure\" from proxy server") err = "General Failure"
elseif (request_status == 0x02) then elseif (request_status == 0x02) then
stdnse.print_debug("Socks5: Received \"Connection not allowed by ruleset\" from proxy server") err = "Connection not allowed by ruleset"
elseif (request_status == 0x03) then elseif (request_status == 0x03) then
stdnse.print_debug("Socks5: Received \"Network unreachable\" from proxy server") err = "Network unreachable"
elseif (request_status == 0x04) then elseif (request_status == 0x04) then
stdnse.print_debug("Socks5: Received \"Host unreachable\" from proxy server") err = "Host unreachable"
elseif (request_status == 0x05) then elseif (request_status == 0x05) then
stdnse.print_debug("Socks5: Received \"Connection refused by destination host\" from proxy server") err = "Connection refused by destination host"
elseif (request_status == 0x06) then elseif (request_status == 0x06) then
stdnse.print_debug("Socks5: Received \"TTL Expired\" from proxy server") err = "TTL Expired"
elseif (request_status == 0x07) then elseif (request_status == 0x07) then
stdnse.print_debug("Socks5: Received \"command not supported / protocol error\" from proxy server") err = "command not supported / protocol error"
elseif (request_status == 0x08) then elseif (request_status == 0x08) then
stdnse.print_debug("Socks5: Received \"Address type not supported\" from proxy server") err = "Address type not supported"
end end
end end
return false stdnse.print_debug('Socks5: Received "%s" from proxy server', err)
return false, err
end end
stdnse.print_debug("Unrecognized proxy type"); return false, "Invalid SOCKS version"
return false
end end
--- Checks if two different responses are equal, --- Checks if two different responses are equal,

View File

@@ -65,11 +65,8 @@ local function custom_test(host, port, test_url, pattern)
test_url = url_table.path test_url = url_table.path
-- make requests -- make requests
local err status4, get_r4, cstatus4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
err, status4, get_r4, cstatus4 = pcall(proxy.test_get, host, port, "socks4", test_url, hostname, pattern) status5, get_r5, cstatus5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
status4 = err and status4
err, status5, get_r5, cstatus5 = pcall(proxy.test_get, host, port, "socks5", test_url, hostname, pattern)
status5 = err and status5
fstatus = status4 or status5 fstatus = status4 or status5
if(cstatus4) then response[#response+1]="socks4" end if(cstatus4) then response[#response+1]="socks4" end
@@ -108,11 +105,8 @@ local function default_test(host, port)
local test_url = "/" local test_url = "/"
local hostname = "www.google.com" local hostname = "www.google.com"
local pattern = "^server: gws" local pattern = "^server: gws"
local err status4, get_r4, cstatus4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
err, status4, get_r4, cstatus4 = pcall(proxy.test_get, host, port, "socks4", test_url, hostname, pattern) status5, get_r5, cstatus5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
status4 = err and status4
err, status5, get_r5, cstatus5 = pcall(proxy.test_get, host, port, "socks5", test_url, hostname, pattern)
status5 = err and status5
fstatus = status4 or status5 fstatus = status4 or status5
if(cstatus4) then response[#response+1]="socks4" end if(cstatus4) then response[#response+1]="socks4" end
@@ -129,10 +123,8 @@ local function default_test(host, port)
test_url = "/" test_url = "/"
hostname = "www.wikipedia.org" hostname = "www.wikipedia.org"
pattern = "wikimedia" pattern = "wikimedia"
err, status4, get_r4, cstatus4 = pcall(proxy.test_get, host, port, "socks4", test_url, hostname, pattern) status4, get_r4, cstatus4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
status4 = err and status4 status5, get_r5, cstatus5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
err, status5, get_r5, cstatus5 = pcall(proxy.test_get, host, port, "socks5", test_url, hostname, pattern)
status5 = err and status5
if(status4) then fstatus = true; response[#response+1]="socks4" end if(status4) then fstatus = true; response[#response+1]="socks4" end
if(status5) then fstatus = true; response[#response+1]="socks5" end if(status5) then fstatus = true; response[#response+1]="socks5" end
@@ -146,10 +138,8 @@ local function default_test(host, port)
test_url = "/" test_url = "/"
hostname = "www.computerhistory.org" hostname = "www.computerhistory.org"
pattern = "museum" pattern = "museum"
err, status4, get_r4, cstatus4 = pcall(proxy.test_get, host, port, "socks4", test_url, hostname, pattern) status4, get_r4, cstatus4 = proxy.test_get(host, port, "socks4", test_url, hostname, pattern)
status4 = err and status4 status5, get_r5, cstatus5 = proxy.test_get(host, port, "socks5", test_url, hostname, pattern)
err, status5, get_r5, cstatus5 = pcall(proxy.test_get, host, port, "socks5", test_url, hostname, pattern)
status5 = err and status5
if(status4) then fstatus = true; response[#response+1]="socks4" end if(status4) then fstatus = true; response[#response+1]="socks4" end
if(status5) then fstatus = true; response[#response+1]="socks5" end if(status5) then fstatus = true; response[#response+1]="socks5" end