1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Enable Nmap, Nping to use Npcap over Winpcap if available.

This commit is contained in:
dmiller
2016-06-14 14:16:46 +00:00
parent 7a9ab13bee
commit 67fd101b01
11 changed files with 233 additions and 22 deletions

View File

@@ -1,5 +1,9 @@
# Nmap Changelog ($Id$); -*-text-*-
o Nmap can now make full use of Npcap, the Nmap Project's packet sniffing
library for Windows. Most notably, this enables SYN scan and OS detection
against localhost. [Yang Luo]
o [NSE] Fix a crash that happened when trying to print the percent done of 0
NSE script threads:
timing.cc:710 bool ScanProgressMeter::printStats(double, const timeval*): Assertion 'ltime' failed.

View File

@@ -133,6 +133,10 @@
#include "linear.h"
#include "FPModel.h"
extern NmapOps o;
#ifdef WIN32
/* from libdnet's intf-win32.c */
extern "C" int g_has_npcap_loopback;
#endif
#include <math.h>
@@ -211,7 +215,11 @@ void FPNetworkControl::init(const char *ifname, devtype iftype) {
this->nsock_init = true;
/* Obtain raw socket or check that we can obtain an eth descriptor. */
if ((o.sendpref & PACKET_SEND_ETH) && iftype == devt_ethernet && ifname != NULL) {
if ((o.sendpref & PACKET_SEND_ETH) && (iftype == devt_ethernet
#ifdef WIN32
|| (g_has_npcap_loopback && iftype == devt_loopback)
#endif
) && ifname != NULL) {
/* We don't need to store the eth handler because FPProbes come with a
* suitable one (FPProbes::getEthernet()), we just attempt to obtain one
* to see if it fails. */

View File

@@ -168,6 +168,10 @@
#include <stdio.h>
extern NmapOps o;
#ifdef WIN32
/* from libdnet's intf-win32.c */
extern "C" int g_has_npcap_loopback;
#endif
struct idle_proxy_info {
Target host; /* contains name, IP, source IP, timing info, etc. */
@@ -662,7 +666,11 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
/* Now lets send some probes to check IP ID algorithm ... */
/* First we need a raw socket ... */
if ((o.sendpref & PACKET_SEND_ETH) && proxy->host.ifType() == devt_ethernet) {
if ((o.sendpref & PACKET_SEND_ETH) && (proxy->host.ifType() == devt_ethernet
#ifdef WIN32
|| (g_has_npcap_loopback && proxy->host.ifType() == devt_loopback)
#endif
)) {
if (!setTargetNextHopMAC(&proxy->host))
fatal("%s: Failed to determine dst MAC address for Idle proxy", __func__);
memcpy(proxy->eth.srcmac, proxy->host.SrcMACAddress(), 6);

View File

@@ -25,6 +25,8 @@
#include <Packet32.h>
#include <Ntddndis.h>
int g_has_npcap_loopback = 0;
struct ifcombo {
struct {
DWORD ipv4;
@@ -210,6 +212,98 @@ _adapter_address_to_entry(intf_t *intf, IP_ADAPTER_ADDRESSES *a,
entry->intf_len = (u_int) ((u_char *)ap - (u_char *)entry);
}
#ifdef _X86_
#define NPCAP_SOFTWARE_REGISTRY_KEY "SOFTWARE\\Npcap"
#else // AMD64
#define NPCAP_SOFTWARE_REGISTRY_KEY "SOFTWARE\\Wow6432Node\\Npcap"
#endif
int intf_get_loopback_name(char *buffer, int buf_size)
{
HKEY hKey;
DWORD type;
int size = buf_size;
int res = 0;
memset(buffer, 0, buf_size);
#ifndef _X86_
Wow64EnableWow64FsRedirection(FALSE);
#endif
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, NPCAP_SOFTWARE_REGISTRY_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
if (RegQueryValueExA(hKey, "Loopback", 0, &type, (LPBYTE)buffer, &size) == ERROR_SUCCESS && type == REG_SZ)
{
res = 1;
}
else
{
res = 0;
}
RegCloseKey(hKey);
}
else
{
res = 0;
}
#ifndef _X86_
Wow64EnableWow64FsRedirection(TRUE);
#endif
return res;
}
static IP_ADAPTER_ADDRESSES*
_update_tables_for_npcap_loopback(IP_ADAPTER_ADDRESSES *p)
{
IP_ADAPTER_ADDRESSES *a_prev = NULL;
IP_ADAPTER_ADDRESSES *a;
IP_ADAPTER_ADDRESSES *a_original_loopback_prev = NULL;
IP_ADAPTER_ADDRESSES *a_original_loopback = NULL;
IP_ADAPTER_ADDRESSES *a_npcap_loopback = NULL;
char npcap_loopback_name[1024];
int has_npcap_loopback = 0;
g_has_npcap_loopback = has_npcap_loopback = intf_get_loopback_name(npcap_loopback_name, 1024);
if (has_npcap_loopback == 0)
return p;
if (!p)
return p;
for (a = p; a != NULL; a = a->Next) {
if (a->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
a_original_loopback = a;
a_original_loopback_prev = a_prev;
}
else if (strcmp(a->AdapterName, npcap_loopback_name + strlen("\\Device\\")) == 0) {
a_npcap_loopback = a;
}
a_prev = a;
}
if (!a_original_loopback || !a_npcap_loopback)
return p;
a_npcap_loopback->IfType = a_original_loopback->IfType;
a_npcap_loopback->FirstUnicastAddress = a_original_loopback->FirstUnicastAddress;
a_npcap_loopback->FirstPrefix = a_original_loopback->FirstPrefix;
memset(a_npcap_loopback->PhysicalAddress, 0, ETH_ADDR_LEN);
if (a_original_loopback_prev) {
a_original_loopback_prev->Next = a_original_loopback_prev->Next->Next;
return p;
}
else if (a_original_loopback == p) {
return a_original_loopback->Next;
}
else {
return p;
}
}
static int
_refresh_tables(intf_t *intf)
{
@@ -245,6 +339,7 @@ _refresh_tables(intf_t *intf)
free(p);
return (-1);
}
p = _update_tables_for_npcap_loopback(p);
intf->iftable = p;
/*

View File

@@ -143,6 +143,10 @@
#define DLI_ERROR VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND)
#endif
#define PCAP_DRIVER_NONE 0
#define PCAP_DRIVER_WINPCAP 1
#define PCAP_DRIVER_NPCAP 2
extern NmapOps o;
/* internal functions */
@@ -163,14 +167,15 @@ void win_pre_init() {
fatal("failed to start winsock.\n");
}
/* Check if the NPF service is running on Windows, and try to start it if it's
/* Check if the NPCAP service is running on Windows, and try to start it if it's
not. Return true if it was running or we were able to start it, false
otherwise. */
static bool start_npf() {
static bool start_service(const char *svcname) {
SC_HANDLE scm, npf;
SERVICE_STATUS service;
bool npf_running;
int ret;
char startsvc[32];
scm = NULL;
npf = NULL;
@@ -180,7 +185,7 @@ static bool start_npf() {
error("Error in OpenSCManager");
goto quit_error;
}
npf = OpenService(scm, "npf", SC_MANAGER_CONNECT | SERVICE_QUERY_STATUS);
npf = OpenService(scm, svcname, SC_MANAGER_CONNECT | SERVICE_QUERY_STATUS);
if (npf == NULL) {
error("Error in OpenService");
goto quit_error;
@@ -195,19 +200,20 @@ static bool start_npf() {
if (npf_running) {
if (o.debugging > 1)
log_write(LOG_PLAIN, "NPF service is already running.\n");
log_write(LOG_PLAIN, "%s service is already running.\n", svcname);
return true;
}
/* NPF is not running. Try to start it. */
/* Service is not running. Try to start it. */
if (o.debugging > 1)
log_write(LOG_PLAIN, "NPF service is not running.\n");
log_write(LOG_PLAIN, "%s service is not running.\n", svcname);
ret = (int) ShellExecute(0, "runas", "net.exe", "start npf", 0, SW_HIDE);
Snprintf(startsvc, 32, "start %s", svcname);
ret = (int) ShellExecute(0, "runas", "net.exe", startsvc, 0, SW_HIDE);
if (ret <= 32) {
error("Unable to start NPF service: ShellExecute returned %d.\n\
Resorting to unprivileged (non-administrator) mode.", ret);
error("Unable to start %s service: ShellExecute returned %d.\n\
Resorting to unprivileged (non-administrator) mode.", svcname, ret);
return false;
}
@@ -246,6 +252,27 @@ static void init_dll_path()
}
}
/* If we find the Npcap driver, allow Nmap to load Npcap DLLs from the "\System32\Npcap" directory. */
static void init_npcap_dll_path()
{
BOOL(WINAPI *SetDllDirectory)(LPCTSTR);
char sysdir_name[512];
int len;
SetDllDirectory = (BOOL(WINAPI *)(LPCTSTR)) GetProcAddress(GetModuleHandle("kernel32.dll"), "SetDllDirectoryA");
if (SetDllDirectory == NULL) {
pfatal("Error in SetDllDirectory");
}
else {
len = GetSystemDirectory(sysdir_name, 480); // be safe
if (!len)
pfatal("Error in GetSystemDirectory (%d)", GetLastError());
strcat(sysdir_name, "\\Npcap");
if (SetDllDirectory(sysdir_name) == 0)
pfatal("Error in SetDllDirectory(\"System32\\Npcap\")");
}
}
/* Requires that win_pre_init() has already been called, also that
options processing has been done so that o.debugging is
available */
@@ -258,6 +285,7 @@ void win_init()
PMIB_IPADDRTABLE pIp = 0;
int i;
int numipsleft;
int pcap_driver;
init_dll_path();
@@ -284,6 +312,17 @@ void win_init()
o.have_pcap = true;
if(o.debugging > 2) printf("Trying to initialize WinPcap\n");
if (start_service("npcap"))
pcap_driver = PCAP_DRIVER_NPCAP;
else if (start_service("npf"))
pcap_driver = PCAP_DRIVER_WINPCAP;
else
pcap_driver = PCAP_DRIVER_NONE;
if (pcap_driver == PCAP_DRIVER_NPCAP)
init_npcap_dll_path();
pcapMutex = CreateMutex(NULL, 0, "Global\\DnetPcapHangAvoidanceMutex");
wait = WaitForSingleObject(pcapMutex, INFINITE);
PacketGetAdapterNames(pcaplist, &len);
@@ -306,7 +345,7 @@ void win_init()
--unprivileged. In that case don't bother them with a
potential UAC dialog when starting NPF. */
if (o.isr00t)
o.have_pcap = o.have_pcap && start_npf();
o.have_pcap = o.have_pcap && ((bool) pcap_driver);
}
#ifdef _MSC_VER
__except (1) {

View File

@@ -132,6 +132,10 @@
#include "common_modified.h"
extern NpingOps o;
#ifdef WIN32
/* from libdnet's intf-win32.c */
extern "C" int g_has_npcap_loopback;
#endif
NpingTargets::NpingTargets(){
memset(specs, 0, 1024*(sizeof(char *)) );
@@ -309,11 +313,11 @@ int NpingTargets::processSpecs(){
continue;
}
#ifdef WIN32
if (rnfo.ii.device_type == devt_loopback){
if (g_has_npcap_loopback == 0 && rnfo.ii.device_type == devt_loopback){
nping_warning(QT_2, "Skipping %s because Windows does not allow localhost scans (try --unprivileged).", mytarget->getTargetIPstr() );
delete mytarget;
continue;
}
}
#endif
/* Determine next hop */
if( rnfo.direct_connect ){
@@ -344,8 +348,17 @@ int NpingTargets::processSpecs(){
/* Determine next hop MAC address and target MAC address */
if( o.sendEth() ){
mytarget->determineNextHopMACAddress();
mytarget->determineTargetMACAddress(); /* Sets Target MAC only if is directly connected to us */
#ifdef WIN32
if (g_has_npcap_loopback == 1 && rnfo.ii.device_type == devt_loopback) {
mytarget->setNextHopMACAddress(mytarget->getSrcMACAddress());
}
else {
#endif
mytarget->determineNextHopMACAddress();
mytarget->determineTargetMACAddress(); /* Sets Target MAC only if is directly connected to us */
#ifdef WIN32
}
#endif
}
/* If we are in debug mode print target details */
if(o.getDebugging() >= DBG_3)

View File

@@ -19,6 +19,10 @@ extern "C" {
#include <assert.h>
extern NmapOps o;
#ifdef WIN32
/* from libdnet's intf-win32.c */
extern "C" int g_has_npcap_loopback;
#endif
enum {
DNET_METATABLE = lua_upvalueindex(1),
@@ -153,7 +157,11 @@ static int ethernet_open (lua_State *L)
const char *interface_name = luaL_checkstring(L, 2);
struct interface_info *ii = getInterfaceByName(interface_name, o.af());
if (ii == NULL || ii->device_type != devt_ethernet)
if (ii == NULL || ii->device_type != devt_ethernet
#ifdef WIN32
&& !(g_has_npcap_loopback && ii->device_type == devt_loopback)
#endif
)
return luaL_argerror(L, 2, "device is not valid ethernet interface");
udata->eth = open_eth_cached(L, 1, interface_name);
@@ -252,8 +260,13 @@ static int ip_send (lua_State *L)
Strncpy(dev, route.ii.devname, sizeof(dev));
if (route.ii.device_type != devt_ethernet)
if (! (route.ii.device_type == devt_ethernet
#ifdef WIN32
|| (g_has_npcap_loopback && route.ii.device_type == devt_loopback)
#endif
) ) {
goto usesock;
}
/* above we fallback to using the raw socket if we can't find an (ethernet)
* route to the host. From here on out it's ethernet all the way.

View File

@@ -140,6 +140,10 @@
#include <math.h>
extern NmapOps o;
#ifdef WIN32
/* from libdnet's intf-win32.c */
extern "C" int g_has_npcap_loopback;
#endif
/* 8 options:
* 0~5: six options for SEQ/OPS/WIN/T1 probes.
@@ -1415,7 +1419,11 @@ HostOsScan::HostOsScan(Target *t) {
rawsd = -1;
ethsd = NULL;
if ((o.sendpref & PACKET_SEND_ETH) && t->ifType() == devt_ethernet) {
if ((o.sendpref & PACKET_SEND_ETH) && (t->ifType() == devt_ethernet
#ifdef WIN32
|| (g_has_npcap_loopback && t->ifType() == devt_loopback)
#endif
)) {
if ((ethsd = eth_open_cached(t->deviceName())) == NULL)
fatal("%s: Failed to open ethernet device (%s)", __func__, t->deviceName());
rawsd = -1;
@@ -3511,7 +3519,7 @@ OsScanInfo::OsScanInfo(std::vector<Target *> &Targets) {
}
#ifdef WIN32
if (Targets[targetno]->ifType() == devt_loopback) {
if (g_has_npcap_loopback == 0 && Targets[targetno]->ifType() == devt_loopback) {
log_write(LOG_STDOUT, "Skipping OS Scan against %s because it doesn't work against your own machine (localhost)\n", Targets[targetno]->NameIP());
continue;
}

View File

@@ -147,6 +147,10 @@
#include <map>
extern NmapOps o;
#ifdef WIN32
/* from libdnet's intf-win32.c */
extern "C" int g_has_npcap_loopback;
#endif
void UltraScanInfo::log_overall_rates(int logt) {
log_write(logt, "Overall sending rates: %.2f packets / s", send_rate_meter.getOverallPacketRate(&now));
@@ -971,7 +975,11 @@ void UltraScanInfo::Init(std::vector<Target *> &Targets, struct scan_lists *pts,
requires it. */
if (isRawScan()) {
if (ping_scan_arp || (ping_scan_nd && o.sendpref != PACKET_SEND_IP_STRONG) || ((o.sendpref & PACKET_SEND_ETH) &&
Targets[0]->ifType() == devt_ethernet)) {
(Targets[0]->ifType() == devt_ethernet
#ifdef WIN32
|| (g_has_npcap_loopback && Targets[0]->ifType() == devt_loopback)
#endif
))) {
/* We'll send ethernet packets with dnet */
ethsd = eth_open_cached(Targets[0]->deviceName());
if (ethsd == NULL)
@@ -2664,7 +2672,7 @@ void ultra_scan(std::vector<Target *> &Targets, struct scan_lists *ports,
}
#ifdef WIN32
if (scantype != CONNECT_SCAN && Targets[0]->ifType() == devt_loopback) {
if (g_has_npcap_loopback == 0 && scantype != CONNECT_SCAN && Targets[0]->ifType() == devt_loopback) {
log_write(LOG_STDOUT, "Skipping %s against %s because Windows does not support scanning your own machine (localhost) this way.\n", scantype2str(scantype), Targets[0]->NameIP());
return;
}

View File

@@ -138,6 +138,10 @@
#include "xml.h"
extern NmapOps o;
#ifdef WIN32
/* from libdnet's intf-win32.c */
extern "C" int g_has_npcap_loopback;
#endif
/* Conducts an ARP ping sweep of the given hosts to determine which ones
are up on a local ethernet network */
@@ -556,6 +560,15 @@ static Target *setup_target(const HostGroupState *hs,
else
t->setSrcMACAddress(rnfo.ii.mac);
}
#ifdef WIN32
else if (g_has_npcap_loopback && rnfo.ii.device_type == devt_loopback) {
if (o.spoofMACAddress())
t->setSrcMACAddress(o.spoofMACAddress());
else
t->setSrcMACAddress(rnfo.ii.mac);
t->setNextHopMACAddress(t->SrcMACAddress());
}
#endif
t->setSourceSockAddr(&rnfo.srcaddr, sizeof(rnfo.srcaddr));
if (hs->current_batch_sz == 0) /* Because later ones can have different src addy and be cut off group */
o.decoys[o.decoyturn] = t->v4source();

View File

@@ -906,6 +906,8 @@ TracerouteState::TracerouteState(std::vector<Target *> &targets) {
assert(targets.size() > 0);
if ((o.sendpref & PACKET_SEND_ETH) && targets[0]->ifType() == devt_ethernet) {
/* No need to check for g_has_npcap_loopback on WIN32 because devt_loopback
* is checked earlier. */
ethsd = eth_open_cached(targets[0]->deviceName());
if (ethsd == NULL)
fatal("dnet: failed to open device %s", targets[0]->deviceName());