diff --git a/CHANGELOG b/CHANGELOG index b18760a3d..3d54b1a01 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,11 @@ # Nmap Changelog ($Id$); -*-text-*- +Nmap 4.20SOC-ALPHA1 + +o Integrated initial 2nd generation OS detection patch! The system is + documented at http://insecure.org/nmap/osdetect/ . Thanks to Zhao Lei + for helping with the coding and design. + o portlist.cc was refactored to remove some code duplication. Thanks to Diman Todorov for the patch. diff --git a/FingerPrintResults.cc b/FingerPrintResults.cc index 000ded2bb..0be7b3e04 100644 --- a/FingerPrintResults.cc +++ b/FingerPrintResults.cc @@ -110,7 +110,8 @@ FingerPrintResults::FingerPrintResults() { overall_results = OSSCAN_NOMATCHES; memset(accuracy, 0, sizeof(accuracy)); isClassified = false; - osscan_opentcpport = osscan_closedtcpport = -1; + osscan_opentcpport = osscan_closedtcpport = osscan_closedudpport = -1; + distance = -1; memset(FPs, 0, sizeof(FPs)); numFPs = goodFP = 0; } @@ -139,7 +140,12 @@ bool FingerPrintResults::fingerprintSuitableForSubmission() { if (o.scan_delay > 500) // This can screw up the sequence timing return false; - if (osscan_opentcpport < 0 || osscan_closedtcpport < 0 ) // then results won't be complete + if (osscan_opentcpport < 0 || osscan_closedtcpport < 0 || osscan_closedudpport < 0) + /* The results won't be complete */ + return false; + + if (distance > 5) + /* Too far away from us. */ return false; return true; diff --git a/FingerPrintResults.h b/FingerPrintResults.h index e5db9866b..87897f574 100644 --- a/FingerPrintResults.h +++ b/FingerPrintResults.h @@ -137,10 +137,14 @@ class FingerPrintResults { any perfect (accuracy 1.0) matches, only those will be returned */ const struct OS_Classification_Results *getOSClassification(); - int osscan_opentcpport; /* Open port used for scannig (if one found -- + int osscan_opentcpport; /* Open TCP port used for scannig (if one found -- otherwise -1) */ - int osscan_closedtcpport; /* Closed port used for scannig (if one found -- + int osscan_closedtcpport; /* Closed TCP port used for scannig (if one found -- otherwise -1) */ + int osscan_closedudpport; /* Closed UDP port used for scannig (if one found -- + otherwise -1) */ + int distance; /* How "far" is this FP gotten from? */ + FingerPrint *FPs[10]; /* Fingerprint data obtained from host */ int numFPs; int goodFP; diff --git a/Makefile.in b/Makefile.in index 2bf650727..61da15b0b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -export NMAP_VERSION = 4.11 +export NMAP_VERSION = 4.20SOC-ALPHA1 NMAP_NAME= Nmap NMAP_URL= http://www.insecure.org/nmap/ NMAP_PLATFORM=@host@ @@ -46,11 +46,11 @@ TARGET = nmap TARGETNMAPFE=@TARGETNMAPFE@ INSTALLNMAPFE=@INSTALLNMAPFE@ -export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc @COMPAT_SRCS@ +export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc @COMPAT_SRCS@ -export HDRS = charpool.h FingerPrintResults.h global_structures.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h NmapOps.h NmapOutputTable.h nmap_rpc.h nmap_tty.h nmap_winconfig.h osscan.h output.h portlist.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h utils.h +export HDRS = charpool.h FingerPrintResults.h global_structures.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h NmapOps.h NmapOutputTable.h nmap_rpc.h nmap_tty.h nmap_winconfig.h osscan.h osscan2.h output.h portlist.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h utils.h -OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o output.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o nmap_tty.o nmap_dns.o @COMPAT_OBJS@ +OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o osscan2.o output.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o nmap_tty.o nmap_dns.o @COMPAT_OBJS@ # %.o : %.cc -- nope this is a GNU extension .cc.o: diff --git a/NmapOps.cc b/NmapOps.cc index 1708d7bf7..bc12f9d61 100644 --- a/NmapOps.cc +++ b/NmapOps.cc @@ -194,6 +194,7 @@ void NmapOps::Initialize() { interactivemode = 0; ping_group_sz = PING_GROUP_SZ; generate_random_ips = 0; + reference_FPs1 = NULL; reference_FPs = NULL; magic_port = 33000 + (get_random_uint() % 31000); magic_port_set = 0; diff --git a/NmapOps.h b/NmapOps.h index 1340c7cee..694ab0a9d 100644 --- a/NmapOps.h +++ b/NmapOps.h @@ -174,7 +174,8 @@ class NmapOps { int interactivemode; int ping_group_sz; int generate_random_ips; /* -iR option */ - FingerPrint **reference_FPs; + FingerPrint **reference_FPs1; /* Used in the old OS scan system. */ + FingerPrint **reference_FPs; /* Used in the new OS scan system. */ u16 magic_port; unsigned short magic_port_set; /* Was this set by user? */ int num_ping_synprobes; diff --git a/Target.cc b/Target.cc index 23d6e7426..a934a540c 100644 --- a/Target.cc +++ b/Target.cc @@ -120,6 +120,8 @@ Target::Target() { void Target::Initialize() { hostname = NULL; memset(&seq, 0, sizeof(seq)); + distance = -1; + FPR1 = NULL; FPR = NULL; osscan_performed = 0; wierd_responses = flags = 0; @@ -161,8 +163,8 @@ void Target::FreeInternal() { nameIPBuf = NULL; } + if (FPR1) delete FPR1; if (FPR) delete FPR; - } /* Creates a "presentation" formatted string out of the IPv4/IPv6 address. diff --git a/Target.h b/Target.h index 668e236d5..e4eea2d0c 100644 --- a/Target.h +++ b/Target.h @@ -215,7 +215,9 @@ class Target { const char *deviceFullName() { return *devfullname? devfullname : NULL; } struct seq_info seq; - FingerPrintResults *FPR; + int distance; + FingerPrintResults *FPR1; /* FP results get by the old OS scan system. */ + FingerPrintResults *FPR; /* FP results get by the new OS scan system. */ int osscan_performed; /* nonzero if an osscan was performed */ PortList ports; /* diff --git a/docs/nmap.xsl b/docs/nmap.xsl index d117dea65..93f61fddc 100644 --- a/docs/nmap.xsl +++ b/docs/nmap.xsl @@ -605,6 +605,16 @@ + + + +

network distance

