diff --git a/scripts/hadoop-datanode-info.nse b/scripts/hadoop-datanode-info.nse new file mode 100644 index 000000000..456e56234 --- /dev/null +++ b/scripts/hadoop-datanode-info.nse @@ -0,0 +1,54 @@ +description = [[ +Gets information from an Apache Hadoop DataNode HTTP status page. + +Information gathered: + * Log directory (relative to http://host:port/) + +For more information about hadoop, see: + * http://hadoop.apache.org/ + * http://en.wikipedia.org/wiki/Apache_Hadoop + * http://wiki.apache.org/hadoop/DataNode +]] + +--- +-- @usage +-- nmap --script hadoop-datanode-info.nse -p 50075 host +-- +-- @output +-- PORT STATE SERVICE REASON +-- 50075/tcp open hadoop-datanode syn-ack +-- | hadoop-datanode-info: +-- |_ Logs: /logs/ +--- + + +author = "john.r.bond@gmail.com" +license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified" +categories = {"default", "discovery", "safe"} + +require ("shortport") +require ("http") + +portrule = shortport.port_or_service ({50075}, "hadoop-datanode", {"tcp"}) + +action = function( host, port ) + + local result = {} + local uri = "/browseDirectory.jsp" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + port.version.name = "hadoop-datanode" + port.version.product = "Apache Hadoop" + nmap.set_port_version(host, port, "hardmatched") + local body = response['body']:gsub("%%","%%%%") + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + if body:match("([^][\"]+)\">Log") then + local logs = body:match("([^][\"]+)\">Log") + stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs)) + table.insert(result, ("Logs: %s"):format(logs)) + end + return stdnse.format_output(true, result) + end +end diff --git a/scripts/hadoop-jobtracker-info.nse b/scripts/hadoop-jobtracker-info.nse new file mode 100644 index 000000000..9c3be41d3 --- /dev/null +++ b/scripts/hadoop-jobtracker-info.nse @@ -0,0 +1,154 @@ +description = [[ +Gets information from an Apache Hadoop JobTracker HTTP status page. + +Information gathered: + * State of the JobTracker. + * Date/time the service was started + * Hadoop version + * Hadoop Compile date + * JobTracker ID + * Log directory (relative to http://host:port/) + * Associated TaskTrackers + * Optionally also user activity history + +For more information about Hadoop, see: + * http://hadoop.apache.org/ + * http://en.wikipedia.org/wiki/Apache_Hadoop + * http://wiki.apache.org/hadoop/JobTracker +]] + +--- +-- @usage +-- nmap --script hadoop-jobtracker-info [--script-args=hadoop-jobtracker-info.userinfo] -p 50030 host +-- +-- @output +-- 50030/tcp open hadoop-jobtracker +-- | hadoop-jobtracker-info: +-- | State: RUNNING +-- | Started: Wed May 11 22:33:44 PDT 2011, bob +-- | Version: 0.20.2 (f415ef415ef415ef415ef415ef415ef415ef415e) +-- | Compiled: Wed May 11 22:33:44 PDT 2011 by bob from unknown +-- | Identifier: 201111031342 +-- | Log Files: logs/ +-- | Tasktrackers: +-- | tracker1.example.com:50060 +-- | tracker2.example.com:50060 +-- | Userhistory: +-- | User: bob (Wed Sep 07 12:14:33 CEST 2011) +-- |_ User: bob (Wed Sep 07 12:14:33 CEST 2011) +-- --- + + +author = "john.r.bond@gmail.com" +license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified" +categories = {"default", "discovery", "safe"} + +require ("shortport") +require ("target") +require ("http") + +portrule = shortport.port_or_service ({50030}, "hadoop-jobtracker", {"tcp"}) + +get_userhistory = function( host, port ) + local results = {} + local uri = "/jobhistory.jsp?pageno=-1&search=" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + for line in string.gmatch(body, "[^\n]+") do + stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line)) + if line:match("job_[%d_]+") then + local user = line:match("([^][<>]+)") + local job_time = line:match("([^][<]+)") + stdnse.print_debug(1, ("%s: User: %s (%s)"):format(SCRIPT_NAME,user,job_time)) + table.insert( results, ("User: %s (%s)"):format(user,job_time)) + end + end + end + return results +end +get_tasktrackers = function( host, port ) + local results = {} + local uri = "/machines.jsp?type=active" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body'])) + for line in string.gmatch(response['body'], "[^\n]+") do + stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line)) + if line:match("href=\"[%w]+://([%w%.:]+)/\">tracker") then + local tasktracker = line:match("href=\".*//([%w%.:]+)/\">tracker") + stdnse.print_debug(1, ("%s: taskstracker %s"):format(SCRIPT_NAME,tasktracker)) + table.insert( results, tasktracker) + if target.ALLOW_NEW_TARGETS then + if tasktracker:match("([%w%.]+)") then + local newtarget = tasktracker:match("([%w%.]+)") + stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) + local status,err = target.add(newtarget) + end + end + end + end + end + return results +end +action = function( host, port ) + + local result = {} + local uri = "/jobtracker.jsp" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,response['body'])) + port.version.name = "hadoop-jobtracker" + port.version.product = "Apache Hadoop" + if response['body']:match("State:%s*([^][<]+)") then + local state = response['body']:match("State:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: State %s"):format(SCRIPT_NAME,state)) + table.insert(result, ("State: %s"):format(state)) + end + if response['body']:match("Started:%s*([^][<]+)") then + local started = response['body']:match("Started:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,started)) + table.insert(result, ("Started: %s"):format(started)) + end + if response['body']:match("Version:%s*([^][<]+)") then + local version = response['body']:match("Version:%s*([^][<]+)") + local versionNo = version:match("([^][,]+)") + local versionHash = version:match("[^][,]+%s+(%w+)") + stdnse.print_debug(1, ("%s: Version %s (%s)"):format(SCRIPT_NAME,versionNo,versionHash)) + table.insert(result, ("Version: %s (%s)"):format(versionNo,versionHash)) + port.version.version = versionNo + end + if response['body']:match("Compiled:%s*([^][<]+)") then + local compiled = response['body']:match("Compiled:%s*([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("Compiled: %s"):format(compiled)) + end + if response['body']:match("Identifier:%s*([^][<]+)") then + local identifier = response['body']:match("Identifier:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: Identifier %s"):format(SCRIPT_NAME,identifier)) + table.insert(result, ("Identifier: %s"):format(identifier)) + end + if response['body']:match("([%w/]+)\">Log<") then + local logfiles = response['body']:match("([%w/-_:%%]+)\">Log<") + stdnse.print_debug(1, ("%s: Log Files %s"):format(SCRIPT_NAME,logfiles)) + table.insert(result, ("Log Files: %s"):format(logfiles)) + end + nmap.set_port_version(host, port, "hardmatched") + local tasktrackers = get_tasktrackers (host, port) + table.insert(result, "Tasktrackers: ") + table.insert(result, tasktrackers) + if stdnse.get_script_args('hadoop-jobtracker-info.userinfo') then + local userhistory = get_userhistory (host, port) + table.insert(result, "Userhistory: ") + table.insert(result, userhistory) + end + return stdnse.format_output(true, result) + end +end diff --git a/scripts/hadoop-namenode-info.nse b/scripts/hadoop-namenode-info.nse new file mode 100644 index 000000000..251f46a2d --- /dev/null +++ b/scripts/hadoop-namenode-info.nse @@ -0,0 +1,139 @@ +description = [[ +Gets information from an Apache Hadoop NameNode HTTP status page. + +Information gathered: + * Date/time the service was started + * Hadoop version + * Hadoop compile date + * Upgrades status + * Filesystem directory (relative to http://host:port/) + * Log directory (relative to http://host:port/) + * Associated DataNodes. + +For more information about Hadoop, see: + * http://hadoop.apache.org/ + * http://en.wikipedia.org/wiki/Apache_Hadoop + * http://wiki.apache.org/hadoop/NameNode +]] + +--- +-- @usage +-- nmap --script hadoop-namenode-info -p 50070 host +-- +-- @output +-- PORT STATE SERVICE REASON +-- 50070/tcp open hadoop-namenode syn-ack +-- | hadoop-namenode-info: +-- | Started: Wed May 11 22:33:44 PDT 2011 +-- | Version: 0.20.2-cdh3u1, f415ef415ef415ef415ef415ef415ef415ef415e +-- | Compiled: Wed May 11 22:33:44 PDT 2011 by bob from unknown +-- | Upgrades: There are no upgrades in progress. +-- | Filesystem: /nn_browsedfscontent.jsp +-- | Logs: /logs/ +-- | Storage: +-- | Total Used (DFS) Used (Non DFS) Remaining +-- | 100 TB 85 TB 500 GB 14.5 TB +-- | Datanodes (Live): +-- | Datanode: datanode1.example.com:50075 +-- | Datanode: datanode2.example.com:50075 +--- + + +author = "john.r.bond@gmail.com" +license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified" +categories = {"default", "discovery", "safe"} + +require ("shortport") +require ("target") +require ("http") + +portrule = shortport.port_or_service ({50070}, "hadoop-namenode", {"tcp"}) + +get_datanodes = function( host, port, Status ) + local result = {} + local uri = "/dfsnodelist.jsp?whatNodes=" .. Status + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response" )) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + for datanodetmp in string.gmatch(body, "[%w%.:-_]+/browseDirectory.jsp") do + local datanode = datanodetmp:gsub("/browseDirectory.jsp","") + stdnse.print_debug(1, ("%s: Datanode %s"):format(SCRIPT_NAME,datanode)) + table.insert(result, ("Datanode: %s"):format(datanode)) + if target.ALLOW_NEW_TARGETS then + if datanode:match("([%w%.]+)") then + local newtarget = datanode:match("([%w%.]+)") + stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) + local status,err = target.add(newtarget) + end + end + end + end + return result +end + +action = function( host, port ) + + local result = {} + local uri = "/dfshealth.jsp" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + local capacity = {} + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + port.version.name = "hadoop-namenode" + port.version.product = "Apache Hadoop" + if body:match("Started:%s*([^][<]+)") then + local start = body:match("Started:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: Started %s"):format(SCRIPT_NAME,start)) + table.insert(result, ("Started: %s"):format(start)) + end + if body:match("Version:%s*([^][<]+)") then + local version = body:match("Version:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version)) + table.insert(result, ("Version: %s"):format(version)) + port.version.version = version + end + if body:match("Compiled:%s*([^][<]+)") then + local compiled = body:match("Compiled:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("Compiled: %s"):format(compiled)) + end + if body:match("Upgrades:%s*([^][<]+)") then + local upgrades = body:match("Upgrades:%s*([^][<]+)") + stdnse.print_debug(1, ("%s: Upgrades %s"):format(SCRIPT_NAME,upgrades)) + table.insert(result, ("Upgrades: %s"):format(upgrades)) + end + if body:match("([^][\"]+)\">Browse") then + local filesystem = body:match("([^][\"]+)\">Browse") + stdnse.print_debug(1, ("%s: Filesystem %s"):format(SCRIPT_NAME,filesystem)) + table.insert(result, ("Filesystem: %s"):format(filesystem)) + end + if body:match("([^][\"]+)\">Namenode") then + local logs = body:match("([^][\"]+)\">Namenode") + stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs)) + table.insert(result, ("Logs: %s"):format(logs)) + end + for i in string.gmatch(body, "[%d%.]+%s[KMGTP]B") do + table.insert(capacity,i) + end + stdnse.print_debug(1, ("%s: Total %s"):format(SCRIPT_NAME,capacity[3])) + stdnse.print_debug(1, ("%s: Used DFS (NonDFS) %s (%s)"):format(SCRIPT_NAME,capacity[4],capacity[5])) + stdnse.print_debug(1, ("%s: Remaining %s"):format(SCRIPT_NAME,capacity[6])) + table.insert(result,"Storage:") + table.insert(result,"Total\tUsed (DFS)\tUsed (Non DFS)\tRemaining") + table.insert(result, ("%s\t%s\t%s\t%s"):format(capacity[3],capacity[4],capacity[5],capacity[6])) + nmap.set_port_version(host, port, "hardmatched") + local datanodes_live = get_datanodes(host,port, "LIVE") + table.insert(result, "Datanodes (Live): ") + table.insert(result, datanodes_live) + local datanodes_dead = get_datanodes(host,port, "DEAD") + table.insert(result, "Datanodes (Dead): ") + table.insert(result, datanodes_dead) + return stdnse.format_output(true, result) + end +end diff --git a/scripts/hadoop-secondary-namenode-info.nse b/scripts/hadoop-secondary-namenode-info.nse new file mode 100644 index 000000000..f0bb07793 --- /dev/null +++ b/scripts/hadoop-secondary-namenode-info.nse @@ -0,0 +1,101 @@ +description = [[ +Gets information from an Apache Hadoop secondary NameNode HTTP status page. + +Information gathered: + * Date/time the service was started + * Hadoop version + * Hadoop compile date + * Hostname or IP address and port of the master NameNode server + * Last time a checkpoint was taken + * How often checkpoints are taken (in seconds) + * Log directory (relative to http://host:port/) + * File size of current checkpoint + +For more information about Hadoop, see: + * http://hadoop.apache.org/ + * http://en.wikipedia.org/wiki/Apache_Hadoop + * http://wiki.apache.org/hadoop/NameNode +]] + +--- +-- @usage +-- nmap --script hadoop-secondary-namenode-info -p 50090 host +-- +-- @output +-- PORT STATE SERVICE REASON +-- 50090/tcp open unknown syn-ack +-- | hadoop-secondary-namenode-info: +-- | Start: Wed May 11 22:33:44 PDT 2011 +-- | Version: 0.20.2, f415ef415ef415ef415ef415ef415ef415ef415e +-- | Compiled: Wed May 11 22:33:44 PDT 2011 by bob from unknown +-- | Log: /logs/ +-- | namenode: namenode1.example.com/192.0.1.1:8020 +-- | Last Checkpoint: Wed May 11 22:33:44 PDT 2011 +-- | Checkpoint Period: 3600 seconds +-- |_ Checkpoint Size: 12345678 MB +-- + +author = "john.r.bond@gmail.com" +license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified" +categories = {"default", "discovery", "safe"} + +require ("shortport") +require ("target") +require ("http") + +portrule = shortport.port_or_service ({50090}, "hadoop-secondary-namenode", {"tcp"}) + +action = function( host, port ) + + local result = {} + local uri = "/status.jsp" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Resposne")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + local stats = {} + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + port.version.name = "hadoop-secondary-namenode" + port.version.product = "Apache Hadoop" + -- Page isn't valid html :( + for i in string.gmatch(body,"\n[%w%s]+:%s+[^][\n]+") do + table.insert(stats,i:match(":%s+([^][\n]+)")) + end + stdnse.print_debug(1, ("%s: namenode %s"):format(SCRIPT_NAME,stats[1])) + stdnse.print_debug(1, ("%s: Start %s"):format(SCRIPT_NAME,stats[2])) + stdnse.print_debug(1, ("%s: Last Checkpoint %s"):format(SCRIPT_NAME,stats[3])) + stdnse.print_debug(1, ("%s: Checkpoint Period %s"):format(SCRIPT_NAME,stats[4])) + stdnse.print_debug(1, ("%s: Checkpoint Size %s"):format(SCRIPT_NAME,stats[5])) + table.insert(result, ("Start: %s"):format(stats[2])) + if body:match("Version:%s*([^][\n]+)") then + local version = body:match("Version:%s*([^][\n]+)") + stdnse.print_debug(1, ("%s: Version %s"):format(SCRIPT_NAME,version)) + table.insert(result, ("Version: %s"):format(version)) + port.version.version = version + end + if body:match("Compiled:%s*([^][\n]+)") then + local compiled = body:match("Compiled:%s*([^][\n]+)") + stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("Compiled: %s"):format(compiled)) + end + if body:match("([^][\"]+)\">Logs") then + local logs = body:match("([^][\"]+)\">Logs") + stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs)) + table.insert(result, ("Logs: %s"):format(logs)) + end + table.insert(result, ("Namenode: %s"):format(stats[1])) + table.insert(result, ("Last Checkpoint: %s"):format(stats[3])) + table.insert(result, ("Checkpoint Period: %s"):format(stats[4])) + table.insert(result, ("Checkpoint: Size %s"):format(stats[5])) + if target.ALLOW_NEW_TARGETS then + if stats[1]:match("([^][/]+)") then + local newtarget = stats[1]:match("([^][/]+)") + stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) + local status,err = target.add(newtarget) + end + end + + end + return stdnse.format_output(true, result) +end diff --git a/scripts/hadoop-tasktracker-info.nse b/scripts/hadoop-tasktracker-info.nse new file mode 100644 index 000000000..ebba03c93 --- /dev/null +++ b/scripts/hadoop-tasktracker-info.nse @@ -0,0 +1,71 @@ +description = [[ +Gets information from an Apache Hadoop TaskTracker HTTP status page. + +Information gathered: + * Hadoop version + * Hadoop Compile date + * Log directory (relative to http://host:port/) + +For more information about Hadoop, see: + * http://hadoop.apache.org/ + * http://en.wikipedia.org/wiki/Apache_Hadoop + * http://wiki.apache.org/hadoop/TaskTracker +]] + +--- +-- @usage +-- nmap --script hadoop-tasktracker-info -p 50060 host +-- +-- @output +-- PORT STATE SERVICE REASON +-- 50060/tcp open hadoop-tasktracker syn-ack +-- | hadoop-tasktracker-info: +-- | Version: 0.20.1 (f415ef415ef415ef415ef415ef415ef415ef415e) +-- | Compiled: Wed May 11 22:33:44 PDT 2011 by bob from unknown +-- |_ Logs: /logs/ +--- + + +author = "john.r.bond@gmail.com" +license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified" +categories = {"default", "discovery", "safe"} + +require ("shortport") +require ("http") + +portrule = shortport.port_or_service ({50060}, "hadoop-tasktracker", {"tcp"}) + +action = function( host, port ) + + local result = {} + local uri = "/tasktracker.jsp" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + port.version.name = "hadoop-tasktracker" + port.version.product = "Apache Hadoop" + if response['body']:match("Version:%s*([^][<]+)") then + local version = response['body']:match("Version:%s*([^][<]+)") + local versionNo = version:match("([^][,]+)") + local versionHash = version:match("[^][,]+%s+(%w+)") + stdnse.print_debug(1, ("%s: Version %s (%s)"):format(SCRIPT_NAME,versionNo,versionHash)) + table.insert(result, ("Version: %s (%s)"):format(versionNo,versionHash)) + port.version.version = version + end + if response['body']:match("Compiled:%s*([^][<]+)") then + local compiled = response['body']:match("Compiled:%s*([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Compiled %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("Compiled: %s"):format(compiled)) + end + if body:match("([^][\"]+)\">Log") then + local logs = body:match("([^][\"]+)\">Log") + stdnse.print_debug(1, ("%s: Logs %s"):format(SCRIPT_NAME,logs)) + table.insert(result, ("Logs: %s"):format(logs)) + end + nmap.set_port_version(host, port, "hardmatched") + return stdnse.format_output(true, result) + end +end diff --git a/scripts/hbase-master-info.nse b/scripts/hbase-master-info.nse new file mode 100644 index 000000000..71fa5cab9 --- /dev/null +++ b/scripts/hbase-master-info.nse @@ -0,0 +1,125 @@ +description = [[ +Gets information from an Apache HBase master HTTP status page. + +Information gathered: + * Hbase version + * Hbase compile date + * Hbase root eirectory + * Hadoop version + * Hadoop compile date + * Average load + * Zookeeper quorum server + * Associated region servers + +For more information about Hbase, see: + * http://hbase.apache.org/ + * http://wiki.apache.org/hadoop/Hbase + * http://wiki.apache.org/hadoop/TaskTracker +]] + +--- +-- @usage +-- nmap --script hbase-master-info -p 60010 host +-- +-- @output +-- | hbase-master-info: +-- | Hbase Version: 0.90.1 +-- | Hbase Compiled: Wed May 11 22:33:44 PDT 2011, bob +-- | HBase Root Directory: hdfs://master.example.com:8020/hbase +-- | Hadoop Version: 0.20 f415ef415ef415ef415ef415ef415ef415ef415e +-- | Hadoop Compiled: Wed May 11 22:33:44 PDT 2011, bob +-- | Average Load: 0.12 +-- | Zookeeper Quorum: zookeeper.example.com:2181 +-- | Region Servers: +-- | region1.example.com:60030 +-- |_ region2.example.com:60030 +--- + + +author = "john.r.bond@gmail.com" +license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified" +categories = {"default", "discovery", "safe"} + +require ("shortport") +require ("http") +require ("target") + +portrule = shortport.port_or_service ({60010}, "hbase-master", {"tcp"}) + +action = function( host, port ) + + local result = {} + local region_servers = {} + local uri = "/master.jsp" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + port.version.name = "hbase-master" + port.version.product = "Apache Hadoop Hbase" + if body:match("HBase%s+Version([^][<]+)") then + local version = body:match("HBase%s+Version([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s:Hbase Version %s"):format(SCRIPT_NAME,version)) + table.insert(result, ("Hbase Version: %s"):format(version)) + port.version.version = version + end + if body:match("HBase%s+Compiled([^][<]+)") then + local compiled = body:match("HBase%s+Compiled([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Hbase Compiled %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("Hbase Compiled: %s"):format(compiled)) + end + if body:match("Directory([^][<]+)") then + local compiled = body:match("Directory([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: HBase RootDirectory %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("HBase Root Directory: %s"):format(compiled)) + end + if body:match("Hadoop%s+Version([^][<]+)") then + local version = body:match("Hadoop%s+Version([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Hadoop Version %s"):format(SCRIPT_NAME,version)) + table.insert(result, ("Hadoop Version: %s"):format(version)) + end + if body:match("Hadoop%s+Compiled([^][<]+)") then + local compiled = body:match("Hadoop%s+Compiled([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Hadoop Compiled %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("Hadoop Compiled: %s"):format(compiled)) + end + if body:match("average([^][<]+)") then + local average = body:match("average([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Average Load %s"):format(SCRIPT_NAME,average)) + table.insert(result, ("Average Load: %s"):format(average)) + end + if body:match("Quorum([^][<]+)") then + local quorum = body:match("Quorum([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Zookeeper Quorum %s"):format(SCRIPT_NAME,quorum)) + table.insert(result, ("Zookeeper Quorum: %s"):format(quorum)) + if target.ALLOW_NEW_TARGETS then + if quorum:match("([%w%.]+)") then + local newtarget = quorum:match("([%w%.]+)") + stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) + local status,err = target.add(newtarget) + end + end + end + for line in string.gmatch(body, "[^\n]+") do + stdnse.print_debug(3, ("%s: Line %s\n"):format(SCRIPT_NAME,line)) + if line:match("maxHeap") then + local region_server= line:match("\">([^][<]+)") + stdnse.print_debug(1, ("%s: Region Server %s"):format(SCRIPT_NAME,region_server)) + table.insert(region_servers, region_server) + if target.ALLOW_NEW_TARGETS then + if region_server:match("([%w%.]+)") then + local newtarget = region_server:match("([%w%.]+)") + stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) + local status,err = target.add(newtarget) + end + end + end + end + nmap.set_port_version(host, port, "hardmatched") + table.insert(result,"Region Servers:") + table.insert(result,region_servers) + return stdnse.format_output(true, result) + end +end diff --git a/scripts/hbase-region-info.nse b/scripts/hbase-region-info.nse new file mode 100644 index 000000000..0b80f316b --- /dev/null +++ b/scripts/hbase-region-info.nse @@ -0,0 +1,87 @@ +description = [[ +Gets information from an Apache HBase region server HTTP status page. + +Information gathered: + * HBase version + * HBase compile date + * A bunch of metrics about the state of the region server + * Zookeeper quorum server + +For more information about Hbase, see: + * http://hbase.apache.org/ + * http://wiki.apache.org/hadoop/Hbase +]] + +--- +-- @usage +-- nmap --script hbase-region-info -p 60030 host +-- +-- @output +-- PORT STATE SERVICE REASON +-- 60030/tcp open hbase-region syn-ack +-- | hbase-region-info: +-- | Hbase Version: 0.90.1 +-- | Hbase Compiled: Wed May 11 22:33:44 PDT 2011, bob +-- | Metrics requests=0, regions=0, stores=0, storefiles=0, storefileIndexSize=0, memstoreSize=0, +-- | compactionQueueSize=0, flushQueueSize=0, usedHeap=0, maxHeap=0, blockCacheSize=0, +-- | blockCacheFree=0, blockCacheCount=0, blockCacheHitCount=0, blockCacheMissCount=0, +-- | blockCacheEvictedCount=0, blockCacheHitRatio=0, blockCacheHitCachingRatio=0 +-- |_ Zookeeper Quorum: zookeeper.example.com:2181 +--- + + +author = "john.r.bond@gmail.com" +license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified" +categories = {"default", "discovery", "safe"} + +require ("shortport") +require ("http") +require ("target") + +portrule = shortport.port_or_service ({60030}, "hbase-region", {"tcp"}) + +action = function( host, port ) + + local result = {} + local region_servers = {} + local uri = "/regionserver.jsp" + stdnse.print_debug(1, ("%s:HTTP GET %s:%s%s"):format(SCRIPT_NAME, host.targetname or host.ip, port.number, uri)) + local response = http.get( host.targetname or host.ip, port.number, uri ) + stdnse.print_debug(1, ("%s: Status %s"):format(SCRIPT_NAME,response['status-line'] or "No Response")) + if response['status-line'] and response['status-line']:match("200%s+OK") and response['body'] then + local body = response['body']:gsub("%%","%%%%") + stdnse.print_debug(2, ("%s: Body %s\n"):format(SCRIPT_NAME,body)) + port.version.name = "hbase-region" + port.version.product = "Apache Hadoop Hbase" + if body:match("HBase%s+Version([^][<]+)") then + local version = body:match("HBase%s+Version([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s:Hbase Version %s"):format(SCRIPT_NAME,version)) + table.insert(result, ("Hbase Version: %s"):format(version)) + port.version.version = version + end + if body:match("HBase%s+Compiled([^][<]+)") then + local compiled = body:match("HBase%s+Compiled([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Hbase Compiled %s"):format(SCRIPT_NAME,compiled)) + table.insert(result, ("Hbase Compiled: %s"):format(compiled)) + end + if body:match("Metrics([^][<]+)") then + local metrics = body:match("Metrics([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Metrics %s"):format(SCRIPT_NAME,metrics)) + table.insert(result, ("Metrics %s"):format(metrics)) + end + if body:match("Quorum([^][<]+)") then + local quorum = body:match("Quorum([^][<]+)"):gsub("%s+", " ") + stdnse.print_debug(1, ("%s: Zookeeper Quorum %s"):format(SCRIPT_NAME,quorum)) + table.insert(result, ("Zookeeper Quorum: %s"):format(quorum)) + if target.ALLOW_NEW_TARGETS then + if quorum:match("([%w%.]+)") then + local newtarget = quorum:match("([%w%.]+)") + stdnse.print_debug(1, ("%s: Added target: %s"):format(SCRIPT_NAME, newtarget)) + local status,err = target.add(newtarget) + end + end + end + nmap.set_port_version(host, port, "hardmatched") + return stdnse.format_output(true, result) + end +end diff --git a/scripts/script.db b/scripts/script.db index 7eb53992f..d615cfad7 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -71,6 +71,13 @@ Entry { filename = "ftp-vuln-cve2010-4221.nse", categories = { "intrusive", "vul Entry { filename = "ganglia-info.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "giop-info.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "gopher-ls.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "hadoop-datanode-info.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "hadoop-jobtracker-info.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "hadoop-namenode-info.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "hadoop-secondary-namenode-info.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "hadoop-tasktracker-info.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "hbase-master-info.nse", categories = { "default", "discovery", "safe", } } +Entry { filename = "hbase-region-info.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "hddtemp-info.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "hostmap.nse", categories = { "discovery", "external", "intrusive", } } Entry { filename = "http-affiliate-id.nse", categories = { "discovery", "safe", } }