
Nmap Development mailing list archives
[NSE] Simple Banner Grabbingbanner.nse
From: jah <jah () zadkiel plus com>
Date: Sat, 01 Nov 2008 04:41:22 +0000
Hi folks, I was looking at Nmap's TODO list and saw mention of a banner grabbing script, so for some light relief I tidied-up a script I had for just such a purpose. It doesn't do anything clever, just connects a socket and returns anything presented to it. The main work is to tidy-up the banner for outputting. In order to keep things pretty it pre-empts nmap's hex encoding of unprintable characters so that output which is truncated to a lines width remains so. This is something I think showHTMLTitle could benefit from too - long titles are truncated to 65 chars, but this is ruined if there are unprintable chars in the title. I've set the character width of a line to 75 chars and the pretty output will look horrible if your command window is less than this, but this value "line_len" is easily changed. I'd love to hear what width everybody uses - I use 80 chars. Timeouts may well need some tweaking. If you envisioned bigger things or have other ideas for such a script then please holler. I find port numbers in the 20's often give-up the goods without being asked. One of my favourites is this: PORT STATE SERVICE 23/tcp open telnet | Banner: \xFF\xFB\x01\xFF\xFE"\x0A\x0D\x09NDS1060HUE-K-TSA Copyright by |_ ARESCOM 2003\x0A\x0D\x0A\x0D\x0A\x0DLogin Success!\x0A\x0D*NetDSL>* Ah, if everything was so easy... Regards, jah
id = "Banner" description = [[ A simple banner grabber. Connects to an open or open|filtered port and prints out anything issued by a listening service. The banner will be truncated to fit into a single line, but an extra line may be printed for every increase in the level of verbosity requested on the command line. ]] author = "jah <jah at zadkiel.plus.com>" license = "See Nmap License: http://nmap.org/book/man-legal.html" runlevel = 1 categories = {"discovery", "safe"} local nmap = require "nmap" local stdnse = require "stdnse" -- The width of your screen. You must choose, but choose wisely. -- For as the true number will bring you pretty output, -- the false number will take it from you. local line_len = 75 --- -- Always returns true. portrule = function( host, port ) return true end --- -- Grabs a banner and outputs it nicely formatted. action = function( host, port ) local out = grab_banner(host, port) return output( out ) end --- -- Connects to the target on the given port and returns any data issued by a listening service. -- @param host Host Table. -- @param port Port Table. -- @return String or nil if data was not recieved. function grab_banner(host, port) local socket = nmap.new_socket() local catch = function() stdnse.print_debug( "%s Connection to %s failed or was aborted! No Output for this Target.", id, host.ip ) socket:close() end local result, status, line = {} local try = nmap.new_try( catch ) socket:set_timeout( get_timeout() ) try( socket:connect( host.ip, port.number ) ) while true do local status, lines = socket:receive_lines(1) if not status then break else result[#result+1] = lines end end socket:close() if #result == 0 then return nil end return table.concat( result ) end --- -- Returns a number of milliseconds for use as a socket timeout value. The number is based on nmap's timing level: -- * T0 = 15000 ms -- * T1 = 10000 ms -- * T2 = 7000 ms -- * T3 = 5000 ms -- * T4 = 5000 ms -- * T5 = 5000 ms -- @return Number of milliseconds. function get_timeout() local timeout = {[0] = 15000, 10000, 7000} return timeout[nmap.timing_level()] or 5000 end --- -- Formats the banner for printing to the port script result. Non-printable characters are hex encoded and the banner is -- then truncated to fit into the number of lines of output desired. -- @param out String banner issued by a listening service. -- @return String formatted for output. function output( out ) if type(out) ~= "string" or out == "" then return nil end local fline_offset = 5 -- number of chars excluding script id not available to the script on the first line local fline_len = line_len -1 -id:len() -fline_offset -- number of chars allowed on first line local sline_len = line_len -1 -(fline_offset-2) -- number of chars allowed on subsequent lines local total_out_chars = fline_len + ( extra_output()*sline_len ) -- replace non-printable ascii chars - no need to do the whole string out = replace_nonprint(out, 1+total_out_chars) -- 1 extra char so we can truncate below. -- truncate banner to total_out_chars ensuring we remove whole hex encoded chars if out:len() > total_out_chars then while out:len() > total_out_chars do if (out:sub(-4,-1)):match("\\x%x%x") then out = out:sub(1,-1-4) else out = out:sub(1,-1-1) end end out = ("%s..."):format(out:sub(1,total_out_chars-3)) -- -3 for ellipsis end -- break into lines - this will look shit if line_len is more than the actual space available on a line... local ptr = fline_len local t = {} while true do if out:len() >= ptr then t[#t+1] = out:sub(1,ptr) out = out:sub(ptr+1,-1) ptr = sline_len else t[#t+1] = out break end end return table.concat(t,"\n") end --- -- Replaces characters with ASCII values outside of the range of standard printable -- characters (decimal 32 to 126 inclusive) with hex encoded equivalents. -- The second paramater dictates the number of characters to return, however, if the -- last character before the number is reached is one that needs replacing then up to -- three characters more than this number may be returned. -- If the second parameter is nil, no limit is applied to the number of characters -- that may be returned. -- @param s String on which to perform substitutions. -- @param len Number of characters to return. -- @return String. function replace_nonprint( s, len ) local t = {} local count = 0 for c in s:gmatch(".") do if c:byte() < 32 or c:byte() > 126 then t[#t+1] = ("\\x%s"):format( ("0%s"):format( ( (stdnse.tohex( c:byte() )):upper() ) ):sub(-2,-1) ) -- capiche count = count+4 else t[#t+1] = c count = count+1 end if type(len) == "number" and count >= len then break end end return table.concat(t) end --- -- Returns a number for each level of verbosity specified on the command line. -- Ignores level increases resulting from debugging level. -- @return Number function extra_output() return (nmap.verbosity()-nmap.debugging()>0 and nmap.verbosity()-nmap.debugging()) or 0 end
_______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://SecLists.Org
Current thread:
- [NSE] Simple Banner Grabbingbanner.nse jah (Oct 31)
- Re: [NSE] Simple Banner Grabbingbanner.nse Kris Katterjohn (Oct 31)
- Re: [NSE] Simple Banner Grabbingbanner.nse Fyodor (Nov 03)