From f1325d7c6f4debdef14aa30511bfee214f4a43e0 Mon Sep 17 00:00:00 2001 From: dmiller Date: Fri, 4 Oct 2024 18:21:25 +0000 Subject: [PATCH] Handle libssh2 errors on connect. Closes #2616. Fixes #1014 --- CHANGELOG | 4 ++++ scripts/ssh-auth-methods.nse | 5 +++-- scripts/ssh-brute.nse | 10 ++++++---- scripts/ssh-publickey-acceptance.nse | 13 ++++++------- scripts/ssh-run.nse | 5 +++-- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 95d6d80e9..c83c49a8d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ #Nmap Changelog ($Id$); -*-text-*- +o [NSE][GH#1014][GH#2616] SSH NSE scripts now catch connection errors thrown by + the libssh2 Lua binding, providing useful output instead of a backtrace. + [Joshua Rogers, Daniel Miller] + o Nmap will now allow targets to be specified both on the command line and in an input file with -iL. Previously, if targets were provided in both places, only the targets in the input file would be scanned, and no notice was given diff --git a/scripts/ssh-auth-methods.nse b/scripts/ssh-auth-methods.nse index cea0ab404..bda586ce4 100644 --- a/scripts/ssh-auth-methods.nse +++ b/scripts/ssh-auth-methods.nse @@ -41,8 +41,9 @@ portrule = shortport.ssh function action (host, port) local result = stdnse.output_table() local helper = libssh2_util.SSHConnection:new() - if not helper:connect(host, port) then - return "Failed to connect to ssh server" + local status, err = helper:connect_pcall(host, port) + if not status then + return "Failed to connect to ssh server: " .. err end local authmethods = helper:list(username) diff --git a/scripts/ssh-brute.nse b/scripts/ssh-brute.nse index f3d37357e..b23fa8688 100644 --- a/scripts/ssh-brute.nse +++ b/scripts/ssh-brute.nse @@ -82,9 +82,7 @@ Driver = { local function password_auth_allowed (host, port) local helper = libssh2_util.SSHConnection:new() - if not helper:connect(host, port) then - return "Failed to connect to ssh server" - end + helper:connect(host, port) -- throws error on failure local methods = helper:list "root" if methods then for _, value in pairs(methods) do @@ -99,7 +97,11 @@ end function action (host, port) local timems = stdnse.parse_timespec(arg_timeout) --todo: use this! local ssh_timeout = 1000 * timems - if password_auth_allowed(host, port) then + local connected, auth_status = pcall(password_auth_allowed, host, port) + if not connected then + return "Failed to connect to ssh server: " .. auth_status + end + if auth_status then local options = { ssh_timeout = ssh_timeout, } diff --git a/scripts/ssh-publickey-acceptance.nse b/scripts/ssh-publickey-acceptance.nse index a006325ed..55a5ade64 100644 --- a/scripts/ssh-publickey-acceptance.nse +++ b/scripts/ssh-publickey-acceptance.nse @@ -61,12 +61,12 @@ function action (host, port) local status, result = helper:read_publickey(publickeys[i]) if not status then stdnse.verbose("Error reading key: " .. result) - elseif helper:connect(host, port) then + elseif helper:connect_pcall(host, port) then successes = successes + 1 local status, err = helper:publickey_canauth(usernames[j], result) if status then table.insert(r, "Key " .. publickeys[i] .. " accepted for user " .. usernames[j]) - stdnse.verbose("Found accepted key: " .. publickeys[i] .. " for user " .. usernames[j]) + stdnse.verbose("Found accepted key: " .. publickeys[i] .. " for user " .. usernames[j] .. " on host " .. host.ip .. ":" .. port.number) elseif err then stdnse.debug("Error in publickey_canauth: %s", err) end @@ -100,7 +100,7 @@ function action (host, port) local msg = sections[3] stdnse.debug("Checking key: " .. key .. " for user " .. user) key = base64.dec(key) - if helper:connect(host, port) then + if helper:connect_pcall(host, port) then successes = successes + 1 if helper:publickey_canauth(user, key) then table.insert(r, msg) @@ -128,14 +128,13 @@ function action (host, port) for j = 1, #usernames do for i = 1, #privatekeys do stdnse.debug("Checking key: " .. privatekeys[i] .. " for user " .. usernames[j]) - if helper:connect(host, port) then + if helper:connect_pcall(host, port) then successes = successes + 1 if not helper:publickey_auth(usernames[j], privatekeys[i], passphrases[i] or "") then - stdnse.verbose "Failed to authenticate" + stdnse.verbose("Failed to authenticate key " .. privatekeys[i] .. " for user " .. usernames[j] .. " on host " .. host.ip .. ":" .. port.number) else table.insert(r, "Key " .. privatekeys[i] .. " accepted for user " .. usernames[j]) - stdnse.verbose("Found accepted key: " .. privatekeys[i] .. " for user " .. usernames[j]) - + stdnse.verbose("Found accepted key: " .. privatekeys[i] .. " for user " .. usernames[j] .. " on host " .. host.ip .. ":" .. port.number) end helper:disconnect() else diff --git a/scripts/ssh-run.nse b/scripts/ssh-run.nse index e91fdbefe..e0b680444 100644 --- a/scripts/ssh-run.nse +++ b/scripts/ssh-run.nse @@ -61,8 +61,9 @@ end function action (host, port) local conn = libssh2_util.SSHConnection:new() - if not conn:connect(host, port) then - return "Failed to connect to ssh server" + local status, err = helper:connect_pcall(host, port) + if not status then + return "Failed to connect to ssh server: " .. err end if username and password and cmd then if not conn:password_auth(username, password) then