diff --git a/CHANGELOG b/CHANGELOG index 95c6c036b..07cb5676b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added the script irc-brute that performs password guessing against + password protected IRC servers. [Patrik] + o [NSE] Added the script nessus-brute that performs password guessing against Nessus using the NTP 1.2 protocol. [Patrik] diff --git a/scripts/irc-brute.nse b/scripts/irc-brute.nse new file mode 100644 index 000000000..ca1394de2 --- /dev/null +++ b/scripts/irc-brute.nse @@ -0,0 +1,134 @@ +description=[[ +Performs password guessing agains the IRC service +]] + +--- +-- @usage +-- nmap --script irc-brute -p 6667 +-- +-- @output +-- PORT STATE SERVICE +-- 6667/tcp open irc +-- | irc-brute: +-- | Accounts +-- | password - Valid credentials +-- | Statistics +-- |_ Performed 1927 guesses in 36 seconds, average tps: 74 +-- + +-- +-- Version 0.1 +-- Created 26/10/2011 - v0.1 - created by Patrik Karlsson +-- + +require 'brute' +require 'shortport' +require 'comm' + +author = "Patrik Karlsson " +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories={"brute","intrusive"} + +portrule = shortport.port_or_service({6666,6667,6697,6679},{"irc","ircs"}) + +Driver = { + + new = function(self, host, port, opts) + local o = { host = host, port = port, opts = opts or {} } + setmetatable(o, self) + self.__index = self + return o + end, + + connect = function(self) + -- the high timeout should take delays from ident into consideration + local s, r, opts, _ = comm.tryssl(self.host, + self.port, + '', + { timeout = self.opts.timeout or 10000 } ) + if ( not(s) ) then + return false, "Failed to connect to server" + end + self.socket = s + return true + end, + + login = function(self, _, password) + local msg = ("PASS %s\r\nNICK nmap_brute\r\nUSER anonymous 0 * :Nmap brute\r\n"):format(password) + local status = self.socket:send(msg) + local success = false + + if ( not(status) ) then + local err = brute.Error:new( data ) + -- This might be temporary, set the retry flag + err:setRetry( true ) + return false, err + end + + repeat + local status, response = self.socket:receive_buf("\r?\n", false) + -- we check for the RPL_WELCOME message, if we don't see it, + -- we failed to authenticate + if ( status and response:match("^:.-%s(%d*)%s") == "001" ) then + success = true + end + until(not(status)) + + if (success) then + return true, brute.Account:new("", password, creds.State.VALID) + end + return false, brute.Error:new("Incorrect password") + end, + + disconnect = function(self) return self.socket:close() end, +} + +local function random_nick() + local nick = "" + for i = 0, 8, 1 do + nick = nick .. string.char(math.random(97, 122)) -- lowercase ascii + end + return nick +end + +local function needsPassword(host, port) + local msg = ("NICK %s\r\nUSER anonymous 0 * :Nmap brute\r\n"):format(random_nick()) + local s, r, opts, _ = comm.tryssl(host, port, msg, { timeout = 15000 } ) + local err, code + + repeat + local status, response = s:receive_buf("\r?\n", false) + if ( status ) then + code = tonumber(response:match("^:.-%s(%d*)%s")) + -- break after first code + if (code == 001 ) then + err = "The IRC service does not require authentication" + break + elseif( code ) then + break + end + end + until(not(status)) + if (code == 464) then + return true + end + return false, ("Failed to check password requirements, unknown code (%d)"):format(code) +end + + +action = function(host, port) + + local status, err = needsPassword(host, port) + if ( not(status) ) then + return stdnse.format_output(false, err) + end + + local engine = brute.Engine:new(Driver, host, port) + engine.options.script_name = SCRIPT_NAME + engine.options.firstonly = true + engine.options.passonly = true + status, result = engine:start() + + return result + +end \ No newline at end of file diff --git a/scripts/script.db b/scripts/script.db index 2cd73377f..18a12ce14 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -120,6 +120,7 @@ Entry { filename = "ip-geolocation-geoplugin.nse", categories = { "discovery", " Entry { filename = "ip-geolocation-ipinfodb.nse", categories = { "discovery", "external", "safe", } } Entry { filename = "ip-geolocation-maxmind.nse", categories = { "discovery", "external", "safe", } } Entry { filename = "ipidseq.nse", categories = { "discovery", "safe", } } +Entry { filename = "irc-brute.nse", categories = { "brute", "intrusive", } } Entry { filename = "irc-info.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "irc-unrealircd-backdoor.nse", categories = { "exploit", "intrusive", "malware", "vuln", } } Entry { filename = "iscsi-brute.nse", categories = { "brute", "intrusive", } }