1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-17 21:19:01 +00:00

Merge r19520:r20039 from nmap-exp/djalal/nmap-add-targets. This will let NSE scripts to add new discovered targets to future Nmap scans.

This commit is contained in:
djalal
2010-09-01 01:50:34 +00:00
parent 81592359e4
commit c7c502b227
5 changed files with 336 additions and 1 deletions

View File

@@ -96,9 +96,14 @@
#include "TargetGroup.h" #include "TargetGroup.h"
#include "NmapOps.h" #include "NmapOps.h"
#include "nmap_error.h" #include "nmap_error.h"
#include "global_structures.h"
extern NmapOps o; extern NmapOps o;
#ifndef NOLUA
NewTargets *NewTargets::new_targets;
#endif
TargetGroup::TargetGroup() { TargetGroup::TargetGroup() {
Initialize(); Initialize();
} }
@@ -562,6 +567,97 @@ const std::list<struct sockaddr_storage> &TargetGroup::get_resolved_addrs(void)
return resolvedaddrs; return resolvedaddrs;
} }
#ifndef NOLUA
NewTargets *NewTargets::get (void) {
if (new_targets)
return new_targets;
new_targets = new NewTargets();
return new_targets;
}
NewTargets::NewTargets (void) {
Initialize();
}
void NewTargets::Initialize (void) {
history.clear();
while(!queue.empty())
queue.pop();
}
/* This private method is used to push new targets to the
* queue. It returns the number of targets in the queue. */
unsigned long NewTargets::push (const char *target) {
std::pair<std::set<std::string>::iterator, bool> pair_iter;
std::string tg(target);
if (tg.length() > 0) {
/* save targets in the scanned history here (NSE side). */
pair_iter = history.insert(tg);
/* A new target */
if (pair_iter.second == true) {
/* push target onto the queue for future scans */
queue.push(tg);
if (o.debugging > 3)
log_write(LOG_PLAIN, "New target %s pushed onto the queue.\n", tg.c_str());
}
}
return queue.size();
}
/* Reads a target from the queue and return it to be pushed
* onto Nmap scan queue */
std::string NewTargets::read (void) {
std::string str;
/* check to see it there are targets in the queue */
if (!new_targets->queue.empty()) {
str = new_targets->queue.front();
new_targets->queue.pop();
}
return str;
}
void NewTargets::clear (void) {
new_targets->history.clear();
}
unsigned long NewTargets::get_number (void) {
return new_targets->history.size();
}
unsigned long NewTargets::get_scanned (void) {
return new_targets->history.size() - new_targets->queue.size();
}
unsigned long NewTargets::get_queued (void) {
return new_targets->queue.size();
}
/* This is the function that is used by nse_nmaplib.cc to add
* new targets.
* Returns the number of targets in the queue on success, or 0 on
* failures or when the queue is empty. */
unsigned long NewTargets::insert (const char *target) {
if (*target) {
if (new_targets == NULL) {
error("Error: to add targets run with -sC or --script options.");
return 0;
}
if (o.current_scantype == SCRIPT_POST_SCAN) {
error("Error: adding targets is disabled in the Post-scanning phase.");
return 0;
}
}
return new_targets->push(target);
}
#endif
/* Lookahead is the number of hosts that can be /* Lookahead is the number of hosts that can be
checked (such as ping scanned) in advance. Randomize causes each checked (such as ping scanned) in advance. Randomize causes each
group of up to lookahead hosts to be internally shuffled around. group of up to lookahead hosts to be internally shuffled around.

View File

@@ -96,6 +96,8 @@
#define TARGETGROUP_H #define TARGETGROUP_H
#include <list> #include <list>
#include <queue>
#include <set>
#include <string> #include <string>
#include "nmap.h" #include "nmap.h"
@@ -172,6 +174,52 @@ class TargetGroup {
int namedhost; int namedhost;
}; };
/* Adding new targets is for NSE scripts */
#ifndef NOLUA
class NewTargets {
public:
NewTargets();
/* return a previous inserted target */
static std::string read (void);
/* clear the scanned_targets_cache */
static void clear (void);
/* get the number of all new added targets */
static unsigned long get_number (void);
/* get the number that have been scanned */
static unsigned long get_scanned (void);
/* get the number of queued targets left to scan */
static unsigned long get_queued (void);
/* get the new_targets object */
static NewTargets *get (void);
/* insert targets to the new_targets_queue */
static unsigned long insert (const char *target);
private:
/* unsigned long mex_new_targets; */
/* A queue to push new targets that were discovered by NSE scripts.
* Nmap will pop future targets from this queue. */
std::queue<std::string> queue;
/* A cache to save scanned targets specifiactions.
* (These are targets that were pushed to Nmap scan queue) */
std::set<std::string> history;
void Initialize();
/* Save new targets onto the queue */
unsigned long push (const char *target);
protected:
static NewTargets *new_targets;
};
#endif
class HostGroupState { class HostGroupState {
public: public:
HostGroupState(int lookahead, int randomize, char *target_expressions[], HostGroupState(int lookahead, int randomize, char *target_expressions[],

24
nmap.cc
View File

@@ -445,6 +445,8 @@ int nmap_main(int argc, char *argv[]) {
#ifndef NOLUA #ifndef NOLUA
/* Pre-Scan and Post-Scan script results datastructure */ /* Pre-Scan and Post-Scan script results datastructure */
ScriptResults *script_scan_results = NULL; ScriptResults *script_scan_results = NULL;
/* Only NSE scripts can add targets */
NewTargets *new_targets = NULL;
#endif #endif
TargetGroup *exclude_group = NULL; TargetGroup *exclude_group = NULL;
char myname[MAXHOSTNAMELEN + 1]; char myname[MAXHOSTNAMELEN + 1];
@@ -1608,6 +1610,7 @@ int nmap_main(int argc, char *argv[]) {
open_nse(); open_nse();
if (o.script) { if (o.script) {
new_targets = NewTargets::get();
script_scan_results = get_script_scan_results_obj(); script_scan_results = get_script_scan_results_obj();
script_scan(Targets, SCRIPT_PRE_SCAN); script_scan(Targets, SCRIPT_PRE_SCAN);
printscriptresults(script_scan_results, SCRIPT_PRE_SCAN); printscriptresults(script_scan_results, SCRIPT_PRE_SCAN);
@@ -1642,6 +1645,23 @@ int nmap_main(int argc, char *argv[]) {
// For purposes of random scan // For purposes of random scan
host_exp_group[num_host_exp_groups++] = strdup(host_spec); host_exp_group[num_host_exp_groups++] = strdup(host_spec);
} }
#ifndef NOLUA
/* Add the new NSE discovered targets to the scan queue */
if (o.script) {
if (new_targets != NULL) {
while (new_targets->get_queued() > 0 && num_host_exp_groups < o.ping_group_sz) {
std::string target_spec = new_targets->read();
if (target_spec.length())
host_exp_group[num_host_exp_groups++] = strdup(target_spec.c_str());
}
if (o.debugging > 3)
log_write(LOG_PLAIN,
"New targets in the scanned cache: %ld, pending ones: %ld.\n",
new_targets->get_scanned(), new_targets->get_queued());
}
}
#endif
if (num_host_exp_groups == 0) if (num_host_exp_groups == 0)
break; break;
delete hstate; delete hstate;
@@ -1876,12 +1896,14 @@ int nmap_main(int argc, char *argv[]) {
} }
o.numhosts_scanning = 0; o.numhosts_scanning = 0;
} while(!o.max_ips_to_scan || o.max_ips_to_scan > o.numhosts_scanned); } while(!o.max_ips_to_scan || o.max_ips_to_scan > o.numhosts_scanned);
#ifndef NOLUA #ifndef NOLUA
if (o.script) { if (o.script) {
script_scan(Targets, SCRIPT_POST_SCAN); script_scan(Targets, SCRIPT_POST_SCAN);
printscriptresults(script_scan_results, SCRIPT_POST_SCAN); printscriptresults(script_scan_results, SCRIPT_POST_SCAN);
script_scan_results->clear(); script_scan_results->clear();
delete new_targets;
new_targets = NULL;
} }
#endif #endif

View File

@@ -10,6 +10,7 @@ extern "C" {
#include "nmap_error.h" #include "nmap_error.h"
#include "NmapOps.h" #include "NmapOps.h"
#include "Target.h" #include "Target.h"
#include "TargetGroup.h"
#include "portlist.h" #include "portlist.h"
#include "service_scan.h" #include "service_scan.h"
#include "nmap_rpc.h" #include "nmap_rpc.h"
@@ -681,6 +682,58 @@ static int l_get_timing_level (lua_State *L)
return 1; return 1;
} }
/* Save new discovered targets.
*
* This function can take a Vararg expression:
* A vararg expression that represents targets (IPs or Hostnames).
*
* Returns two values if it receives target arguments:
* The number of targets that were added, or 0 on failures.
* An error message on failures.
*
* If this function was called without an argument then it
* will simply return the number of pending targets that are
* in the queue (waiting to be passed to Nmap).
*
* If the function was only able to add a one target, then we
* consider this success. */
static int l_add_targets (lua_State *L)
{
int n;
unsigned long ntarget = 0;
if (lua_gettop(L) > 0) {
for (n = 1; n <= lua_gettop(L); n++) {
if (!NewTargets::insert(luaL_checkstring(L, n)))
break;
ntarget++;
}
/* was able to add some targets */
if (ntarget) {
lua_pushnumber(L, ntarget);
return 1;
/* errors */
} else {
lua_pushnumber(L, ntarget);
lua_pushstring(L,
"Error: failed to add targets, post-scanning phase or no resources.");
return 2;
}
} else {
/* function called without arguments */
/* push the number of pending targets that are in the queue */
lua_pushnumber(L, NewTargets::insert(""));
return 1;
}
}
/* Return the number of added targets */
static int l_get_new_targets_num (lua_State *L)
{
lua_pushnumber(L, NewTargets::get_number());
return 1;
}
// returns a table with DNS servers known to nmap // returns a table with DNS servers known to nmap
static int l_get_dns_servers (lua_State *L) static int l_get_dns_servers (lua_State *L)
{ {
@@ -775,6 +828,8 @@ int luaopen_nmap (lua_State *L)
{"have_ssl", l_get_have_ssl}, {"have_ssl", l_get_have_ssl},
{"fetchfile", l_fetchfile}, {"fetchfile", l_fetchfile},
{"timing_level", l_get_timing_level}, {"timing_level", l_get_timing_level},
{"add_targets", l_add_targets},
{"new_targets_num",l_get_new_targets_num},
{"get_dns_servers", l_get_dns_servers}, {"get_dns_servers", l_get_dns_servers},
{"is_privileged", l_is_privileged}, {"is_privileged", l_is_privileged},
{"resolve", l_resolve}, {"resolve", l_resolve},

114
nselib/target.lua Normal file
View File

@@ -0,0 +1,114 @@
---
-- Utility functions to add new discovered targets to Nmap scan queue.
--
-- The library lets scripts to add new discovered targets to Nmap scan
-- queue. Only scripts that run in the script pre-scanning phase
-- (prerule) and the script scanning phase (hostrule and portrule) are
-- able to add new targets. Post-scanning scripts (postrule) are not
-- allowed to add new targets.
--
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
--
-- @args newtargets If specified, lets NSE scripts add new targets.
-- @args max-newtargets Sets the number of the maximum allowed
-- new targets. If set to 0 or less then there
-- is no limit. The default value is 0.
local type = type
local select = select
local unpack = unpack
local tonumber = tonumber
local stdnse = require "stdnse"
local nmap = require "nmap"
module ("target")
-- This is a special variable and it is a global one, so
-- scripts can check it to see if adding targets is allowed,
-- before calling target.add() function.
-- This variable will be set to true if the script argument
-- 'newtargets' was specified.
ALLOW_NEW_TARGETS = false
local newtargets, max_newtargets = stdnse.get_script_args("newtargets",
"max-newtargets")
if newtargets then
ALLOW_NEW_TARGETS = true
end
if max_newtargets then
max_newtargets = tonumber(max_newtargets)
else
max_newtargets = 0
end
--- Local function to calculate max allowed new targets
local calc_max_targets = function(targets)
if max_newtargets > 0 then
local pushed_targets = nmap.new_targets_num()
if pushed_targets >= max_newtargets then
return 0
elseif (targets + pushed_targets) > max_newtargets then
return (max_newtargets - pushed_targets)
end
end
return targets
end
--- Adds the passed arguments to the Nmap scan queue.
--
-- Only prerule, portrule and hostrule scripts can add new targets.
--
-- @param targets A variable number of targets. Target is a
-- string that represents an IP or a Hostname. If this function
-- is called without target arguments then it will return true
-- and the number of pending targets (waiting to be scanned).
-- @usage
-- local status, err = target.add("192.168.1.1")
-- local status, err = target.add("192.168.1.1","192.168.1.2",...)
-- local status, err = target.add("scanme.nmap.org","192.168.1.1",...)
-- local status, err = target.add(unpack(array_of_targets))
-- local status, pending_targets = target.add()
-- @return True if it has been able to add a minimum one target, or
-- False on failures and if no targets were added. If this
-- function is called without target arguments then it will
-- return true.
-- @return Number of added targets on success, or a string error
-- message in case of failures. If this function is called
-- without target arguments then it will return the number
-- of targets that are in the queue (waiting to be scanned).
add = function (...)
-- Force the check here, but it would be better if scripts
-- check ALLOW_NEW_TARGETS before calling target.add()
if not ALLOW_NEW_TARGETS then
stdnse.print_debug(3,
"Error: to add targets run with --script-args 'newtargets'")
return false, "Error: to add targets run with --script-args 'newtargets'"
end
local new_targets = {count = select("#", ...), ...}
-- function called without arguments
if new_targets.count == 0 then
return true, nmap.add_targets()
end
new_targets.count = calc_max_targets(new_targets.count)
if new_targets.count == 0 then
stdnse.print_debug(3,
"Warning: Maximum new targets reached, no more new targets.")
return false, "Warning: Maximum new targets reached, no more new targets."
end
local hosts, err = nmap.add_targets(unpack(new_targets,1,new_targets.count))
if hosts == 0 then
stdnse.print_debug(3, "%s", err)
return false, err
end
return true, hosts
end