summaryrefslogtreecommitdiffstats
path: root/scripts/irc-info.nse
blob: 697a33ed9c44a415e170f2e089b1434554d51862 (plain)
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
local comm = require "comm"
local nmap = require "nmap"
local math = require "math"
local irc = require "irc"
local stdnse = require "stdnse"
local rand = require "rand"

description = [[
Gathers information from an IRC server.

It uses STATS, LUSERS, and other queries to obtain this information.
]]

---
-- @output
-- 6665/tcp open     irc
-- | irc-info:
-- |   server: asimov.freenode.net
-- |   version: ircd-seven-1.1.3(20111112-b71671d1e846,charybdis-3.4-dev). asimov.freenode.net
-- |   servers: 31
-- |   ops: 36
-- |   chans: 48636
-- |   users: 84883
-- |   lservers: 1
-- |   lusers: 4350
-- |   uptime: 511 days, 23:02:29
-- |   source host: source.example.com
-- |_  source ident: NONE or BLOCKED
--@xmloutput
-- <elem key="server">asimov.freenode.net</elem>
-- <elem key="version">ircd-seven-1.1.3(20111112-b71671d1e846,charybdis-3.4-dev). asimov.freenode.net </elem>
-- <elem key="servers">31</elem>
-- <elem key="ops">36</elem>
-- <elem key="chans">48636</elem>
-- <elem key="users">84883</elem>
-- <elem key="lservers">1</elem>
-- <elem key="lusers">4350</elem>
-- <elem key="uptime">511 days, 23:02:29</elem>
-- <elem key="source host">source.example.com</elem>
-- <elem key="source ident">NONE or BLOCKED</elem>

author = {"Doug Hoyte", "Patrick Donnelly"}

license = "Same as Nmap--See https://nmap.org/book/man-legal.html"

categories = {"default", "discovery", "safe"}

portrule = irc.portrule

local banner_timeout = 60

function action (host, port)
  local nick = rand.random_alpha(9)

  local output = stdnse.output_table()

  local sd, line = comm.tryssl(host, port,
    ("USER nmap +iw nmap :Nmap Wuz Here\nNICK %s\n"):format(nick),
    {request_timeout=6000})
  if not sd then return "Unable to open connection" end

  local buf = stdnse.make_buffer(sd, "\r?\n")

  while line do
    stdnse.debug2("%s", line)

    -- This one lets us know we've connected, pre-PONGed, and got a NICK
    -- Start of MOTD, we'll take the server name from here
    local info = line:match "^:([%w-_.]+) 375"
    if info then
      output.server = info
      sd:send("LUSERS\nVERSION\nSTATS u\nWHO " .. nick .. "\nQUIT\n")
    end

    -- MOTD could be missing, we want to handle that scenario as well
    info = line:match "^:([%w-_.]+) 422"
    if info then
      output.server = info
      sd:send("LUSERS\nVERSION\nSTATS u\nWHO " .. nick .. "\nQUIT\n")
    end

    -- NICK already in use
    info = line:match "^:([%w-_.]+) 433"
    if info then
      nick = rand.random_alpha(9)
      sd:send("NICK " .. nick .. "\n")
    end

    -- PING/PONG
    local dummy = line:match "^PING :(.*)"
    if dummy then
      sd:send("PONG :" .. dummy .. "\n")
    end

    -- Server version info
    info = line:match "^:[%w-_.]+ 351 %w+ ([^:]+)"
    if info then
      output.version = info
    end

    -- Various bits of info
    local users, invisible, servers = line:match "^:[%w-_.]+ 251 %w+ :There are (%d+) users and (%d+) invisible on (%d+) servers"
    if users then
      output.users = math.tointeger(users + invisible)
      output.servers = servers
    end

    local users, servers = line:match "^:[%w-_.]+ 251 %w+ :There are (%d+) users and %d+ services on (%d+) servers"
    if users then
      output.users = users
      output.servers = servers
    end

    info = line:match "^:[%w-_.]+ 252 %w+ (%d+) :"
    if info then
      output.ops = info
    end

    info = line:match "^:[%w-_.]+ 254 %w+ (%d+) :"
    if info then
      output.chans = info
    end

    -- efnet
    local clients, servers = line:match "^:[%w-_.]+ 255 %w+ :I have (%d+) clients and (%d+) server"
    if clients then
      output.lusers = clients
      output.lservers = servers
    end

    -- ircnet
    local clients, servers = line:match "^:[%w-_.]+ 255 %w+ :I have (%d+) users, %d+ services and (%d+) server"
    if clients then
      output.lusers = clients
      output.lservers = servers
    end

    local uptime = line:match "^:[%w-_.]+ 242 %w+ :Server Up (%d+ days, [%d:]+)"
    if uptime then
      output.uptime = uptime
    end

    local ident, host = line:match "^:[%w-_.]+ 352 %w+ %S+ (%S+) ([%w-_.]+)"
    if ident then
      if ident:find "^~" then
        output["source ident"] = "NONE or BLOCKED"
      else
        output["source ident"] = ident
      end
      output["source host"] = host
    end

    local err = line:match "^ERROR :(.*)"
    if err then
      output.error = err
    end

    line = buf()
  end

  if output.server then
    return output
  else
    return nil
  end
end