1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 20:51:30 +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-*- # 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 o [NSE] Fix a crash that happened when trying to print the percent done of 0
NSE script threads: NSE script threads:
timing.cc:710 bool ScanProgressMeter::printStats(double, const timeval*): Assertion 'ltime' failed. timing.cc:710 bool ScanProgressMeter::printStats(double, const timeval*): Assertion 'ltime' failed.

View File

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

View File

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

View File

@@ -25,6 +25,8 @@
#include <Packet32.h> #include <Packet32.h>
#include <Ntddndis.h> #include <Ntddndis.h>
int g_has_npcap_loopback = 0;
struct ifcombo { struct ifcombo {
struct { struct {
DWORD ipv4; 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); 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 static int
_refresh_tables(intf_t *intf) _refresh_tables(intf_t *intf)
{ {
@@ -245,6 +339,7 @@ _refresh_tables(intf_t *intf)
free(p); free(p);
return (-1); return (-1);
} }
p = _update_tables_for_npcap_loopback(p);
intf->iftable = p; intf->iftable = p;
/* /*

View File

@@ -143,6 +143,10 @@
#define DLI_ERROR VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) #define DLI_ERROR VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND)
#endif #endif
#define PCAP_DRIVER_NONE 0
#define PCAP_DRIVER_WINPCAP 1
#define PCAP_DRIVER_NPCAP 2
extern NmapOps o; extern NmapOps o;
/* internal functions */ /* internal functions */
@@ -163,14 +167,15 @@ void win_pre_init() {
fatal("failed to start winsock.\n"); 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 not. Return true if it was running or we were able to start it, false
otherwise. */ otherwise. */
static bool start_npf() { static bool start_service(const char *svcname) {
SC_HANDLE scm, npf; SC_HANDLE scm, npf;
SERVICE_STATUS service; SERVICE_STATUS service;
bool npf_running; bool npf_running;
int ret; int ret;
char startsvc[32];
scm = NULL; scm = NULL;
npf = NULL; npf = NULL;
@@ -180,7 +185,7 @@ static bool start_npf() {
error("Error in OpenSCManager"); error("Error in OpenSCManager");
goto quit_error; 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) { if (npf == NULL) {
error("Error in OpenService"); error("Error in OpenService");
goto quit_error; goto quit_error;
@@ -195,19 +200,20 @@ static bool start_npf() {
if (npf_running) { if (npf_running) {
if (o.debugging > 1) 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; return true;
} }
/* NPF is not running. Try to start it. */ /* Service is not running. Try to start it. */
if (o.debugging > 1) 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) { if (ret <= 32) {
error("Unable to start NPF service: ShellExecute returned %d.\n\ error("Unable to start %s service: ShellExecute returned %d.\n\
Resorting to unprivileged (non-administrator) mode.", ret); Resorting to unprivileged (non-administrator) mode.", svcname, ret);
return false; 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 /* Requires that win_pre_init() has already been called, also that
options processing has been done so that o.debugging is options processing has been done so that o.debugging is
available */ available */
@@ -258,6 +285,7 @@ void win_init()
PMIB_IPADDRTABLE pIp = 0; PMIB_IPADDRTABLE pIp = 0;
int i; int i;
int numipsleft; int numipsleft;
int pcap_driver;
init_dll_path(); init_dll_path();
@@ -284,6 +312,17 @@ void win_init()
o.have_pcap = true; o.have_pcap = true;
if(o.debugging > 2) printf("Trying to initialize WinPcap\n"); 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"); pcapMutex = CreateMutex(NULL, 0, "Global\\DnetPcapHangAvoidanceMutex");
wait = WaitForSingleObject(pcapMutex, INFINITE); wait = WaitForSingleObject(pcapMutex, INFINITE);
PacketGetAdapterNames(pcaplist, &len); PacketGetAdapterNames(pcaplist, &len);
@@ -306,7 +345,7 @@ void win_init()
--unprivileged. In that case don't bother them with a --unprivileged. In that case don't bother them with a
potential UAC dialog when starting NPF. */ potential UAC dialog when starting NPF. */
if (o.isr00t) if (o.isr00t)
o.have_pcap = o.have_pcap && start_npf(); o.have_pcap = o.have_pcap && ((bool) pcap_driver);
} }
#ifdef _MSC_VER #ifdef _MSC_VER
__except (1) { __except (1) {

View File

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

View File

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

View File

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

View File

@@ -147,6 +147,10 @@
#include <map> #include <map>
extern NmapOps o; 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) { void UltraScanInfo::log_overall_rates(int logt) {
log_write(logt, "Overall sending rates: %.2f packets / s", send_rate_meter.getOverallPacketRate(&now)); 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. */ requires it. */
if (isRawScan()) { if (isRawScan()) {
if (ping_scan_arp || (ping_scan_nd && o.sendpref != PACKET_SEND_IP_STRONG) || ((o.sendpref & PACKET_SEND_ETH) && 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 */ /* We'll send ethernet packets with dnet */
ethsd = eth_open_cached(Targets[0]->deviceName()); ethsd = eth_open_cached(Targets[0]->deviceName());
if (ethsd == NULL) if (ethsd == NULL)
@@ -2664,7 +2672,7 @@ void ultra_scan(std::vector<Target *> &Targets, struct scan_lists *ports,
} }
#ifdef WIN32 #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()); 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; return;
} }

View File

@@ -138,6 +138,10 @@
#include "xml.h" #include "xml.h"
extern NmapOps o; 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 /* Conducts an ARP ping sweep of the given hosts to determine which ones
are up on a local ethernet network */ are up on a local ethernet network */
@@ -556,6 +560,15 @@ static Target *setup_target(const HostGroupState *hs,
else else
t->setSrcMACAddress(rnfo.ii.mac); 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)); 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 */ 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(); o.decoys[o.decoyturn] = t->v4source();

View File

@@ -906,6 +906,8 @@ TracerouteState::TracerouteState(std::vector<Target *> &targets) {
assert(targets.size() > 0); assert(targets.size() > 0);
if ((o.sendpref & PACKET_SEND_ETH) && targets[0]->ifType() == devt_ethernet) { 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()); ethsd = eth_open_cached(targets[0]->deviceName());
if (ethsd == NULL) if (ethsd == NULL)
fatal("dnet: failed to open device %s", targets[0]->deviceName()); fatal("dnet: failed to open device %s", targets[0]->deviceName());