9.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
10 High
CVSS2
Access Vector
NETWORK
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:L/Au:N/C:C/I:C/A:C
0.973 High
EPSS
Percentile
99.8%
Performs brute force password auditing against the DelugeRPC daemon.
See the documentation for the unpwdb library.
See the documentation for the creds library.
See the documentation for the brute library.
nmap --script deluge-rpc-brute -p 58846 <host>
PORT STATE SERVICE REASON TTL
58846/tcp open unknown syn-ack 0
| deluge-rpc-brute:
| Accounts
| admin:default - Valid credentials
| Statistics
|_ Performed 8 guesses in 1 seconds, average tps: 8
local brute = require "brute"
local creds = require "creds"
local shortport = require "shortport"
local string = require "string"
local have_zlib, zlib = pcall(require, "zlib")
description = [[
Performs brute force password auditing against the DelugeRPC daemon.
]]
---
-- @usage
-- nmap --script deluge-rpc-brute -p 58846 <host>
--
-- @output
-- PORT STATE SERVICE REASON TTL
-- 58846/tcp open unknown syn-ack 0
-- | deluge-rpc-brute:
-- | Accounts
-- | admin:default - Valid credentials
-- | Statistics
-- |_ Performed 8 guesses in 1 seconds, average tps: 8
author = "Claudiu Perta <[email protected]>"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive", "brute"}
portrule = shortport.port_or_service(58846, "deluge-rpc")
-- Returns an rencoded login request with the given username and password.
-- The format of the login command is the following:
--
-- ((0, 'daemon.login', ('username', 'password'), {}),)
--
-- This is inspired from deluge source code, in particular, see
-- http://git.deluge-torrent.org/deluge/tree/deluge/rencode.py
local rencoded_login_request = function(username, password)
local INT_POS_FIXED_START = 0
local INT_POS_FIXED_COUNT = 44
-- Dictionaries with length embedded in typecode.
local DICT_FIXED_START = 102
local DICT_FIXED_COUNT = 25
-- Strings with length embedded in typecode.
local STR_FIXED_START = 128
local STR_FIXED_COUNT = 64
-- Lists with length embedded in typecode.
local LIST_FIXED_START = 192
local LIST_FIXED_COUNT = 64
if #username > 0xff - STR_FIXED_START then
return nil, "Username too long"
elseif #password > 0xff - STR_FIXED_START then
return nil, "Password too long"
end
-- Encode the login request:
-- ((0, 'daemon.login', ('username', 'password'), {}),)
local request = string.pack("BBBB",
LIST_FIXED_START + 1,
LIST_FIXED_START + 4,
INT_POS_FIXED_START,
STR_FIXED_START + string.len("daemon.login")
)
.. "daemon.login"
.. string.pack("BB",
LIST_FIXED_START + 2,
STR_FIXED_START + string.len(username)
)
.. username
.. string.pack("B",
STR_FIXED_START + string.len(password)
)
.. password
.. string.pack("B", DICT_FIXED_START)
return request
end
Driver = {
new = function(self, host, port, invalid_users)
local o = {}
setmetatable(o, self)
self.__index = self
o.host = host
o.port = port
o.invalid_users = invalid_users
return o
end,
connect = function(self)
local status, err
self.socket = brute.new_socket()
self.socket:set_timeout(
((self.host.times and self.host.times.timeout) or 8) * 1000)
local status, err = self.socket:connect(self.host, self.port, "ssl")
if not status then
return false, brute.Error:new("Failed to connect to server")
end
return true
end,
disconnect = function(self)
self.socket:close()
end,
login = function(self, username, password)
if (self.invalid_users[username]) then
return false, brute.Error:new("Invalid user")
end
local request, err = rencoded_login_request(username, password)
if not request then
return false, brute.Error:new(err)
end
local status, err = self.socket:send(zlib.compress(request))
if not status then
return false, brute.Error:new("Login error")
end
local status, response = self.socket:receive()
if not status then
return false, brute.Error:new("Login error")
end
response = zlib.decompress(response)
if response:match("BadLoginError") then
local error_message = "Login error"
if response:match("Username does not exist") then
self.invalid_users[username] = true
error_message = "Username not found"
elseif response:match("Password does not match") then
error_message = "Username not found"
end
return false, brute.Error:new(error_message)
end
return true, creds.Account:new(username, password, creds.State.VALID)
end,
check = function(self)
return true
end
}
action = function(host, port)
if not have_zlib then
return "Error: zlib required!"
end
local invalid_users = {}
local engine = brute.Engine:new(Driver, host, port, invalid_users)
engine.options.script_name = SCRIPT_NAME
local status, results = engine:start()
return results
end
9.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
10 High
CVSS2
Access Vector
NETWORK
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:L/Au:N/C:C/I:C/A:C
0.973 High
EPSS
Percentile
99.8%