File: irc-brute.nse

package info (click to toggle)
nmap 7.40-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 50,080 kB
  • ctags: 26,777
  • sloc: ansic: 98,862; cpp: 64,063; python: 17,751; sh: 14,584; xml: 11,448; makefile: 2,635; perl: 2,585; yacc: 660; lex: 457; asm: 372; java: 45; objc: 43
file content (138 lines) | stat: -rw-r--r-- 3,624 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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 <ip>
--
-- @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 <patrik@cqure.net>
--


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