+ +
+ + diff --git a/global_structures.h b/global_structures.h index 8fd28fece..751ba708c 100644 --- a/global_structures.h +++ b/global_structures.h @@ -216,6 +216,12 @@ struct seq_info { time_t lastboot; /* 0 means unknown */ }; +/* Different kinds of Ipids. */ +struct ipid_info { + int tcp_ipids[NUM_SEQ_SAMPLES]; + int icmp_ipids[NUM_SEQ_SAMPLES]; +}; + /* The various kinds of port/protocol scans we can have * Each element is to point to an array of port/protocol numbers */ diff --git a/idle_scan.cc b/idle_scan.cc index e5b0a85a8..1b7b7a326 100644 --- a/idle_scan.cc +++ b/idle_scan.cc @@ -187,10 +187,10 @@ static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent, /* Time to send the pr0be!*/ send_tcp_raw(proxy->rawsd, proxy->ethptr, proxy->host.v4sourceip(), - proxy->host.v4hostip(), o.ttl, base_port + tries, + proxy->host.v4hostip(), o.ttl, false, base_port + tries, proxy->probe_port, - seq_base + (packet_send_count++ * 500) + 1, ack, - TH_SYN|TH_ACK, 0, + seq_base + (packet_send_count++ * 500) + 1, ack, 0, + TH_SYN|TH_ACK, 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); sent++; tries++; @@ -417,10 +417,10 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName, think I'll use TH_SYN, although it is a tough call. */ /* We can't use decoys 'cause that would screw up the IPIDs */ send_tcp_raw(proxy->rawsd, proxy->ethptr, proxy->host.v4sourceip(), - proxy->host.v4hostip(), o.ttl, + proxy->host.v4hostip(), o.ttl, false, o.magic_port + probes_sent + 1, proxy->probe_port, - sequence_base + probes_sent + 1, ack, TH_SYN|TH_ACK, - 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); + sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, + 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); gettimeofday(&probe_send_times[probes_sent], NULL); probes_sent++; @@ -525,9 +525,9 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName, if (probes_sent) usleep(50000); send_tcp_raw(proxy->rawsd, proxy->ethptr, first_target, proxy->host.v4hostip(), - o.ttl, o.magic_port, proxy->probe_port, - sequence_base + probes_sent + 1, 0, TH_SYN|TH_ACK, - ack, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); + o.ttl, false,o.magic_port, proxy->probe_port, + sequence_base + probes_sent + 1, ack, 0, TH_SYN|TH_ACK, + 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, NULL, 0); } @@ -682,7 +682,7 @@ static int idlescan_countopen2(struct idle_proxy_info *proxy, about this more. */ send_tcp_raw(proxy->rawsd, eth.ethsd? ð : NULL, proxy->host.v4hostip(), target->v4hostip(), - o.ttl, proxy->probe_port, ports[pr0be], seq, 0, TH_SYN, 0, + o.ttl, false, proxy->probe_port, ports[pr0be], seq, 0, 0, TH_SYN, 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, o.extra_payload, o.extra_payload_length); } gettimeofday(&end, NULL); diff --git a/nmap.cc b/nmap.cc index bf4fb85e5..16daad32b 100644 --- a/nmap.cc +++ b/nmap.cc @@ -102,6 +102,7 @@ #include "nmap.h" #include "osscan.h" +#include "osscan2.h" #include "scan_engine.h" #include "idle_scan.h" #include "timing.h" @@ -594,7 +595,7 @@ int nmap_main(int argc, char *argv[]) { /* OK, lets parse these args! */ optind = 1; /* so it can be called multiple times */ - while((arg = getopt_long_only(argc,fakeargv,"6Ab:D:d::e:Ffg:hIi:M:m:nOo:P:p:qRrS:s:T:Vv", long_options, &option_index)) != EOF) { + while((arg = getopt_long_only(argc,fakeargv,"6Ab:D:d::e:Ffg:hIi:M:m:nO::o:P:p:qRrS:s:T:Vv", long_options, &option_index)) != EOF) { switch(arg) { case 0: if (optcmp(long_options[option_index].name, "max-rtt-timeout") == 0) { @@ -797,7 +798,7 @@ int nmap_main(int argc, char *argv[]) { case 'A': o.servicescan = true; if (o.isr00t) - o.osscan++; + o.osscan = OS_SCAN_DEFAULT; break; case 'b': o.bouncescan++; @@ -876,7 +877,15 @@ int nmap_main(int argc, char *argv[]) { break; case 'n': o.noresolve++; break; case 'O': - o.osscan++; + if (!optarg) + o.osscan = OS_SCAN_DEFAULT; + else if (*optarg == '1') + o.osscan = OS_SCAN_SYS_1_ONLY; + else if (*optarg == '2') + o.osscan = OS_SCAN_SYS_2_ONLY; + else { + fatal("Use -O for new osscan engine, -O1 for old osscan engine."); + } break; case 'o': normalfilename = optarg; @@ -1076,8 +1085,10 @@ int nmap_main(int argc, char *argv[]) { if (pre_host_timeout != -1) o.host_timeout = pre_host_timeout; - if (o.osscan) - o.reference_FPs = parse_fingerprint_reference_file(); + if (o.osscan == OS_SCAN_SYS_1_ONLY) + o.reference_FPs1 = parse_fingerprint_reference_file("nmap-os-fingerprints"); + else + o.reference_FPs = parse_fingerprint_reference_file("nmap-os-db"); o.ValidateOptions(); @@ -1548,6 +1559,9 @@ int nmap_main(int argc, char *argv[]) { service_scan(Targets); } + if (o.osscan != OS_SCAN_SYS_1_ONLY) + os_scan_2(Targets); + for(targetno = 0; targetno < Targets.size(); targetno++) { currenths = Targets[targetno]; @@ -1558,7 +1572,7 @@ int nmap_main(int argc, char *argv[]) { if (o.servicescan || o.rpcscan) pos_scan(currenths, NULL, 0, RPC_SCAN); // Should be host parallelized. Though rarely takes a huge amt. of time. - if (o.osscan) { + if (o.osscan == OS_SCAN_SYS_1_ONLY) { os_scan(currenths); } @@ -1980,6 +1994,10 @@ char *ipidclass2ascii(int seqclass) { return "Random positive increments"; case IPID_SEQ_ZERO: return "All zeros"; + case IPID_SEQ_LINUX: + return "Linux way"; + case IPID_SEQ_VBP: + return "Different counters by "; case IPID_SEQ_UNKNOWN: return "Busy server or unknown class"; default: diff --git a/nmap.h b/nmap.h index d1e23cd03..a39912049 100644 --- a/nmap.h +++ b/nmap.h @@ -275,8 +275,6 @@ void *realloc(); /* If reads of a UDP port keep returning EAGAIN (errno 13), do we want to count the port as valid? */ #define RISKY_UDP_SCAN 0 -/* How many syn packets do we send to TCP sequence a host? */ -#define NUM_SEQ_SAMPLES 6 /* This ideally should be a port that isn't in use for any protocol on our machine or on the target */ #define MAGIC_PORT 49724 /* How many udp sends without a ICMP port unreachable error does it take before we consider the port open? */ @@ -366,6 +364,19 @@ void *realloc(); #define PINGTYPE_ARP 1024 #define DEFAULT_PING_TYPES PINGTYPE_TCP|PINGTYPE_TCP_USE_ACK|PINGTYPE_ICMP_PING + +/* OS scan */ +#define OS_SCAN_DEFAULT 9 +#define OS_SCAN_SYS_1_ONLY 1 +#define OS_SCAN_SYS_2_ONLY 2 + +/* How many syn packets do we send to TCP sequence a host? */ +#define NUM_SEQ_SAMPLES 6 + +/* The max length of each line of the subject fingerprint when + wrapped. */ +#define FP_RESULT_WRAP_LINE_LEN 74 + /* TCP/IP ISN sequence prediction classes */ #define SEQ_UNKNOWN 0 #define SEQ_64K 1 @@ -381,7 +392,8 @@ void *realloc(); #define TS_SEQ_2HZ 2 #define TS_SEQ_100HZ 3 #define TS_SEQ_1000HZ 4 -#define TS_SEQ_UNSUPPORTED 5 /* System didn't send back a timestamp */ +#define TS_SEQ_OTHER_NUM 5 +#define TS_SEQ_UNSUPPORTED 6 /* System didn't send back a timestamp */ #define IPID_SEQ_UNKNOWN 0 #define IPID_SEQ_INCR 1 /* simple increment by one each time */ @@ -392,6 +404,14 @@ void *realloc(); #define IPID_SEQ_RD 4 /* Appears to select IPID using a "random" distributions (meaning it can go up or down) */ #define IPID_SEQ_CONSTANT 5 /* Contains 1 or more sequential duplicates */ #define IPID_SEQ_ZERO 6 /* Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) */ +#define IPID_SEQ_LINUX 7 /* Different IPID counter in different TCP + session but set zero in the TCP + negotiation process. And different IPID + counter in different protocol. Found in + linux 2.6. */ +#define IPID_SEQ_VBP 8 /* Different IPID counter for different triple. */ + #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif diff --git a/nmap_winconfig.h b/nmap_winconfig.h index 785781ea3..d3f945d28 100644 --- a/nmap_winconfig.h +++ b/nmap_winconfig.h @@ -106,7 +106,7 @@ /* Without this, Windows will give us all sorts of crap about using functions like strcpy() even if they are done safely */ #define _CRT_SECURE_NO_DEPRECATE 1 -#define NMAP_VERSION "4.11" +#define NMAP_VERSION "4.20SOC-ALPHA1" #define NMAP_NAME "Nmap" #define NMAP_URL "http://www.insecure.org/nmap" #define NMAP_PLATFORM "i686-pc-windows-windows" diff --git a/osscan.cc b/osscan.cc index 679c7fa0d..61c7245af 100644 --- a/osscan.cc +++ b/osscan.cc @@ -578,18 +578,19 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Lets find an open port to use */ openport = (unsigned long) -1; - target->FPR->osscan_opentcpport = -1; - target->FPR->osscan_closedtcpport = -1; + target->FPR1->osscan_opentcpport = -1; + target->FPR1->osscan_closedtcpport = -1; + target->FPR1->osscan_closedudpport = -1; tport = NULL; if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_OPEN))) { openport = tport->portno; - target->FPR->osscan_opentcpport = tport->portno; + target->FPR1->osscan_opentcpport = tport->portno; } /* Now we should find a closed port */ if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_CLOSED))) { closedport = tport->portno; - target->FPR->osscan_closedtcpport = tport->portno; + target->FPR1->osscan_closedtcpport = tport->portno; } else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_UNFILTERED))) { /* Well, we will settle for unfiltered */ closedport = tport->portno; @@ -612,57 +613,58 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { /* Test 1 */ if (!FPtests[1]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, - current_port, openport, sequence_base, 0, - TH_ECE|TH_SYN, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + current_port, openport, sequence_base, 0, 0, + TH_ECE|TH_SYN, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000", 20, NULL, 0); } /* Test 2 */ if (!FPtests[2]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, - current_port +1, - openport, sequence_base, 0,0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + current_port +1, openport, sequence_base, 0, 0, + 0, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } /* Test 3 */ if (!FPtests[3]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, current_port +2, - openport, sequence_base, 0,TH_SYN|TH_FIN|TH_URG|TH_PUSH, 0,(u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + current_port +2, openport, sequence_base, 0, 0, + TH_SYN|TH_FIN|TH_URG|TH_PUSH, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } /* Test 4 */ if (!FPtests[4]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, - current_port +3, - openport, sequence_base, 0,TH_ACK, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + current_port +3, openport, sequence_base, 0, 0, + TH_ACK, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } } /* Test 5 */ if (!FPtests[5]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, - current_port +4, - closedport, sequence_base, 0,TH_SYN, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + current_port +4, closedport, sequence_base, 0, 0, + TH_SYN, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } /* Test 6 */ if (!FPtests[6]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, - current_port +5, - closedport, sequence_base, 0,TH_ACK, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + current_port +5, closedport, sequence_base, 0, 0, + TH_ACK, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } /* Test 7 */ if (!FPtests[7]) { if (o.scan_delay) enforce_scan_delay(NULL); - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, - current_port +6, - closedport, sequence_base, 0,TH_FIN|TH_PUSH|TH_URG, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, + current_port +6, closedport, sequence_base, 0, 0, + TH_FIN|TH_PUSH|TH_URG, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); } /* Test 8 */ @@ -747,11 +749,11 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) { usleep(remaining_us); } } - send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, + send_tcp_raw_decoys(rawsd, ethptr, target->v4hostip(), o.ttl, false, o.magic_port + seq_packets_sent + 1, openport, - sequence_base + seq_packets_sent + 1, 0, - TH_SYN, 0 , (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); + sequence_base + seq_packets_sent + 1, 0, 0, + TH_SYN, 0, 0, (u8 *) "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" , 20, NULL, 0); gettimeofday(&seq_send_times[seq_packets_sent], NULL); t1 = seq_send_times[seq_packets_sent]; seq_packets_sent++; @@ -1183,9 +1185,9 @@ static struct AVal *gettestbyname(FingerPrint *FP, const char *name) { static int AVal_match(struct AVal *reference, struct AVal *fprint, unsigned long *num_subtests, unsigned long *num_subtests_succeeded, int shortcut) { struct AVal *current_ref; struct AVal *current_fp; - unsigned int number; + unsigned int number, number1; unsigned int val; - char *p, *q; /* OHHHH YEEEAAAAAHHHH!#!@#$!% */ + char *p, *q, *q1; /* OHHHH YEEEAAAAAHHHH!#!@#$!% */ char valcpy[512]; char *endptr; int andexp, orexp, expchar, numtrue; @@ -1196,9 +1198,9 @@ static int AVal_match(struct AVal *reference, struct AVal *fprint, unsigned long current_fp = getattrbyname(fprint, current_ref->attribute); if (!current_fp) continue; /* OK, we compare an attribute value in current_fp->value to a - potentially large expression in current_ref->value. The syntax uses - < (less than), > (greather than), + (non-zero), | (or), and & (and) - No parenthesis are allowed and an expression cannot have | AND & */ + potentially large expression in current_ref->value. The syntax + uses < (less than), > (greather than), + (non-zero), | (or), - + (range), and & (and). No parenthesis are allowed */ numtrue = andexp = orexp = 0; testfailed = 0; Strncpy(valcpy, current_ref->value, sizeof(valcpy)); p = valcpy; @@ -1229,8 +1231,17 @@ static int AVal_match(struct AVal *reference, struct AVal *fprint, unsigned long val = strtol(current_fp->value, &endptr, 16); if (val <= number || *endptr) { if (andexp) { testfailed=1; break; } } else { numtrue++; if (orexp) break; } + } else if (((q1 = strchr(p, '-')) != NULL) && isxdigit((int) p[0]) && isxdigit((int) q1[1])) { + if (!*current_fp->value) { if (andexp) { testfailed=1; break; } } + *q1 = '\0'; number = strtol(p, NULL, 16); + number1 = strtol(q1 + 1, NULL, 16); + if(number1 < number && o.debugging) { + error("Range error in reference aval: %s=%s\n", current_ref->attribute, current_ref->value); } - else { + val = strtol(current_fp->value, &endptr, 16); + if (val < number || val > number1 || *endptr) { if (andexp) { testfailed=1; break; } } + else { numtrue++; if (orexp) break; } + } else { if (strcmp(p, current_fp->value)) { if (andexp) { testfailed=1; break; } } else { numtrue++; if (orexp) break; } @@ -1322,7 +1333,7 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR, acc = compare_fingerprints(current_os, FP, 0); - /* error("Comp to %s: %li/%li=%f", o.reference_FPs[i]->OS_name, num_subtests_succeeded, num_subtests, acc); */ + /* error("Comp to %s: %li/%li=%f", o.reference_FPs1[i]->OS_name, num_subtests_succeeded, num_subtests, acc); */ if (acc >= FPR_entrance_requirement || acc == 1.0) { state = 0; @@ -1441,8 +1452,8 @@ o.current_scantype = OS_SCAN; log_write(LOG_STDOUT|LOG_NORMAL|LOG_SKID, "Initiating OS Detection against %s at %.3fs\n", target->targetipstr(), starttimems / 1000.0); } - if (target->FPR == NULL) - target->FPR = new FingerPrintResults; + if (target->FPR1 == NULL) + target->FPR1 = new FingerPrintResults; memset(si, 0, sizeof(si)); if (target->ports.getStateCounts(IPPROTO_TCP, PORT_OPEN) == 0 || @@ -1467,10 +1478,10 @@ o.current_scantype = OS_SCAN; // Do nothing because the keyWasPressed Method prints out the basic status line } - target->FPR->FPs[itry] = get_fingerprint(target, &si[itry]); + target->FPR1->FPs[itry] = get_fingerprint(target, &si[itry]); - match_fingerprint(target->FPR->FPs[itry], &FP_matches[itry], - o.reference_FPs, OSSCAN_GUESS_THRESHOLD); + match_fingerprint(target->FPR1->FPs[itry], &FP_matches[itry], + o.reference_FPs1, OSSCAN_GUESS_THRESHOLD); if (FP_matches[itry].overall_results == OSSCAN_SUCCESS && FP_matches[itry].num_perfect_matches > 0) break; @@ -1478,13 +1489,13 @@ o.current_scantype = OS_SCAN; sleep(2); } - target->FPR->numFPs = (itry == 3)? 3 : itry + 1; - memcpy(&(target->seq), &si[target->FPR->numFPs - 1], sizeof(struct seq_info)); + target->FPR1->numFPs = (itry == 3)? 3 : itry + 1; + memcpy(&(target->seq), &si[target->FPR1->numFPs - 1], sizeof(struct seq_info)); /* Now lets find the best match */ bestacc = 0; bestaccidx = 0; - for(itry=0; itry < target->FPR->numFPs; itry++) { + for(itry=0; itry < target->FPR1->numFPs; itry++) { if (FP_matches[itry].overall_results == OSSCAN_SUCCESS && FP_matches[itry].num_matches > 0 && FP_matches[itry].accuracy[0] > bestacc) { @@ -1496,27 +1507,27 @@ o.current_scantype = OS_SCAN; } - for(i=0; i < target->FPR->numFPs; i++) { + for(i=0; i < target->FPR1->numFPs; i++) { if (i == bestaccidx) continue; if (o.debugging) { - error("Failed exact match #%d (0-based):\n%s", i, fp2ascii(target->FPR->FPs[i])); + error("Failed exact match #%d (0-based):\n%s", i, fp2ascii(target->FPR1->FPs[i])); } } - if (target->FPR->numFPs > 1 && target->FPR->overall_results == OSSCAN_SUCCESS && - target->FPR->accuracy[0] == 1.0) { - if (o.verbose) error("WARNING: OS didn't match until the try #%d", target->FPR->numFPs); + if (target->FPR1->numFPs > 1 && target->FPR1->overall_results == OSSCAN_SUCCESS && + target->FPR1->accuracy[0] == 1.0) { + if (o.verbose) error("WARNING: OS didn't match until the try #%d", target->FPR1->numFPs); } - target->FPR->goodFP = bestaccidx; + target->FPR1->goodFP = bestaccidx; - // Now we redo the match, since target->FPR has various data (such as - // target->FPR->numFPs) which is not in FP_matches[bestaccidx]. This is + // Now we redo the match, since target->FPR1 has various data (such as + // target->FPR1->numFPs) which is not in FP_matches[bestaccidx]. This is // kinda ugly. - if (target->FPR->goodFP >= 0) - match_fingerprint(target->FPR->FPs[target->FPR->goodFP], target->FPR, - o.reference_FPs, OSSCAN_GUESS_THRESHOLD); + if (target->FPR1->goodFP >= 0) + match_fingerprint(target->FPR1->FPs[target->FPR1->goodFP], target->FPR1, + o.reference_FPs1, OSSCAN_GUESS_THRESHOLD); if (o.debugging > 2) { log_write(LOG_STDOUT|LOG_NORMAL|LOG_SKID, "Completed OS Detection against %s at %.3fs (took %.3fs)\n", target->targetipstr(), o.TimeSinceStartMS() / 1000.0, (o.TimeSinceStartMS() - starttimems) / 1000.0); @@ -1529,34 +1540,55 @@ o.current_scantype = OS_SCAN; top of a fingerprint. Gives info which might be useful when the FPrint is submitted (eg Nmap version, etc). Result is written (up to ostrlen) to the ostr var passed in */ -static void WriteSInfo(char *ostr, int ostrlen, int openport, int closedport, - const u8 *mac) { +static void WriteSInfo(char *ostr, int ostrlen, bool isGoodFP, + const struct in_addr * const addr, int distance, const u8 *mac, + int openTcpPort, int closedTcpPort, int closedUdpPort) { struct tm *ltime; time_t timep; + char dsbuf[8], otbuf[8], ctbuf[8], cubuf[8]; char macbuf[16]; timep = time(NULL); ltime = localtime(&timep); + otbuf[0] = '\0'; + if(openTcpPort != -1) + snprintf(otbuf, sizeof(otbuf), "%d", openTcpPort); + ctbuf[0] = '\0'; + if(closedTcpPort != -1) + snprintf(ctbuf, sizeof(ctbuf), "%d", closedTcpPort); + cubuf[0] = '\0'; + if(closedUdpPort != -1) + snprintf(cubuf, sizeof(cubuf), "%d", closedUdpPort); + + dsbuf[0] = '\0'; + if(distance != -1) { + snprintf(dsbuf, sizeof(dsbuf), "%%DS=%d", distance); + } + macbuf[0] = '\0'; if (mac) - snprintf(macbuf, sizeof(macbuf), "%%M=%02X%02X%02X", mac[0], mac[1], - mac[2]); + snprintf(macbuf, sizeof(macbuf), "%%M=%02X%02X%02X", mac[0], mac[1], mac[2]); - snprintf(ostr, ostrlen, "SInfo(V=%s%%P=%s%%D=%d/%d%%Tm=%X%%O=%d%%C=%d%s)\n", - NMAP_VERSION, NMAP_PLATFORM, ltime->tm_mon + 1, ltime->tm_mday, - (int) timep, openport, closedport, macbuf); + snprintf(ostr, ostrlen, "SCAN(V=%s%%D=%d/%d%%OT=%s%%CT=%s%%CU=%s%%PV=%c%s%%G=%c%s%%TM=%X%%P=%s)", + NMAP_VERSION, ltime->tm_mon + 1, ltime->tm_mday, + otbuf, ctbuf, cubuf, isipprivate(addr)?'Y':'N', dsbuf, isGoodFP?'Y':'N', + macbuf, (int) timep, NMAP_PLATFORM); } -char *mergeFPs(FingerPrint *FPs[], int numFPs, int openport, int closedport, - const u8 *mac) { +char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP, + const struct in_addr * const addr, int distance, const u8 *mac, + int openTcpPort, int closedTcpPort, int closedUdpPort, bool wrapit) { static char str[10240]; + static char wrapstr[10240]; + struct AVal *AV; FingerPrint *currentFPs[32]; char *p = str; int i; int changed; char *end = str + sizeof(str) - 1; /* Last byte allowed to write into */ + if (numFPs <=0) return "(None)"; if (numFPs > 32) return "(Too many)"; @@ -1568,9 +1600,10 @@ for(i=0; i < numFPs; i++) { currentFPs[i] = FPs[i]; } -/* Lets start by writing the fake "Info" test for submitting fingerprints */ - WriteSInfo(str, sizeof(str), openport, closedport, mac); + /* Lets start by writing the fake "SCAN" test for submitting fingerprints */ + WriteSInfo(str, sizeof(str), isGoodFP, addr, distance, mac, openTcpPort, closedTcpPort, closedUdpPort); p = p + strlen(str); + if (!wrapit) *p++ = '\n'; do { changed = 0; @@ -1599,6 +1632,8 @@ do { if(*(p-1) != '(') p--; /* Kill the final & */ *p++ = ')'; + + if(!wrapit) *p++ = '\n'; } /* Now prepare for the next one */ @@ -1608,9 +1643,34 @@ do { } while(changed); *p = '\0'; -return str; -} + if(!wrapit) { +return str; + } else { + /* Wrap the str. */ + int len; + char *p1 = wrapstr; + end = wrapstr + sizeof(wrapstr) - 1; + + p = str; + + while(*p && end-p1 >= 3) { + len = 0; + strcpy(p1, "OS:"); p1 += 3; len +=3; + while(*p && len <= FP_RESULT_WRAP_LINE_LEN && end-p1 > 0) { + *p1++=*p++; len++; + } + if(end-p1<=0) { + fatal("Wrapped result too long!\n"); + break; + } + *p1++ = '\n'; +} + *p1 = '\0'; + + return wrapstr; + } +} char *fp2ascii(FingerPrint *FP) { static char str[2048]; @@ -1953,18 +2013,17 @@ while(fgets(line, sizeof(line), fp)) { /* printf("Read in fingerprint:\n%s\n", fp2ascii(FPs[numrecords])); */ numrecords++; if (numrecords >= max_records) - fatal("Too many OS fingerprints -- 0verfl0w"); + fatal("Too many OS fingerprints -- 0verflow"); } fclose(fp); FPs[numrecords] = NULL; return FPs; } -FingerPrint **parse_fingerprint_reference_file() { +FingerPrint **parse_fingerprint_reference_file(char *dbname) { char filename[256]; - -if (nmap_fetchfile(filename, sizeof(filename), "nmap-os-fingerprints") == -1){ - fatal("OS scan requested but I cannot find nmap-os-fingerprints file. It should be in %s, ~/.nmap/ or .", NMAPDATADIR); +if (nmap_fetchfile(filename, sizeof(filename), dbname) == -1){ + fatal("OS scan requested but I cannot find %s file. It should be in %s, ~/.nmap/ or .", dbname, NMAPDATADIR); } return parse_fingerprint_file(filename); diff --git a/osscan.h b/osscan.h index 06164e6a2..6c159a843 100644 --- a/osscan.h +++ b/osscan.h @@ -129,7 +129,7 @@ char *fp2ascii(FingerPrint *FP); which some partial fingerpritns are OK. */ FingerPrint *parse_single_fingerprint(char *fprint_orig); FingerPrint **parse_fingerprint_file(char *fname); -FingerPrint **parse_fingerprint_reference_file(); +FingerPrint **parse_fingerprint_reference_file(char *dbname); /* Compares 2 fingerprints -- a referenceFP (can have expression attributes) with an observed fingerprint (no expressions). If @@ -150,8 +150,7 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR, /* Returns true if perfect match -- if num_subtests & num_subtests_succeeded are non_null it updates them. if shortcircuit is zero, it does all the tests, otherwise it returns when the first one fails */ void freeFingerPrint(FingerPrint *FP); -char *mergeFPs(FingerPrint *FPs[], int numFPs, int openport, int closedport, - const u8 *mac); +char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP, const struct in_addr * const addr, int distance, const u8 *mac, int openTcpPort, int closedTcpPort, int closedUdpPort, bool wrapit); /* This function takes an array of "numSamples" IP IDs and analyzes them to determine their sequenceability classification. It returns diff --git a/output.cc b/output.cc index 73fc55c54..269ef0e7b 100644 --- a/output.cc +++ b/output.cc @@ -1208,120 +1208,184 @@ void printmacinfo(Target *currenths) { + /* Prints the formatted OS Scan output to stdout, logfiles, etc (but only - if an OS Scan was performed */ + if an OS Scan was performed).*/ void printosscanoutput(Target *currenths) { int i; char numlst[512]; /* For creating lists of numbers */ char *p; /* Used in manipulating numlst above */ + FingerPrintResults *FPR; + int distance = -1; + bool wrapFP = true; /* Whether to wrap the fingerprint result. */ + + if (!currenths->osscan_performed) + return; + + if (currenths->FPR == NULL && currenths->FPR1 == NULL) { + return; + } else if (currenths->FPR != NULL && currenths->FPR1 == NULL) { + FPR = currenths->FPR; + } else if (currenths->FPR == NULL && currenths->FPR1 != NULL) { + FPR = currenths->FPR1; + wrapFP = false; + } + else { + /* Neither is NULL. This happens when new OS scan system fails to + get a perfect match and falls back on the old OS scan + system. */ + if (currenths->FPR->num_perfect_matches > 0) { + FPR = currenths->FPR; /* Just an ensurance. */ + } else if (currenths->FPR1->num_perfect_matches > 0) { + FPR = currenths->FPR1; + wrapFP = false; + } else if (currenths->FPR->overall_results == OSSCAN_SUCCESS) { + FPR = currenths->FPR; + } else if (currenths->FPR1->overall_results == OSSCAN_SUCCESS) { + FPR = currenths->FPR1; + wrapFP = false; + } else { + /* Both fails. */ + FPR = currenths->FPR; + } + } + + if (islocalhost(currenths->v4hostip())) { + /* scanning localhost */ + distance = 0; + } else if (currenths->MACAddress()) { + /* on the same network segment */ + distance = 1; + } else if (currenths->distance!=-1) { + distance = currenths->distance; + } - if (currenths->osscan_performed && currenths->FPR != NULL) { log_write(LOG_XML, ""); - if (currenths->FPR->osscan_opentcpport > 0) { + if (FPR->osscan_opentcpport > 0) { log_write(LOG_XML, "\n", - currenths->FPR->osscan_opentcpport); + FPR->osscan_opentcpport); } - if (currenths->FPR->osscan_closedtcpport > 0) { + if (FPR->osscan_closedtcpport > 0) { log_write(LOG_XML, "\n", - currenths->FPR->osscan_closedtcpport); + FPR->osscan_closedtcpport); + } + if (FPR->osscan_closedudpport > 0) { + log_write(LOG_XML, + "\n", + FPR->osscan_closedudpport); } // If the FP can't be submitted anyway, might as well make a guess. - printosclassificationoutput(currenths->FPR->getOSClassification(), - o.osscan_guess || !currenths->FPR->fingerprintSuitableForSubmission()); + printosclassificationoutput(FPR->getOSClassification(), + o.osscan_guess || !FPR->fingerprintSuitableForSubmission()); - if (currenths->FPR->overall_results == OSSCAN_SUCCESS && (currenths->FPR->num_perfect_matches <= 8 || o.debugging)) { - if (currenths->FPR->num_perfect_matches > 0) { + if (FPR->overall_results == OSSCAN_SUCCESS && (FPR->num_perfect_matches <= 8 || o.debugging)) { + if (FPR->num_perfect_matches > 0) { char *p; - log_write(LOG_MACHINE,"\tOS: %s", currenths->FPR->prints[0]->OS_name); + log_write(LOG_MACHINE,"\tOS: %s", FPR->prints[0]->OS_name); log_write(LOG_XML, "\n", - p = xml_convert(currenths->FPR->prints[0]->OS_name), - currenths->FPR->prints[0]->line); + p = xml_convert(FPR->prints[0]->OS_name), + FPR->prints[0]->line); free(p); i = 1; - while(currenths->FPR->accuracy[i] == 1 ) { - log_write(LOG_MACHINE,"|%s", currenths->FPR->prints[i]->OS_name); + while(FPR->accuracy[i] == 1 ) { + log_write(LOG_MACHINE,"|%s", FPR->prints[i]->OS_name); log_write(LOG_XML, "\n", - p = xml_convert(currenths->FPR->prints[i]->OS_name), - currenths->FPR->prints[i]->line); + p = xml_convert(FPR->prints[i]->OS_name), + FPR->prints[i]->line); free(p); i++; } - - if (currenths->FPR->num_perfect_matches == 1) + if (FPR->num_perfect_matches == 1) log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "OS details: %s", - currenths->FPR->prints[0]->OS_name); + FPR->prints[0]->OS_name); else { log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "OS details: %s", - currenths->FPR->prints[0]->OS_name); + FPR->prints[0]->OS_name); i = 1; - while(currenths->FPR->accuracy[i] == 1) { + while(FPR->accuracy[i] == 1) { log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,", %s", - currenths->FPR->prints[i]->OS_name); + FPR->prints[i]->OS_name); i++; } } } else { - if ((o.osscan_guess || !currenths->FPR->fingerprintSuitableForSubmission()) && - currenths->FPR->num_matches > 0) { + if ((o.osscan_guess || !FPR->fingerprintSuitableForSubmission()) && FPR->num_matches > 0) { /* Print the best guesses available */ - log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Aggressive OS guesses: %s (%d%%)", currenths->FPR->prints[0]->OS_name, (int) (currenths->FPR->accuracy[0] * 100)); - for(i=1; i < 10 && currenths->FPR->num_matches > i && - currenths->FPR->accuracy[i] > - currenths->FPR->accuracy[0] - 0.10; i++) { + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Aggressive OS guesses: %s (%d%%)", FPR->prints[0]->OS_name, (int) (FPR->accuracy[0] * 100)); + for(i=1; i < 10 && FPR->num_matches > i && FPR->accuracy[i] > FPR->accuracy[0] - 0.10; i++) { char *p; - log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,", %s (%d%%)", currenths->FPR->prints[i]->OS_name, (int) (currenths->FPR->accuracy[i] * 100)); + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,", %s (%d%%)", FPR->prints[i]->OS_name, (int) (FPR->accuracy[i] * 100)); log_write(LOG_XML, "\n", - p = xml_convert(currenths->FPR->prints[i]->OS_name), - (int) (currenths->FPR->accuracy[i] * 100), - currenths->FPR->prints[i]->line); + p = xml_convert(FPR->prints[i]->OS_name), + (int) (FPR->accuracy[i] * 100), + FPR->prints[i]->line); free(p); } log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "\n"); } - if (currenths->FPR->fingerprintSuitableForSubmission()) { - log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT,"No exact OS matches for host (If you know what OS is running on it, see http://www.insecure.org/cgi-bin/nmap-submit.cgi).\nTCP/IP fingerprint:\n%s\n", mergeFPs(currenths->FPR->FPs, currenths->FPR->numFPs, currenths->FPR->osscan_opentcpport, currenths->FPR->osscan_closedtcpport, currenths->MACAddress())); + if (FPR->fingerprintSuitableForSubmission()) { + log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT,"No exact OS matches for host (If you know what OS is running on it, see http://www.insecure.org/cgi-bin/nmap-submit.cgi).\nTCP/IP fingerprint:\n%s\n", + mergeFPs(FPR->FPs, FPR->numFPs, true, + currenths->v4hostip(), distance, currenths->MACAddress(), + FPR->osscan_opentcpport, FPR->osscan_closedtcpport, FPR->osscan_closedudpport, + wrapFP)); + } else { log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT,"No exact OS matches for host (test conditions non-ideal)."); if (o.verbose > 1) - log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT, "\nTCP/IP fingerprint:\n%s", mergeFPs(currenths->FPR->FPs, currenths->FPR->numFPs, currenths->FPR->osscan_opentcpport, currenths->FPR->osscan_closedtcpport, currenths->MACAddress())); + log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT, "\nTCP/IP fingerprint:\n%s", + mergeFPs(FPR->FPs, FPR->numFPs, false, + currenths->v4hostip(), distance, currenths->MACAddress(), + FPR->osscan_opentcpport, FPR->osscan_closedtcpport, FPR->osscan_closedudpport, + false)); } } log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"\n"); - if (currenths->FPR->goodFP >= 0 && (o.debugging || o.verbose > 1) && currenths->FPR->num_perfect_matches > 0 ) { - log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"OS Fingerprint:\n%s\n", fp2ascii(currenths->FPR->FPs[currenths->FPR->goodFP])); + if (FPR->goodFP >= 0 && (o.debugging || o.verbose > 1) && FPR->num_perfect_matches > 0 ) { + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"OS Fingerprint:\n%s\n", fp2ascii(FPR->FPs[FPR->goodFP])); } - } else if (currenths->FPR->overall_results == OSSCAN_NOMATCHES) { - if (o.scan_delay < 500 && currenths->FPR->osscan_opentcpport > 0 && - currenths->FPR->osscan_closedtcpport > 0 ) { - log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT,"No OS matches for host (If you know what OS is running on it, see http://www.insecure.org/cgi-bin/nmap-submit.cgi).\nTCP/IP fingerprint:\n%s\n", mergeFPs(currenths->FPR->FPs, currenths->FPR->numFPs, currenths->FPR->osscan_opentcpport, currenths->FPR->osscan_closedtcpport, currenths->MACAddress())); + } else if (FPR->overall_results == OSSCAN_NOMATCHES) { + if (FPR->fingerprintSuitableForSubmission()) { + log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT,"No OS matches for host (If you know what OS is running on it, see http://www.insecure.org/cgi-bin/nmap-submit.cgi).\nTCP/IP fingerprint:\n%s\n", + mergeFPs(FPR->FPs, FPR->numFPs, true, + currenths->v4hostip(), distance, currenths->MACAddress(), + FPR->osscan_opentcpport, FPR->osscan_closedtcpport, FPR->osscan_closedudpport, + wrapFP)); } else { - log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT,"No OS matches for host (test conditions non-ideal).\nTCP/IP fingerprint:\n%s\n", mergeFPs(currenths->FPR->FPs, currenths->FPR->numFPs, currenths->FPR->osscan_opentcpport, currenths->FPR->osscan_closedtcpport, currenths->MACAddress())); + log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT,"No OS matches for host (test conditions non-ideal).\n"); + if (o.verbose > 1) + log_write(LOG_NORMAL|LOG_SKID_NOXLT|LOG_STDOUT, "\nTCP/IP fingerprint:\n%s", + mergeFPs(FPR->FPs, FPR->numFPs, false, + currenths->v4hostip(), distance, currenths->MACAddress(), + FPR->osscan_opentcpport, FPR->osscan_closedtcpport, FPR->osscan_closedudpport, + false)); } - } else if (currenths->FPR->overall_results == OSSCAN_TOOMANYMATCHES || (currenths->FPR->num_perfect_matches > 8 && !o.debugging)) - { + } else if (FPR->overall_results == OSSCAN_TOOMANYMATCHES || (FPR->num_perfect_matches > 8 && !o.debugging)) { log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Too many fingerprints match this host to give specific OS details\n"); if (o.debugging || o.verbose) { - log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"TCP/IP fingerprint:\n%s", mergeFPs(currenths->FPR->FPs, currenths->FPR->numFPs, currenths->FPR->osscan_opentcpport, currenths->FPR->osscan_closedtcpport, currenths->MACAddress())); + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"TCP/IP fingerprint:\n%s", + mergeFPs(FPR->FPs, FPR->numFPs, false, + currenths->v4hostip(), distance, currenths->MACAddress(), + FPR->osscan_opentcpport, FPR->osscan_closedtcpport, FPR->osscan_closedudpport, + false)); } } else { assert(0); } if (o.debugging || o.verbose) { - log_write(LOG_XML,"\n", - mergeFPs(currenths->FPR->FPs, currenths->FPR->numFPs, - currenths->FPR->osscan_opentcpport, - currenths->FPR->osscan_closedtcpport, - currenths->MACAddress())); + mergeFPs(FPR->FPs, FPR->numFPs, false, + currenths->v4hostip(), distance, currenths->MACAddress(), + FPR->osscan_opentcpport, FPR->osscan_closedtcpport, FPR->osscan_closedudpport, + false)); } - log_write(LOG_XML, "\n"); if (currenths->seq.lastboot) { @@ -1330,10 +1394,15 @@ void printosscanoutput(Target *currenths) { gettimeofday(&tv, NULL); strncpy(tmbuf, ctime(&(currenths->seq.lastboot)), sizeof(tmbuf)); chomp(tmbuf); - log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Uptime %.3f days (since %s)\n", (double) (tv.tv_sec - currenths->seq.lastboot) / 86400, tmbuf); + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"Uptime: %.3f days (since %s)\n", (double) (tv.tv_sec - currenths->seq.lastboot) / 86400, tmbuf); log_write(LOG_XML, "\n", tv.tv_sec - currenths->seq.lastboot, tmbuf); } + if (distance!=-1) { + log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT, "Network Distance: %d hops\n", distance); + log_write(LOG_XML, "\n", distance); + } + if (currenths->seq.responses > 3) { p=numlst; for(i=0; i < currenths->seq.responses; i++) { @@ -1379,12 +1448,9 @@ void printosscanoutput(Target *currenths) { } log_write(LOG_XML, " />\n"); } - } log_flush_all(); } - - /* An auxillary function for printserviceinfooutput(). Returns non-zero if a and b are considered the same hostnames. */ static int hostcmp(const char *a, const char *b) { diff --git a/scan_engine.cc b/scan_engine.cc index 5672fd294..4af9c5bf8 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -2136,9 +2136,9 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, } for(decoy = 0; decoy < o.numdecoys; decoy++) { - packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, - ipid, sport, pspec->pd.tcp.dport, seq, ack, - pspec->pd.tcp.flags, 0, tcpops, tcpopslen, + packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, false, + ipid, sport, pspec->pd.tcp.dport, seq, ack, 0, + pspec->pd.tcp.flags, 0, 0, tcpops, tcpopslen, o.extra_payload, o.extra_payload_length, &packetlen); if (decoy == o.decoyturn) { @@ -2166,15 +2166,15 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, switch(pspec->proto) { case IPPROTO_TCP: - packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, + packet = build_tcp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, false, ipid, sport, o.magic_port, get_random_u32(), - get_random_u32(), TH_ACK, 0, NULL, + get_random_u32(), 0, TH_ACK, 0, 0, NULL, 0, o.extra_payload, o.extra_payload_length, &packetlen); break; case IPPROTO_ICMP: packet = build_icmp_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, - ipid, 0, 0, 8, 0, o.extra_payload, + ipid, 0, false, 0, 0, 8, 0, o.extra_payload, o.extra_payload_length, &packetlen); break; case IPPROTO_UDP: @@ -2186,7 +2186,7 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss, break; default: packet = build_ip_raw(&o.decoys[decoy], hss->target->v4hostip(), o.ttl, - pspec->proto, ipid, + pspec->proto, ipid, 0, false, o.extra_payload, o.extra_payload_length, &packetlen); break; diff --git a/scripts/Makefile b/scripts/Makefile index d8c36b739..d630ee83f 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -3,7 +3,7 @@ CC=gcc CPP=g++ INCLUDE_FLAGS= -I.. -I../nbase -I../libpcap LINK_FLAGS=-L.. -L../nbase -L../libpcap -NMAP_OBJS=../osscan.o ../nmap_error.o ../utils.o ../tcpip.o ../output.o ../nmap.o ../scan_engine.o ../portlist.o ../timing.o ../nmap_rpc.o ../charpool.o ../services.o ../targets.o ../idle_scan.o ../MACLookup.o ../protocols.o ../FingerPrintResults.o ../NmapOps.o ../TargetGroup.o ../Target.o ../NmapOutputTable.o ../service_scan.o ../nmap_tty.o ../nmap_dns.o ../nsock/src/libnsock.a +NMAP_OBJS=../osscan.o ../osscan2.o ../nmap_error.o ../utils.o ../tcpip.o ../output.o ../nmap.o ../scan_engine.o ../portlist.o ../timing.o ../nmap_rpc.o ../charpool.o ../services.o ../targets.o ../idle_scan.o ../MACLookup.o ../protocols.o ../FingerPrintResults.o ../NmapOps.o ../TargetGroup.o ../Target.o ../NmapOutputTable.o ../service_scan.o ../nmap_tty.o ../nmap_dns.o ../nsock/src/libnsock.a DEFINES=-DHAVE_CONFIG_H=1 DATAFILES = nmap-os-fingerprints nmap-service-probes nmap-services nmap-rpc nmap-protocols nmap-mac-prefixes SHTOOL = ../shtool diff --git a/targets.cc b/targets.cc index eb5918246..d3dbd3651 100644 --- a/targets.cc +++ b/targets.cc @@ -925,10 +925,10 @@ else { o.decoys[o.decoyturn].s_addr = target->v4source().s_addr; if (pingtype & PINGTYPE_TCP_USE_SYN) { - send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), o.ttl, sportbase + trynum, probe_port, myseq, myack, TH_SYN, 0, (u8 *) "\x02\x04\x05\xb4", 4, o.extra_payload, + send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), o.ttl, false, sportbase + trynum, probe_port, myseq, myack, 0, TH_SYN, 0, 0, (u8 *) "\x02\x04\x05\xb4", 4, o.extra_payload, o.extra_payload_length); } else { - send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), o.ttl, sportbase + trynum, probe_port, myseq, myack, TH_ACK, 0, NULL, 0, o.extra_payload, + send_tcp_raw_decoys( rawsd, eth, target->v4hostip(), o.ttl, false, sportbase + trynum, probe_port, myseq, myack, 0, TH_ACK, 0, 0, NULL, 0, o.extra_payload, o.extra_payload_length); } diff --git a/tcpip.cc b/tcpip.cc index 94d5f346e..7887d585b 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -645,6 +645,31 @@ char dev[128]; return 0; } +int isipprivate(const struct in_addr * const addr) { + char *ipc; + unsigned char i1, i2; + + if(!addr) return 0; + + ipc = (char *) &(addr->s_addr); + i1 = ipc[0]; + i2 = ipc[1]; + + /* 10.0.0.0/8 */ + if (i1 == 10) + return 1; + + /* 172.16.0.0/12 */ + if (i1 == 172 && i2 >= 16 && i2 <= 31) + return 1; + + /* 192.168.0.0/16 */ + if (i1 == 192 && i2 == 168) + return 1; + + return 0; +} + #ifdef WIN32 /* Convert a dnet interface name into the long pcap style. This also caches the data to speed things up. Fills out pcapdev (up to pcapdevlen) and returns true if it finds anything. @@ -830,16 +855,16 @@ void eth_close_cached() { } int send_tcp_raw_decoys( int sd, struct eth_nfo *eth, - const struct in_addr *victim, int ttl, - u16 sport, u16 dport, u32 seq, u32 ack, u8 flags, - u16 window, u8 *options, int optlen, char *data, + const struct in_addr *victim, int ttl, bool df, + u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, + u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen) { int decoy; for(decoy = 0; decoy < o.numdecoys; decoy++) - if (send_tcp_raw(sd, eth, &o.decoys[decoy], victim, ttl, sport, dport, - seq, ack, flags, window, options, optlen, data, + if (send_tcp_raw(sd, eth, &o.decoys[decoy], victim, ttl, df, sport, dport, + seq, ack, reserved, flags, window, urp, options, optlen, data, datalen) == -1) return -1; @@ -853,9 +878,9 @@ int send_tcp_raw_decoys( int sd, struct eth_nfo *eth, finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_tcp_raw(const struct in_addr *source, - const struct in_addr *victim, int ttl, - u16 ipid, u16 sport, u16 dport, u32 seq, u32 ack, u8 flags, - u16 window, u8 *options, int optlen, char *data, + const struct in_addr *victim, int ttl, u16 ipid, bool df, + u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, + u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen, u32 *packetlen) { struct pseudo_header { @@ -907,6 +932,8 @@ if (ack) /*else if (flags & TH_ACK) tcp->th_ack = rand() + rand();*/ +if (reserved) + tcp->th_x2 = reserved & 0x0F; tcp->th_off = 5 + (optlen /4) /*words*/; tcp->th_flags = flags; @@ -914,6 +941,10 @@ if (window) tcp->th_win = htons(window); else tcp->th_win = htons(1024 * (myttl % 4 + 1)); /* Who cares */ +/* Urgend pointer */ +if (urp) + tcp->th_urp = htons(urp); + /* We should probably copy the data over too */ if (data && datalen) memcpy(packet + sizeof(struct ip) + sizeof(struct tcphdr) + optlen, data, datalen); @@ -941,6 +972,7 @@ get_random_bytes(&(ip->ip_id), 2); ip->ip_ttl = myttl; ip->ip_p = IPPROTO_TCP; ip->ip_id = ipid; +if(df) ip->ip_off |= htons(IP_DF); ip->ip_src.s_addr = source->s_addr; #ifdef WIN32 // I'm not sure why this is --Fyodor @@ -959,16 +991,16 @@ ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip)); /* You need to call sethdrinclude(sd) on the sending sd before calling this */ int send_tcp_raw( int sd, struct eth_nfo *eth, const struct in_addr *source, - const struct in_addr *victim, int ttl, - u16 sport, u16 dport, u32 seq, u32 ack, u8 flags, - u16 window, u8 *options, int optlen, char *data, + const struct in_addr *victim, int ttl, bool df, + u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, + u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen) { unsigned int packetlen; int res = -1; - u8 *packet = build_tcp_raw(source, victim, ttl, get_random_u16(), sport, - dport, seq, ack, flags, window, options, optlen, + u8 *packet = build_tcp_raw(source, victim, ttl, get_random_u16(), df, sport, + dport, seq, ack, reserved, flags, window, urp, options, optlen, data, datalen, &packetlen); if (!packet) return -1; res = send_ip_packet(sd, eth, packet, packetlen); @@ -1134,7 +1166,7 @@ int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, unsigned int packetl finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u16 ipid, u16 seq, unsigned short id, u8 ptype, + int ttl, u16 ipid, u8 tos, bool df, u16 seq, unsigned short id, u8 ptype, u8 pcode, char *data, u16 datalen, u32 *packetlen) { struct ppkt { @@ -1153,7 +1185,7 @@ char *ping = (char *) &pingpkt; pingpkt.type = ptype; pingpkt.code = pcode; - if (ptype == 8 && pcode == 0) /* echo request */ { + if (ptype == 8) /* echo request */ { icmplen = 8; } else if (ptype == 13 && pcode == 0) /* ICMP timestamp req */ { icmplen = 20; @@ -1173,7 +1205,6 @@ char *ping = (char *) &pingpkt; } /* Fill out the ping packet */ -pingpkt.code = 0; pingpkt.id = id; pingpkt.seq = seq; pingpkt.checksum = 0; @@ -1182,7 +1213,7 @@ pingpkt.checksum = in_cksum((unsigned short *)ping, icmplen); if ( o.badsum ) --pingpkt.checksum; -return build_ip_raw(source, victim, o.ttl, IPPROTO_ICMP, get_random_u16(), +return build_ip_raw(source, victim, o.ttl, IPPROTO_ICMP, get_random_u16(), tos, df, ping, icmplen, packetlen); } @@ -1420,7 +1451,7 @@ int send_udp_raw( int sd, struct eth_nfo *eth, struct in_addr *source, finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u8 proto, u16 ipid, char *data, u16 datalen, + int ttl, u8 proto, u16 ipid, u8 tos, bool df, char *data, u16 datalen, u32 *packetlen) { @@ -1448,8 +1479,10 @@ memset((char *) packet, 0, sizeof(struct ip)); ip->ip_v = 4; ip->ip_hl = 5; +ip->ip_tos = tos; ip->ip_len = htons(sizeof(struct ip) + datalen); ip->ip_id = htons(ipid); +if(df) ip->ip_off |= htons(IP_DF); ip->ip_ttl = myttl; ip->ip_p = proto; ip->ip_src.s_addr = source->s_addr; @@ -1480,7 +1513,7 @@ int send_ip_raw( int sd, struct eth_nfo *eth, struct in_addr *source, int res = -1; u8 *packet = build_ip_raw(source, victim, ttl, proto, get_random_u16(), - data, datalen, &packetlen); + IP_TOS_DEFAULT, false, data, datalen, &packetlen); if (!packet) return -1; res = send_ip_packet(sd, eth, packet, packetlen); diff --git a/tcpip.h b/tcpip.h index a9f969ba5..c76e77cba 100644 --- a/tcpip.h +++ b/tcpip.h @@ -570,9 +570,9 @@ unsigned short in_cksum(u16 *ptr,int nbytes); /* Build and send a raw tcp packet. If TTL is -1, a partially random (but likely large enough) one is chosen */ int send_tcp_raw( int sd, struct eth_nfo *eth, const struct in_addr *source, - const struct in_addr *victim, int ttl, - u16 sport, u16 dport, u32 seq, u32 ack, u8 flags, - u16 window, u8 *options, int optlen, char *data, + const struct in_addr *victim, int ttl, bool df, + u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, + u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen); int send_udp_raw( int sd, struct eth_nfo *eth, struct in_addr *source, const struct in_addr *victim, int ttl, u16 sport, @@ -588,11 +588,10 @@ int send_ip_raw( int sd, struct eth_nfo *eth, struct in_addr *source, actually sent by this function. Caller must delete the buffer when finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ -u8 *build_tcp_raw(const struct in_addr *source, - const struct in_addr *victim, int ttl, - u16 ipid, u16 sport, u16 dport, u32 seq, u32 ack, u8 flags, - u16 window, u8 *options, int optlen, char *data, - u16 datalen, u32 *packetlen); +u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim, + int ttl, u16 ipid, bool df, u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, + u8 flags, u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen, + u32 *packetlen); /* Builds a UDP packet (including an IP header) by packing the fields with the given information. It allocates a new buffer to store the @@ -611,7 +610,7 @@ u8 *build_udp_raw(struct in_addr *source, const struct in_addr *victim, finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u16 ipid, u16 seq, unsigned short id, u8 ptype, + int ttl, u16 ipid, u8 tos, bool df, u16 seq, unsigned short id, u8 ptype, u8 pcode, char *data, u16 datalen, u32 *packetlen); /* Builds an IP packet (including an IP header) by packing the fields @@ -621,7 +620,7 @@ u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim, finished with the packet. The packet length is returned in packetlen, which must be a valid int pointer. */ u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim, - int ttl, u8 proto, u16 ipid, char *data, u16 datalen, + int ttl, u8 proto, u16 ipid, u8 tos, bool df, char *data, u16 datalen, u32 *packetlen); /* Send a pre-built IPv4 packet */ @@ -630,9 +629,9 @@ int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet, /* Decoy versions of the raw packet sending functions ... */ int send_tcp_raw_decoys( int sd, struct eth_nfo *eth, - const struct in_addr *victim, int ttl, - u16 sport, u16 dport, u32 seq, u32 ack, u8 flags, - u16 window, u8 *options, int optlen, char *data, + const struct in_addr *victim, int ttl, bool df, + u16 sport, u16 dport, u32 seq, u32 ack, u8 reserved, u8 flags, + u16 window, u16 urp, u8 *options, int optlen, char *data, u16 datalen); int send_udp_raw_decoys( int sd, struct eth_nfo *eth, @@ -723,6 +722,7 @@ int setTargetMACIfAvailable(Target *target, struct link_header *linkhdr, bool setTargetNextHopMAC(Target *target); int islocalhost(const struct in_addr * const addr); +int isipprivate(const struct in_addr * const addr); int unblock_socket(int sd); // Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, or