-
-
Save bcoles/1231055 to your computer and use it in GitHub Desktop.
description = [[ | |
Retrieves the available commands and banners from a listening NNTP daemon. | |
The Network News Transfer Protocol (NNTP) is an Internet application protocol used for transporting Usenet news articles (netnews) between news servers and for reading and posting articles by end user client applications. | |
For more information about NNTP, see: | |
http://tools.ietf.org/html/rfc3977 | |
http://tools.ietf.org/html/rfc6048 | |
http://en.wikipedia.org/wiki/Network_News_Transfer_Protocol | |
]] | |
--- | |
-- @usage | |
-- nmap --script nntp-options --script-args nntp-options.timeout=10 -p <port> <host> | |
-- | |
-- @args nntp-options.timeout | |
-- Set the timeout in seconds. The default value is 10. | |
-- | |
-- @output | |
-- PORT STATE SERVICE REASON | |
-- 119/tcp open nntp syn-ack | |
-- | nntp-options: | |
-- | Banners: | |
-- | news.example.com - colobus 2.1 ready - (posting ok). | |
-- | Colobus 2.1 | |
-- | Commands: | |
-- | authinfo user Name|pass Password | |
-- | article [MessageID|Number] | |
-- | body [MessageID|Number] | |
-- | check MessageID | |
-- | group newsgroup | |
-- | head [MessageID|Number] | |
-- | list [active|active.times|newsgroups|subscriptions] | |
-- | listgroup newsgroup | |
-- | mode stream | |
-- | mode reader | |
-- | newgroups yymmdd hhmmss [GMT] [<distributions>] | |
-- | newnews newsgroups yymmdd hhmmss [GMT] [<distributions>] | |
-- | stat [MessageID|Number] | |
-- | takethis MessageID | |
-- | xgtitle [group_pattern] | |
-- | xhdr header [range|MessageID] | |
-- | xover [range] | |
-- |_ xpat header range|MessageID pat [morepat...] | |
-- | |
-- @changelog | |
-- 2011-06-28 - v0.1 - created by Brendan Coles <[email protected]> | |
-- | |
author = "Brendan Coles" | |
license = "Same as Nmap--See http://nmap.org/book/man-legal.html" | |
categories = {"discovery"} | |
local stdnse = require "stdnse" | |
local comm = require "comm" | |
local shortport = require "shortport" | |
portrule = shortport.port_or_service (119, "nntp", {"tcp"}) | |
action = function(host, port) | |
local result = {} | |
local banners = {} | |
local commands = {} | |
-- Set timeout | |
local timeout = tonumber(nmap.registry.args[SCRIPT_NAME .. '.timeout']) | |
if not timeout or timeout < 0 then timeout = 10 end | |
-- Connect and retrieve banner and commands | |
local command = "HELP\n" | |
stdnse.print_debug(1, ("%s: Connecting to %s:%s [Timeout: %ss]"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, timeout)) | |
local status, data = comm.exchange(host, port, command,{lines=100, proto=port.protocol, timeout=timeout*1000}) | |
if not status or not data then | |
stdnse.print_debug(1, ("%s: Retrieving data from %s:%s failed [Timeout expired]"):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) | |
return | |
end | |
-- Parse NNTP banners and commands | |
stdnse.print_debug(1, ("%s: Parsing data from %s:%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) | |
for line in string.gmatch(data, "[^\r^\n]+") do | |
if line ~= "" then | |
if string.match(line, "^500") then | |
stdnse.print_debug(1, ("%s: Server returned an error: %s"):format(SCRIPT_NAME, line)) | |
return | |
elseif string.match(line, "^100") then | |
stdnse.print_debug(1, ("%s: Server returned help text (%s:%s)"):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) | |
elseif string.match(line, "^20[01] (.+)$") then | |
local banner = string.match(line, "^20[01] (.+)$") | |
table.insert(banners, string.format("%s", banner)) | |
elseif string.match(line, "^ ([a-zA-Z]+)") then | |
-- commands with help description text | |
local cmd = string.match(line, "^ ([a-zA-Z]+ .+)$") | |
if cmd then | |
table.insert(commands, string.format("%s", cmd)) | |
else | |
-- commands only - no help description text | |
local cmd = string.match(line, "^ ([a-zA-Z]+)$") | |
if cmd then table.insert(commands, string.format("%s", cmd)) end | |
end | |
end | |
end | |
end | |
-- Add banners to results table | |
if next(banners) == nil then | |
stdnse.print_debug(1, ("%s: No banners were returned by %s:%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) | |
else | |
table.insert(result, "Banners:") | |
table.insert(result, banners) | |
end | |
-- Add commands to results table | |
if next(commands) == nil then | |
stdnse.print_debug(1, ("%s: No commands were returned by %s:%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number)) | |
else | |
table.insert(result, "Commands:") | |
table.insert(result, commands) | |
end | |
-- Return results | |
return stdnse.format_output(true, result) | |
end |
nmap NSE has changed in the past 6 years since this script was written. In particular, the version of lua in use and the way libraries are loaded.
I've updated the gist appropriately.
local stdnse = require "stdnse"
local comm = require "comm"
local shortport = require "shortport"
Nmap now loads the script successfully. This may or may not fix the issues you're encountering.
I've tried it out on a couple of servers with the above changes. The script returned the banner successfully, although failed to enumerate the available options. It's possible that there's an issue with the regex. In many instances, the NNTP server will require valid authentication credentials before providing the a response to the HELP
command, in which case the script will return only the banner.
There was an issue with the regex for identifying commands in instances where the NTTP server returned only a list of commands without associated help text describing each command.
I've fixed this.
There's another issue with the regex for identifying commands in instances where the commands aren't indented with two spaces. Ideally the script should be updated to parse the response properly - ie, identify a 100
response before attempting to parse the command list. I'll leave this as an exercise for someone else.
Doesn't work