mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41:29 +00:00
In addition to fitting better (brute library is the verb, creds library is the noun), this will allow creds.lua to use creds.Account internally where necessary (see subsequent commits) Also change old references to string argument "OPEN" into creds.State.VALID.
113 lines
2.7 KiB
Lua
113 lines
2.7 KiB
Lua
local brute = require "brute"
|
|
local creds = require "creds"
|
|
local redis = require "redis"
|
|
local shortport = require "shortport"
|
|
|
|
description = [[
|
|
Performs brute force passwords auditing against a Redis key-value store.
|
|
]]
|
|
|
|
---
|
|
-- @usage
|
|
-- nmap -p 6379 <ip> --script redis-brute
|
|
--
|
|
-- @output
|
|
-- PORT STATE SERVICE
|
|
-- 6379/tcp open unknown
|
|
-- | redis-brute:
|
|
-- | Accounts
|
|
-- | toledo - Valid credentials
|
|
-- | Statistics
|
|
-- |_ Performed 5000 guesses in 3 seconds, average tps: 1666
|
|
--
|
|
--
|
|
|
|
author = "Patrik Karlsson"
|
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
|
categories = {"intrusive", "brute"}
|
|
|
|
|
|
portrule = shortport.port_or_service(6379, "redis")
|
|
|
|
local function fail(err) return ("\n ERROR: %s"):format(err) end
|
|
|
|
Driver = {
|
|
|
|
new = function(self, host, port)
|
|
local o = { host = host, port = port }
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
return o
|
|
end,
|
|
|
|
connect = function( self )
|
|
self.helper = redis.Helper:new(self.host, self.port)
|
|
return self.helper:connect()
|
|
end,
|
|
|
|
login = function( self, username, password )
|
|
local status, response = self.helper:reqCmd("AUTH", password)
|
|
|
|
-- some error occurred, attempt to retry
|
|
if ( status and response.type == redis.Response.Type.ERROR and
|
|
"-ERR invalid password" == response.data ) then
|
|
return false, brute.Error:new( "Incorrect password" )
|
|
elseif ( status and response.type == redis.Response.Type.STATUS and
|
|
"+OK" ) then
|
|
return true, creds.Account:new( "", password, creds.State.VALID)
|
|
else
|
|
local err = brute.Error:new( response.data )
|
|
err:setRetry( true )
|
|
return false, err
|
|
end
|
|
|
|
end,
|
|
|
|
disconnect = function(self)
|
|
return self.helper:close()
|
|
end,
|
|
|
|
}
|
|
|
|
|
|
local function checkRedis(host, port)
|
|
|
|
local helper = redis.Helper:new(host, port)
|
|
local status = helper:connect()
|
|
if( not(status) ) then
|
|
return false, "Failed to connect to server"
|
|
end
|
|
|
|
local status, response = helper:reqCmd("INFO")
|
|
if ( not(status) ) then
|
|
return false, "Failed to request INFO command"
|
|
end
|
|
|
|
if ( redis.Response.Type.ERROR == response.type ) then
|
|
if ( "-ERR operation not permitted" == response.data ) or
|
|
( "-NOAUTH Authentication required." == response.data) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false, "Server does not require authentication"
|
|
end
|
|
|
|
action = function(host, port)
|
|
|
|
local status, err = checkRedis(host, port)
|
|
if ( not(status) ) then
|
|
return fail(err)
|
|
end
|
|
|
|
local engine = brute.Engine:new(Driver, host, port )
|
|
|
|
engine.options.script_name = SCRIPT_NAME
|
|
engine.options.firstonly = true
|
|
engine.options:setOption( "passonly", true )
|
|
|
|
local result
|
|
status, result = engine:start()
|
|
return result
|
|
end
|