diff --git a/CHANGELOG b/CHANGELOG index 064870b88..4a87748b2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added tftp-enum by Alexander Rudakov. + o [NSE] Added openlookup-info by Toni Ruottu. o [NSE] Added amqp-info.nse by Sebastian Dragomir. diff --git a/nselib/data/tftplist.txt b/nselib/data/tftplist.txt new file mode 100644 index 000000000..96abf126f --- /dev/null +++ b/nselib/data/tftplist.txt @@ -0,0 +1,90 @@ +000000000000.cfg +000000000000-directory~.xml +323tosip1_1.bin +4601_02_readme_R2_3.txt +4601dbte1_82.bin +4602_02SWSIPreadme_R1_1.txt +4602dbte1_82.bin +4602sbte1_82.bin +4610_20_readme_R2_3.txt +4610_20_readme_SIP_R2_2.txt +4624_12_06readme_1_8_3.txt +4625_readme_2_5.txt +4690_010707.bin +4690_readme_1_7_7.txt +46xxreadme_111405.txt +46xxsettings.txt +46xxupgrade.scr +a01d01b2_3.bin +a02d01b2_3.bin +a10d01b2_3.bin +a20d01a2_3.bin +a20d01b2_3.bin +a25d01a2_5.bin +b01d01b2_3.bin +b02d01b2_3.bin +b10d01b2_3.bin +b20d01a2_3.bin +b20d01b2_3.bin +b25d01a2_5.bin +bbla0_83.bin +bootrom.ld +cisco_util +CP7912010301SIP050608A.sbin +cvt01_2_3.bin +cvt02_2_3.bin +cvt02sw_2_3.bin +def06r1_8_3.bin +def24r1_8_3.bin +dialplan.xml +gkdefault.cfg +infrared.txt +merlin2.pcm +OS79XX.TXT +P003-07-5-00.bin +P003-07-5-00.sbn +P0S3-07-5-00.bin +P0S3-07-5-00.loads +P0S3-07-5-00.sb2 +phbook00e011010455.txt +phone1.cfg +release.xml +RINGLIST.DAT +s10d01b2_2.bin +s20d01b2_2.bin +SEP000F34118045.cnf +SEP001562EA69E8.cnf +SEPDefault.cnf +SIP000F34118045.cnf +SIPinsertMAChere.cnf +SIP000F34118045.cnf +SIPinsertMAChere.cnf +SIPinsertMAChere.cnf +sip_4602ap1_1.ebin +sip_4602bt1_1.ebin +sip_4602D01A.txt +sip_4602D02A.txt +sip.cfg +SIPDefault.cnf +sip.ld +sipto323_1_1.ebin +sip.ver +SoundPointIPLocalization +SoundPointIPWelcome.wav +syncinfo.xml +test +test.txt +uip200_463enc.pac +uniden00e011030397.txt +unidencom.txt +XMLDefault.cnf.xml +router-confg +cisco-confg +gateway-confg +gw-confg +bridge-confg +admin-confg +vip-confg +sip-confg +voip-confg +myrouter-confg \ No newline at end of file diff --git a/scripts/script.db b/scripts/script.db index 173b3d6dd..ae74c92f7 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -237,6 +237,7 @@ Entry { filename = "targets-ipv6-multicast-slaac.nse", categories = { "broadcast Entry { filename = "targets-sniffer.nse", categories = { "broadcast", "discovery", "safe", } } Entry { filename = "targets-traceroute.nse", categories = { "discovery", "safe", } } Entry { filename = "telnet-brute.nse", categories = { "brute", "intrusive", } } +Entry { filename = "tftp-enum.nse", categories = { "discovery", "intrusive", } } Entry { filename = "upnp-info.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "vnc-brute.nse", categories = { "brute", "intrusive", } } Entry { filename = "vnc-info.nse", categories = { "default", "discovery", "safe", } } diff --git a/scripts/tftp-enum.nse b/scripts/tftp-enum.nse new file mode 100644 index 000000000..79892a466 --- /dev/null +++ b/scripts/tftp-enum.nse @@ -0,0 +1,201 @@ +description = [[ + Enumerates filenames at tftp server. + + This script is implementation of tftptheft python utility written by Sandro Gauci + Original utility can be found at http://code.google.com/p/tftptheft/ +]] + +--- +-- @usage nmap -sU -p 69 --script tftp-enum.nse --script-args="tftp-enum.filelist=customlist.txt" +-- +-- @args filelist - file name with list of filenames to enumerate at tftp server +-- +-- + +author = "Alexander Rudakov" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = { "discovery", "intrusive" } + +require'bin' +require'stdnse' +require'shortport' +require'datafiles' + +local REQUEST_ERROR = -1 +local FILE_FOUND = 1 +local FILE_NOT_FOUND = 2 + +portrule = shortport.portnumber(69, "udp") + +-- return a new array containing the concatenation of all of its +-- parameters. Scaler parameters are included in place, and array +-- parameters have their values shallow-copied to the final array. +-- Note that userdata and function values are treated as scalar. +local function array_concat(...) + local t = {} + for n = 1, select("#", ...) do + local arg = select(n, ...) + if type(arg) == "table" then + for _, v in ipairs(arg) do + t[#t + 1] = v + end + else + t[#t + 1] = arg + end + end + return t +end + +local generate_cisco_address_confg = function(base_address) + local filenames = {} + local octets = stdnse.strsplit("%.", base_address) + + for i = 0, 255 do + local address_confg = octets[1] .. "." .. octets[2] .. "." .. octets[3] .. "." .. i .. "-confg" + table.insert(filenames, address_confg) + end + + return filenames +end + +local generate_filenames = function(host) + local customlist = stdnse.get_script_args('tftp-enum.filelist') + local status, default_filenames = datafiles.parse_file(customlist or "nselib/data/tftplist.txt" , {}) + if not status then + stdnse.print_debug(1, "Can not open file with tftp file names list") + return {} + end + + local cisco_address_confg_filenames = generate_cisco_address_confg(host.ip) + + return array_concat(default_filenames, cisco_address_confg_filenames) +end + + +local create_tftp_file_request = function(filename) + return bin.pack('CC', 0x00, 0x01) .. filename .. bin.pack('C', 0x00) .. 'octet' .. bin.pack('C', 0x00) +end + +local check_file_present = function(host, port, filename) + stdnse.print_debug(1, ("checking file %s"):format(filename)) + + local file_request = create_tftp_file_request(filename) + + + local socket = nmap.new_socket() + socket:connect(host.ip, port.number, "udp") + local status, lhost, lport, rhost, rport = socket:get_info() + + + if (not (status)) then + stdnse.print_debug(1, ("error %s"):format(lhost)) + socket:close() + return REQUEST_ERROR + end + + + local bind_socket = nmap.new_socket("udp") + stdnse.print_debug(1, ("local port = %d"):format(lport)) + + socket:send(file_request) + socket:close() + + local bindOK, error = bind_socket:bind(nil, lport) + + + stdnse.print_debug(1, "starting listener") + + if (not (bindOK)) then + stdnse.print_debug(1, ("Error in bind %s"):format(error)) + bind_socket:close() + return REQUEST_ERROR + end + + + local recvOK, data = bind_socket:receive() + + if (not (recvOK)) then + stdnse.print_debug(1, ("Error in receive %s"):format(data)) + bind_socket:close() + return REQUEST_ERROR + end + + if (data:byte(1) == 0x00 and data:byte(2) == 0x03) then + bind_socket:close() + return FILE_FOUND + elseif (data:byte(1) == 0x00 and data:byte(2) == 0x05) then + bind_socket:close() + return FILE_NOT_FOUND + else + bind_socket:close() + return REQUEST_ERROR + end + + return FILE_NOT_FOUND +end + +--- Generates a random string of the requested length. This can be used to check how hosts react to +-- weird username/password combinations. +-- @param length (optional) The length of the string to return. Default: 8. +-- @param set (optional) The set of letters to choose from. Default: upper, lower, numbers, and underscore. +-- @return The random string. +local function get_random_string(length, set) + if (length == nil) then + length = 8 + end + + if (set == nil) then + set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" + end + + local str = "" + + -- Seed the random number, if we haven't already + if (not (nmap.registry.oracle_enum_users) or not (nmap.registry.oracle_enum_users.seeded)) then + math.randomseed(os.time()) + nmap.registry.oracle_enum_users = {} + nmap.registry.oracle_enum_users.seeded = true + end + + for i = 1, length, 1 do + local random = math.random(#set) + str = str .. string.sub(set, random, random) + end + + return str +end + +local check_open_tftp = function(host, port) + local random_name = get_random_string() + local ret_value = check_file_present(host, port, random_name) + if (ret_value == FILE_FOUND or ret_value == FILE_NOT_FOUND) then + return true + else + return false + end +end + +action = function(host, port) + + if (not (check_open_tftp(host, port))) then + stdnse.print_debug(1, "tftp seems not active") + nmap.set_port_state(host, port, "closed") + return + end + + stdnse.print_debug(1, "tftp detected") + + nmap.set_port_state(host, port, "open") + + local results = {} + filenames = generate_filenames(host) + + for i, filename in ipairs(filenames) do + local request_status = check_file_present(host, port, filename) + if (request_status == FILE_FOUND) then + table.insert(results, filename .. " found") + end + end + + return stdnse.format_output(true, results) +end \ No newline at end of file