summaryrefslogtreecommitdiffstats
path: root/scripts/ssh-brute.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/ssh-brute.nse')
-rw-r--r--scripts/ssh-brute.nse113
1 files changed, 113 insertions, 0 deletions
diff --git a/scripts/ssh-brute.nse b/scripts/ssh-brute.nse
new file mode 100644
index 0000000..f3d3735
--- /dev/null
+++ b/scripts/ssh-brute.nse
@@ -0,0 +1,113 @@
+local shortport = require "shortport"
+local stdnse = require "stdnse"
+local brute = require "brute"
+local creds = require "creds"
+
+local libssh2_util = require "libssh2-utility"
+
+description = [[
+Performs brute-force password guessing against ssh servers.
+]]
+
+---
+-- @usage
+-- nmap -p 22 --script ssh-brute --script-args userdb=users.lst,passdb=pass.lst,ssh-brute.timeout=4s <target>
+--
+-- @output
+-- 22/ssh open ssh
+-- | ssh-brute:
+-- | Accounts
+-- | username:password
+-- | Statistics
+-- |_ Performed 32 guesses in 25 seconds.
+--
+-- @args ssh-brute.timeout Connection timeout (default: "5s")
+
+author = "Devin Bjelland"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {
+ 'brute',
+ 'intrusive',
+}
+
+portrule = shortport.ssh
+
+local arg_timeout = stdnse.get_script_args(SCRIPT_NAME .. ".timeout") or "5s"
+
+Driver = {
+ new = function (self, host, port, options)
+ stdnse.debug(2, "creating brute driver")
+ local o = {
+ helper = libssh2_util.SSHConnection:new(),
+ }
+ setmetatable(o, self)
+ self.__index = self
+ o.host = host
+ o.port = port
+ o.options = options
+ return o
+ end,
+
+ connect = function (self)
+ local status, err = self.helper:connect_pcall(self.host, self.port)
+ if not status then
+ stdnse.debug(2, "libssh2 error: %s", self.helper.session)
+ local err = brute.Error:new(self.helper.session)
+ err:setReduce(true)
+ return false, err
+ elseif not self.helper.session then
+ stdnse.debug(2, "failure to connect: %s", err)
+ local err = brute.Error:new(err)
+ err:setAbort(true)
+ return false, err
+ else
+ self.helper:set_timeout(self.options.ssh_timeout)
+ return true
+ end
+ end,
+
+ login = function (self, username, password)
+ stdnse.verbose(1, "Trying username/password pair: %s:%s", username, password)
+ local status, resp = self.helper:password_auth(username, password)
+ if status then
+ return true, creds.Account:new(username, password, creds.State.VALID)
+ end
+ return false, brute.Error:new "Incorrect password"
+ end,
+
+ disconnect = function (self)
+ return self.helper:disconnect()
+ end,
+}
+
+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
+ local methods = helper:list "root"
+ if methods then
+ for _, value in pairs(methods) do
+ if value == "password" then
+ return true
+ end
+ end
+ end
+ return false
+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 options = {
+ ssh_timeout = ssh_timeout,
+ }
+ local engine = brute.Engine:new(Driver, host, port, options)
+ engine.options.script_name = SCRIPT_NAME
+ local _, result = engine:start()
+ return result
+ else
+ return "Password authentication not allowed"
+ end
+end