local brute = require "brute" local comm = require "comm" local creds = require "creds" local shortport = require "shortport" local stdnse = require "stdnse" description=[[ Performs brute force password auditing against IRC (Internet Relay Chat) servers. ]] --- -- @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 -- author = "Patrik Karlsson" license = "Same as Nmap--See https://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, data = 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, creds.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() return stdnse.generate_random_string(9, "abcdefghijklmnopqrstuvwxyz") 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 if ( code ) then return false, ("Failed to check password requirements, unknown code (%d)"):format(code) else return false, "Failed to check password requirements" end 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 local result status, result = engine:start() return result end