mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 13:11:28 +00:00
IPv6 idle scan patch by Mathias Morbitzer.
http://seclists.org/nmap-dev/2013/q3/549
This commit is contained in:
@@ -565,7 +565,7 @@ dialog where you can start NPF if you have administrator privileges.";
|
|||||||
fatal("--min-rate=%g must be less than or equal to --max-rate=%g", min_packet_send_rate, max_packet_send_rate);
|
fatal("--min-rate=%g must be less than or equal to --max-rate=%g", min_packet_send_rate, max_packet_send_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (af() == AF_INET6 && (generate_random_ips|numdecoys|bouncescan|fragscan|idlescan)) {
|
if (af() == AF_INET6 && (generate_random_ips|numdecoys|bouncescan|fragscan)) {
|
||||||
fatal("Sorry -- IPv6 support is currently only available for TCP, UDP, and SCTP port scans and list scan (-sL). OS detection, random targets and decoys are also not supported with IPv6. Further support is under consideration.");
|
fatal("Sorry -- IPv6 support is currently only available for TCP, UDP, and SCTP port scans and list scan (-sL). OS detection, random targets and decoys are also not supported with IPv6. Further support is under consideration.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
512
idle_scan.cc
512
idle_scan.cc
@@ -126,7 +126,7 @@
|
|||||||
* *
|
* *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/* $Id$ */
|
/* $Id: idle_scan.cc 2013-07-26 Mathias Morbitzer (mathias.morbitzer(at)fox-it.com) $ */
|
||||||
|
|
||||||
#include "idle_scan.h"
|
#include "idle_scan.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
@@ -169,6 +169,40 @@ struct idle_proxy_info {
|
|||||||
struct eth_nfo *ethptr; // points to eth if filled out, otherwise NULL
|
struct eth_nfo *ethptr; // points to eth if filled out, otherwise NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Finds the IPv6 extension header for fragmentation in an IPv6 packet, and returns
|
||||||
|
* the identification value of the fragmentation header
|
||||||
|
*/
|
||||||
|
int ipv6_get_fragment_id(const struct ip6_hdr *ip6, unsigned int len) {
|
||||||
|
const unsigned char *p, *end;
|
||||||
|
u8 hdr;
|
||||||
|
struct ip6_ext_data_fragment *frag_header = NULL;
|
||||||
|
|
||||||
|
if (len < sizeof(*ip6))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
p = (unsigned char *) ip6;
|
||||||
|
end = p + len;
|
||||||
|
|
||||||
|
hdr = ip6->ip6_nxt;
|
||||||
|
p += sizeof(*ip6);
|
||||||
|
|
||||||
|
/* If the first extension header is not the fragmentation, we search our way
|
||||||
|
* through the extension headers until we find the fragmentation header */
|
||||||
|
while (p < end && hdr != IP_PROTO_FRAGMENT) {
|
||||||
|
if (p + 2 > end)
|
||||||
|
return -1;
|
||||||
|
hdr = *p;
|
||||||
|
p += (*(p + 1) + 1) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hdr != IP_PROTO_FRAGMENT || (p + 2 + sizeof(ip6_ext_data_fragment)) > end)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
frag_header = (struct ip6_ext_data_fragment *)( p + 2 );
|
||||||
|
|
||||||
|
return (ntohl(frag_header->ident));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Sends an IP ID probe to the proxy machine and returns the IP ID.
|
/* Sends an IP ID probe to the proxy machine and returns the IP ID.
|
||||||
This function handles retransmissions, and returns -1 if it fails.
|
This function handles retransmissions, and returns -1 if it fails.
|
||||||
@@ -188,10 +222,18 @@ static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
|
|||||||
unsigned int bytes;
|
unsigned int bytes;
|
||||||
int base_port;
|
int base_port;
|
||||||
struct ip *ip;
|
struct ip *ip;
|
||||||
struct tcp_hdr *tcp;
|
struct tcp_hdr *tcp = NULL;
|
||||||
static u32 seq_base = 0;
|
static u32 seq_base = 0;
|
||||||
static u32 ack = 0;
|
static u32 ack = 0;
|
||||||
static int packet_send_count = 0; /* Total # of probes sent by this program -- to ensure that our sequence # always changes */
|
static int packet_send_count = 0; /* Total # of probes sent by this program -- to ensure that our sequence # always changes */
|
||||||
|
u32 packetlen = 0;
|
||||||
|
u8 *ipv6_packet = NULL;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
size_t sslen;
|
||||||
|
struct ip6_hdr *ip6 = NULL;
|
||||||
|
const void *ipv6_data;
|
||||||
|
u8 hdr;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (o.magic_port_set)
|
if (o.magic_port_set)
|
||||||
base_port = o.magic_port;
|
base_port = o.magic_port;
|
||||||
@@ -208,14 +250,30 @@ static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
|
|||||||
gettimeofday(&tv_sent[tries], NULL);
|
gettimeofday(&tv_sent[tries], NULL);
|
||||||
|
|
||||||
/* Time to send the pr0be!*/
|
/* Time to send the pr0be!*/
|
||||||
send_tcp_raw(proxy->rawsd, proxy->ethptr,
|
if (o.af() == AF_INET)
|
||||||
proxy->host.v4sourceip(), proxy->host.v4hostip(),
|
send_tcp_raw(proxy->rawsd, proxy->ethptr,
|
||||||
o.ttl, false,
|
proxy->host.v4sourceip(), proxy->host.v4hostip(),
|
||||||
o.ipoptions, o.ipoptionslen,
|
o.ttl, false,
|
||||||
base_port + tries, proxy->probe_port,
|
o.ipoptions, o.ipoptionslen,
|
||||||
seq_base + (packet_send_count++ * 500) + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
base_port + tries, proxy->probe_port,
|
||||||
(u8 *) "\x02\x04\x05\xb4", 4,
|
seq_base + (packet_send_count++ * 500) + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
||||||
NULL, 0);
|
(u8 *) "\x02\x04\x05\xb4", 4,
|
||||||
|
NULL, 0);
|
||||||
|
else {
|
||||||
|
ipv6_packet = build_tcp_raw_ipv6(proxy->host.v6sourceip(), proxy->host.v6hostip(),
|
||||||
|
0x00, 0x0000,
|
||||||
|
o.ttl,
|
||||||
|
base_port + tries, proxy->probe_port,
|
||||||
|
seq_base + (packet_send_count++ * 500) + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
||||||
|
(u8 *) "\x02\x04\x05\xb4", 4,
|
||||||
|
NULL, 0,
|
||||||
|
&packetlen);
|
||||||
|
proxy->host.TargetSockAddr(&ss, &sslen);
|
||||||
|
res = send_ip_packet(proxy->rawsd, proxy->ethptr, &ss, ipv6_packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send IPv6 packet");
|
||||||
|
free(ipv6_packet);
|
||||||
|
}
|
||||||
sent++;
|
sent++;
|
||||||
tries++;
|
tries++;
|
||||||
|
|
||||||
@@ -227,15 +285,26 @@ static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
|
|||||||
to_usec = proxy->host.to.timeout - TIMEVAL_SUBTRACT(tv_end, tv_sent[tries - 1]);
|
to_usec = proxy->host.to.timeout - TIMEVAL_SUBTRACT(tv_end, tv_sent[tries - 1]);
|
||||||
if (to_usec < 0)
|
if (to_usec < 0)
|
||||||
to_usec = 0; // Final no-block poll
|
to_usec = 0; // Final no-block poll
|
||||||
ip = (struct ip *) readipv4_pcap(proxy->pd, &bytes, to_usec, &rcvdtime, NULL, true);
|
ip = (struct ip *) readip_pcap(proxy->pd, &bytes, to_usec, &rcvdtime, NULL, true);
|
||||||
gettimeofday(&tv_end, NULL);
|
gettimeofday(&tv_end, NULL);
|
||||||
if (ip) {
|
if (ip) {
|
||||||
if (bytes < ( 4 * ip->ip_hl) + 14U)
|
if (o.af() == AF_INET) {
|
||||||
continue;
|
if (bytes < ( 4 * ip->ip_hl) + 14U)
|
||||||
|
continue;
|
||||||
if (ip->ip_p == IPPROTO_TCP) {
|
if (ip->ip_p == IPPROTO_TCP)
|
||||||
|
tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
||||||
tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
} else if (o.af() == AF_INET6) {
|
||||||
|
if (ip->ip_v != 6) {
|
||||||
|
error("IPv6 packet with a version field != 6 received");
|
||||||
|
} else {
|
||||||
|
ip6 = (struct ip6_hdr *) ip;
|
||||||
|
ipv6_data = ipv6_get_data(ip6, &packetlen, &hdr);
|
||||||
|
if (hdr == IPPROTO_TCP && ipv6_data != NULL) {
|
||||||
|
tcp = (struct tcp_hdr *) ipv6_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tcp) {
|
||||||
if (ntohs(tcp->th_dport) < base_port || ntohs(tcp->th_dport) - base_port >= tries || ntohs(tcp->th_sport) != proxy->probe_port || ((tcp->th_flags & TH_RST) == 0)) {
|
if (ntohs(tcp->th_dport) < base_port || ntohs(tcp->th_dport) - base_port >= tries || ntohs(tcp->th_sport) != proxy->probe_port || ((tcp->th_flags & TH_RST) == 0)) {
|
||||||
if (ntohs(tcp->th_dport) > o.magic_port && ntohs(tcp->th_dport) < (o.magic_port + 260)) {
|
if (ntohs(tcp->th_dport) > o.magic_port && ntohs(tcp->th_dport) < (o.magic_port + 260)) {
|
||||||
if (o.debugging) {
|
if (o.debugging) {
|
||||||
@@ -245,7 +314,12 @@ static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
|
|||||||
proxy->host.to.rttvar = (int) (proxy->host.to.rttvar * 1.2);
|
proxy->host.to.rttvar = (int) (proxy->host.to.rttvar * 1.2);
|
||||||
rcvd++;
|
rcvd++;
|
||||||
} else if (o.debugging > 1) {
|
} else if (o.debugging > 1) {
|
||||||
error("Received unexpected response packet from %s during IP ID zombie probing:", inet_ntoa(ip->ip_src));
|
char straddr[INET6_ADDRSTRLEN];
|
||||||
|
if (o.af() == AF_INET)
|
||||||
|
inet_ntop(AF_INET, &(ip->ip_src), straddr, sizeof(straddr));
|
||||||
|
else if (o.af() == AF_INET6)
|
||||||
|
inet_ntop(AF_INET6, &(ip6->ip6_src), straddr, sizeof(straddr));
|
||||||
|
error("Received unexpected response packet from %s during IP ID zombie probing:", straddr);
|
||||||
readtcppacket( (unsigned char *) ip, MIN(ntohs(ip->ip_len), bytes));
|
readtcppacket( (unsigned char *) ip, MIN(ntohs(ip->ip_len), bytes));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -254,7 +328,10 @@ static int ipid_proxy_probe(struct idle_proxy_info *proxy, int *probes_sent,
|
|||||||
trynum = ntohs(tcp->th_dport) - base_port;
|
trynum = ntohs(tcp->th_dport) - base_port;
|
||||||
rcvd++;
|
rcvd++;
|
||||||
|
|
||||||
ipid = ntohs(ip->ip_id);
|
if (o.af() == AF_INET)
|
||||||
|
ipid = ntohs(ip->ip_id);
|
||||||
|
else if (o.af() == AF_INET6)
|
||||||
|
ipid = ipv6_get_fragment_id(ip6, bytes);
|
||||||
adjust_timeouts2(&(tv_sent[trynum]), &rcvdtime, &(proxy->host.to));
|
adjust_timeouts2(&(tv_sent[trynum]), &rcvdtime, &(proxy->host.to));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,6 +365,10 @@ static int ipid_distance(int seqclass , u32 startid, u32 endid) {
|
|||||||
return endid - startid;
|
return endid - startid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seqclass == IPID_SEQ_INCR_BY_2) {
|
||||||
|
return (endid - startid)/2;
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -303,22 +384,139 @@ static void initialize_proxy_struct(struct idle_proxy_info *proxy) {
|
|||||||
proxy->ethptr = NULL;
|
proxy->ethptr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forces the permanent use of the IPv6 extension header for fragmentation in each IPv6 packet sent from
|
||||||
|
* the idle host to the target or the attacker
|
||||||
|
* This is achieved by first sending a ping, and afterwards an ICMPv6 Packet Too Big message
|
||||||
|
* which states that the response from the ping was too big, our MTU is smaller than the IPv6 minimum MTU */
|
||||||
|
static void ipv6_force_fragmentation(struct idle_proxy_info *proxy, Target *target) {
|
||||||
|
int hardtimeout = 9000000; /* Generally don't wait more than 9 secs total */
|
||||||
|
char filter[512]; /* Libpcap filter string */
|
||||||
|
struct ip *ip;
|
||||||
|
/* The maximum data size we can create without fragmenting, considering that the headers also need place */
|
||||||
|
char data[IP6_MTU_MIN - IPv6_HEADER_LEN - ETH_HDR_LEN - ICMPv6_MIN_HEADER_LEN];
|
||||||
|
unsigned int datalen, bytes;
|
||||||
|
const unsigned int proxy_reply_timeout = 2000;
|
||||||
|
const void *rdata; //the data received in the echo response
|
||||||
|
struct timeval tmptv, rcvdtime, ipv6_packet_send_time;
|
||||||
|
struct abstract_ip_hdr hdr;
|
||||||
|
bool response_received = false;
|
||||||
|
struct icmpv6_hdr *icmp6_header;
|
||||||
|
u8 *ipv6_packet = NULL;
|
||||||
|
u32 packetlen = 0;
|
||||||
|
u16 pingid = 0;
|
||||||
|
u16 seq = 0;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
size_t sslen;
|
||||||
|
int res;
|
||||||
|
assert(proxy);
|
||||||
|
|
||||||
|
/* First, we force the proxy to provide us with a fragmentation header in each packet
|
||||||
|
by sending an ping and afterwards an ICMPv6 Packet Too Big */
|
||||||
|
memset(data,'A', sizeof(data));
|
||||||
|
pingid = get_random_u16();
|
||||||
|
seq = get_random_u16();
|
||||||
|
|
||||||
|
/* pcap, to get the answer. Max size here is the IPv6 minimum MTU */
|
||||||
|
if ((proxy->pd = my_pcap_open_live(proxy->host.deviceName(), IP6_MTU_MIN, (o.spoofsource) ? 1 : 0, 50)) == NULL)
|
||||||
|
fatal("%s", PCAP_OPEN_ERRMSG);
|
||||||
|
|
||||||
|
Snprintf(filter, sizeof(filter), "icmp6 and src host %s and dst host %s", proxy->host.targetipstr(), proxy->host.sourceipstr());
|
||||||
|
if (o.debugging)
|
||||||
|
log_write(LOG_STDOUT, "Packet capture filter (device %s): %s\n", proxy->host.deviceFullName(), filter);
|
||||||
|
|
||||||
|
/* Make a ping that is in total 1280 byte long and send it */
|
||||||
|
proxy->host.TargetSockAddr(&ss, &sslen);
|
||||||
|
ipv6_packet = build_icmpv6_raw(proxy->host.v6sourceip(), proxy->host.v6hostip(), 0x00, 0x0000, o.ttl, seq , pingid, ICMPV6_ECHO, 0x00, data, sizeof(data) , &packetlen);
|
||||||
|
res = send_ip_packet(proxy->rawsd, proxy->ethptr, &ss, ipv6_packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send ICMPv6 Echo Request to the idle host");
|
||||||
|
free(ipv6_packet);
|
||||||
|
gettimeofday(&ipv6_packet_send_time, NULL);
|
||||||
|
|
||||||
|
/* Now let's wait for the answer */
|
||||||
|
while (!response_received) {
|
||||||
|
gettimeofday(&tmptv, NULL);
|
||||||
|
ip = (struct ip *) readip_pcap(proxy->pd, &bytes, proxy_reply_timeout, &rcvdtime, NULL, true);
|
||||||
|
if (!ip) {
|
||||||
|
if (TIMEVAL_SUBTRACT(tmptv, ipv6_packet_send_time) >= hardtimeout) {
|
||||||
|
fatal("Idle scan zombie %s (%s) port %hu cannot be used because it has not returned any of our ICMPv6 Echo Requests -- perhaps it is down or firewalled.",
|
||||||
|
proxy->host.HostName(), proxy->host.targetipstr(),
|
||||||
|
proxy->probe_port);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
datalen = bytes;
|
||||||
|
rdata = ip_get_data(ip, &datalen, &hdr);
|
||||||
|
if (hdr.version == 6 && hdr.proto == IPPROTO_ICMPV6) {
|
||||||
|
icmp6_header = (struct icmpv6_hdr *) rdata;
|
||||||
|
if (icmp6_header->icmpv6_type == ICMPV6_ECHOREPLY) {
|
||||||
|
const struct icmpv6_msg_echo *echo;
|
||||||
|
echo = (struct icmpv6_msg_echo *) ((u8 *) icmp6_header + sizeof(*icmp6_header));
|
||||||
|
if (ntohs(echo->icmpv6_id) == pingid && ntohs(echo->icmpv6_seq) == seq)
|
||||||
|
response_received=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy->pd)
|
||||||
|
pcap_close(proxy->pd);
|
||||||
|
|
||||||
|
/* Now we can tell the idle host that its reply was too big, we want it smaller than the IPV6 minimum MTU */
|
||||||
|
/* the data contains first the MTU we want, and then the received IPv6 package */
|
||||||
|
*(uint32_t *)&data = ntohl(IP6_MTU_MIN - 2);
|
||||||
|
memcpy(&data[4], ip, sizeof(data)-4);
|
||||||
|
|
||||||
|
ipv6_packet = build_icmpv6_raw(proxy->host.v6sourceip(), proxy->host.v6hostip(), 0x00, 0x0000, o.ttl, 0x00 , 0x00, 0x02, 0x00, data, sizeof(data) , &packetlen);
|
||||||
|
res = send_ip_packet(proxy->rawsd, proxy->ethptr, &ss, ipv6_packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send spoofed ICMPv6 Echo Request to the idle host");
|
||||||
|
|
||||||
|
free(ipv6_packet);
|
||||||
|
|
||||||
|
/* Now we do the same in the name of the target */
|
||||||
|
/* No pcap this time, we won't receive the answer */
|
||||||
|
memset(data,'A', sizeof(data));
|
||||||
|
pingid = get_random_u16();
|
||||||
|
seq = get_random_u16();
|
||||||
|
|
||||||
|
ipv6_packet = build_icmpv6_raw(target->v6hostip(), proxy->host.v6hostip(), 0x00, 0x0000, o.ttl, seq , pingid, ICMPV6_ECHO, 0x00, data, sizeof(data) , &packetlen);
|
||||||
|
res = send_ip_packet(proxy->rawsd, proxy->ethptr, &ss, ipv6_packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send ICMPv6 Echo Request to the idle host");
|
||||||
|
|
||||||
|
free(ipv6_packet);
|
||||||
|
|
||||||
|
/* Now we guess what answer the decoy host sent to the target, so that we can piggyback this on the ICMPV6 Packet too Big message */
|
||||||
|
ipv6_packet = build_icmpv6_raw(proxy->host.v6hostip(), target->v6hostip(), 0x00, 0x0000, o.ttl, seq , pingid, ICMPV6_ECHOREPLY, 0x00, data, sizeof(data) , &packetlen);
|
||||||
|
*(uint32_t *)&data = ntohl(IP6_MTU_MIN - 2);
|
||||||
|
memcpy(&data[4], ipv6_packet, sizeof(data)-4);
|
||||||
|
free(ipv6_packet);
|
||||||
|
|
||||||
|
ipv6_packet = build_icmpv6_raw(target->v6hostip(), proxy->host.v6hostip(), 0x00, 0x0000, o.ttl, 0x00 , 0x00, 0x02, 0x00, data, sizeof(data) , &packetlen);
|
||||||
|
/* give the decoy host time to reply to the target */
|
||||||
|
usleep(10000);
|
||||||
|
res = send_ip_packet(proxy->rawsd, proxy->ethptr, &ss, ipv6_packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send ICMPv6 PTB to the idle host");
|
||||||
|
free(ipv6_packet);
|
||||||
|
}
|
||||||
|
|
||||||
/* takes a proxy name/IP, resolves it if necessary, tests it for IP ID
|
/* takes a proxy name/IP, resolves it if necessary, tests it for IP ID
|
||||||
suitability, and fills out an idle_proxy_info structure. If the
|
suitability, and fills out an idle_proxy_info structure. If the
|
||||||
proxy is determined to be unsuitable, the function whines and exits
|
proxy is determined to be unsuitable, the function whines and exits
|
||||||
the program */
|
the program */
|
||||||
#define NUM_IPID_PROBES 6
|
#define NUM_IPID_PROBES 6
|
||||||
static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
||||||
const struct in_addr *first_target, const struct scan_lists *ports) {
|
Target *target, const struct scan_lists *ports) {
|
||||||
int probes_sent = 0, probes_returned = 0;
|
unsigned int probes_sent = 0, probes_returned = 0;
|
||||||
int hardtimeout = 9000000; /* Generally don't wait more than 9 secs total */
|
int hardtimeout = 9000000; /* Generally don't wait more than 9 secs total */
|
||||||
unsigned int bytes, to_usec;
|
unsigned int bytes, to_usec;
|
||||||
int timedout = 0;
|
int timedout = 0;
|
||||||
char *p, *q;
|
char *p, *q = NULL, *r;
|
||||||
char *endptr = NULL;
|
char *endptr = NULL;
|
||||||
int seq_response_num;
|
int seq_response_num;
|
||||||
int newipid;
|
int newipid;
|
||||||
int i;
|
unsigned int i;
|
||||||
char filter[512]; /* Libpcap filter string */
|
char filter[512]; /* Libpcap filter string */
|
||||||
char name[MAXHOSTNAMELEN + 1];
|
char name[MAXHOSTNAMELEN + 1];
|
||||||
struct sockaddr_storage ss;
|
struct sockaddr_storage ss;
|
||||||
@@ -333,8 +531,16 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
int ipids[NUM_IPID_PROBES];
|
int ipids[NUM_IPID_PROBES];
|
||||||
u8 probe_returned[NUM_IPID_PROBES];
|
u8 probe_returned[NUM_IPID_PROBES];
|
||||||
struct route_nfo rnfo;
|
struct route_nfo rnfo;
|
||||||
|
assert(proxyName);
|
||||||
|
u8 *ipv6_packet = NULL;
|
||||||
|
u32 packetlen = 0;
|
||||||
|
const struct ip6_hdr *ip6;
|
||||||
|
u8 ip6hdr;
|
||||||
|
const void *ip6data;
|
||||||
|
bool retried_forcing_fragmentation = false;
|
||||||
assert(proxy);
|
assert(proxy);
|
||||||
assert(proxyName);
|
assert(proxyName);
|
||||||
|
int res;
|
||||||
|
|
||||||
ack = get_random_u32();
|
ack = get_random_u32();
|
||||||
|
|
||||||
@@ -348,8 +554,26 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
proxy->max_groupsz = MAX(proxy->min_groupsz, o.max_parallelism ? o.max_parallelism : 100);
|
proxy->max_groupsz = MAX(proxy->min_groupsz, o.max_parallelism ? o.max_parallelism : 100);
|
||||||
proxy->max_senddelay = 100000;
|
proxy->max_senddelay = 100000;
|
||||||
|
|
||||||
Strncpy(name, proxyName, sizeof(name));
|
|
||||||
q = strchr(name, ':');
|
/* If we have an IPv6 address, we specify the port with [address]:port */
|
||||||
|
if (o.af() == AF_INET)
|
||||||
|
q = strchr(proxyName, ':');
|
||||||
|
else if (o.af() == AF_INET6) {
|
||||||
|
r = strstr(proxyName, "]:");
|
||||||
|
if (r != NULL)
|
||||||
|
q = strchr(r, ':');
|
||||||
|
else
|
||||||
|
q = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a : in IPv4 or [] in IPv6, we strip them off */
|
||||||
|
if (o.af() == AF_INET && strchr(proxyName, ':') != NULL )
|
||||||
|
strncpy(name, proxyName , MIN(strcspn(proxyName,":") , sizeof(name)));
|
||||||
|
else if (o.af() == AF_INET6 && strchr(proxyName, '[') != NULL && strchr(proxyName, ']') != NULL)
|
||||||
|
strncpy(name, strchr(proxyName, '[') + 1, MIN(strcspn(proxyName,"]") - strcspn(proxyName, "[") - 1, sizeof(name)));
|
||||||
|
else
|
||||||
|
strncpy(name, proxyName, sizeof(name));
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
*q++ = '\0';
|
*q++ = '\0';
|
||||||
proxy->probe_port = strtoul(q, &endptr, 10);
|
proxy->probe_port = strtoul(q, &endptr, 10);
|
||||||
@@ -427,18 +651,21 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
proxy->ethptr = NULL;
|
proxy->ethptr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now for the pcap opening nonsense ... */
|
if (proxy->host.af() == AF_INET6)
|
||||||
/* Note that the snaplen is 152 = 64 byte max IPhdr + 24 byte max link_layer
|
ipv6_force_fragmentation(proxy, target);
|
||||||
* header + 64 byte max TCP header. */
|
|
||||||
if ((proxy->pd = my_pcap_open_live(proxy->host.deviceName(), 152, (o.spoofsource) ? 1 : 0, 50)) == NULL)
|
/* Now for the pcap opening nonsense ...
|
||||||
|
Snaplen will be the IPv6 minimum MTU of 1280, because an IPv6 packet
|
||||||
|
may have any number of extension header up to the minimal IPv6 MTU */
|
||||||
|
if ((proxy->pd = my_pcap_open_live(proxy->host.deviceName(), IP6_MTU_MIN, (o.spoofsource) ? 1 : 0, 50)) == NULL)
|
||||||
fatal("%s", PCAP_OPEN_ERRMSG);
|
fatal("%s", PCAP_OPEN_ERRMSG);
|
||||||
|
|
||||||
|
|
||||||
p = strdup(proxy->host.targetipstr());
|
p = (char *) proxy->host.targetipstr();
|
||||||
q = strdup(inet_ntoa(proxy->host.v4source()));
|
q = (char *) proxy->host.sourceipstr();
|
||||||
Snprintf(filter, sizeof(filter), "tcp and src host %s and dst host %s and src port %hu", p, q, proxy->probe_port);
|
|
||||||
free(p);
|
/* libpcap doesn't find the source port in IPv6 if there is an extension header. So we check for this later in the tcp header. */
|
||||||
free(q);
|
Snprintf(filter, sizeof(filter), "tcp and src host %s and dst host %s", p, q);
|
||||||
set_pcap_filter(proxy->host.deviceFullName(), proxy->pd, filter);
|
set_pcap_filter(proxy->host.deviceFullName(), proxy->pd, filter);
|
||||||
if (o.debugging)
|
if (o.debugging)
|
||||||
log_write(LOG_STDOUT, "Packet capture filter (device %s): %s\n", proxy->host.deviceFullName(), filter);
|
log_write(LOG_STDOUT, "Packet capture filter (device %s): %s\n", proxy->host.deviceFullName(), filter);
|
||||||
@@ -461,14 +688,30 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
a response with the exact request for timing purposes. So I
|
a response with the exact request for timing purposes. So I
|
||||||
think I'll use TH_SYN, although it is a tough call. */
|
think I'll use TH_SYN, although it is a tough call. */
|
||||||
/* We can't use decoys 'cause that would screw up the IP IDs */
|
/* We can't use decoys 'cause that would screw up the IP IDs */
|
||||||
send_tcp_raw(proxy->rawsd, proxy->ethptr,
|
if (o.af() == AF_INET)
|
||||||
proxy->host.v4sourceip(), proxy->host.v4hostip(),
|
send_tcp_raw(proxy->rawsd, proxy->ethptr,
|
||||||
o.ttl, false,
|
proxy->host.v4sourceip(), proxy->host.v4hostip(),
|
||||||
o.ipoptions, o.ipoptionslen,
|
o.ttl, false,
|
||||||
o.magic_port + probes_sent + 1, proxy->probe_port,
|
o.ipoptions, o.ipoptionslen,
|
||||||
sequence_base + probes_sent + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
o.magic_port + probes_sent + 1, proxy->probe_port,
|
||||||
(u8 *) "\x02\x04\x05\xb4", 4,
|
sequence_base + probes_sent + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
||||||
NULL, 0);
|
(u8 *) "\x02\x04\x05\xb4", 4,
|
||||||
|
NULL, 0);
|
||||||
|
else if (o.af() == AF_INET6) {
|
||||||
|
ipv6_packet = build_tcp_raw_ipv6(proxy->host.v6sourceip(), proxy->host.v6hostip(),
|
||||||
|
0x00, 0x0000,
|
||||||
|
o.ttl,
|
||||||
|
o.magic_port + probes_sent + 1, proxy->probe_port,
|
||||||
|
sequence_base + probes_sent + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
||||||
|
(u8 *) "\x02\x04\x05\xb4", 4,
|
||||||
|
NULL, 0,
|
||||||
|
&packetlen);
|
||||||
|
res = send_ip_packet(proxy->rawsd, proxy->ethptr, &ss, ipv6_packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send IPv6 packet");
|
||||||
|
free(ipv6_packet);
|
||||||
|
}
|
||||||
|
|
||||||
gettimeofday(&probe_send_times[probes_sent], NULL);
|
gettimeofday(&probe_send_times[probes_sent], NULL);
|
||||||
probes_sent++;
|
probes_sent++;
|
||||||
|
|
||||||
@@ -476,7 +719,7 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
while (probes_returned < probes_sent && !timedout) {
|
while (probes_returned < probes_sent && !timedout) {
|
||||||
|
|
||||||
to_usec = (probes_sent == NUM_IPID_PROBES) ? hardtimeout : 1000;
|
to_usec = (probes_sent == NUM_IPID_PROBES) ? hardtimeout : 1000;
|
||||||
ip = (struct ip *) readipv4_pcap(proxy->pd, &bytes, to_usec, &rcvdtime, NULL, true);
|
ip = (struct ip *) readip_pcap(proxy->pd, &bytes, to_usec, &rcvdtime, NULL, true);
|
||||||
|
|
||||||
gettimeofday(&tmptv, NULL);
|
gettimeofday(&tmptv, NULL);
|
||||||
|
|
||||||
@@ -491,32 +734,94 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
timedout = 1;
|
timedout = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastipid != 0 && ip->ip_id == lastipid) {
|
if (o.af() == AF_INET) {
|
||||||
continue; /* probably a duplicate */
|
if (ip->ip_v != 4) {
|
||||||
}
|
error("Received a packet with version field != 4");
|
||||||
lastipid = ip->ip_id;
|
|
||||||
|
|
||||||
if (bytes < ( 4 * ip->ip_hl) + 14U)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ip->ip_p == IPPROTO_TCP) {
|
|
||||||
tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
|
||||||
if (ntohs(tcp->th_dport) < (o.magic_port + 1) || ntohs(tcp->th_dport) - o.magic_port > NUM_IPID_PROBES || ntohs(tcp->th_sport) != proxy->probe_port || ((tcp->th_flags & TH_RST) == 0)) {
|
|
||||||
if (o.debugging > 1)
|
|
||||||
error("Received unexpected response packet from %s during initial IP ID zombie testing", inet_ntoa(ip->ip_src));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (lastipid != 0 && ip->ip_id == lastipid) {
|
||||||
|
continue; /* probably a duplicate */
|
||||||
|
}
|
||||||
|
lastipid = ip->ip_id;
|
||||||
|
if (bytes < ( 4 * ip->ip_hl) + 14U)
|
||||||
|
continue;
|
||||||
|
|
||||||
seq_response_num = probes_returned;
|
if (ip->ip_p == IPPROTO_TCP) {
|
||||||
|
tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
||||||
|
/* Checking now for the source port, which we were not able to do in the libpcap filter */
|
||||||
|
if (ntohs(tcp->th_sport) != proxy->probe_port) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* The stuff below only works when we send SYN packets instead of
|
if (ntohs(tcp->th_dport) < (o.magic_port + 1) || ntohs(tcp->th_dport) - o.magic_port > NUM_IPID_PROBES || ((tcp->th_flags & TH_RST) == 0)) {
|
||||||
SYN|ACK, but then are slightly less stealthy and have less chance
|
if (o.debugging > 1)
|
||||||
of sneaking through the firewall. Plus SYN|ACK is what they will
|
error("Received unexpected response packet from %s during initial IP ID zombie testing", inet_ntoa(ip->ip_src));
|
||||||
be receiving back from the target */
|
continue;
|
||||||
probes_returned++;
|
}
|
||||||
ipids[seq_response_num] = ntohs(ip->ip_id);
|
|
||||||
probe_returned[seq_response_num] = 1;
|
seq_response_num = probes_returned;
|
||||||
adjust_timeouts2(&probe_send_times[seq_response_num], &rcvdtime, &(proxy->host.to));
|
|
||||||
|
/* The stuff below only works when we send SYN packets instead of
|
||||||
|
SYN|ACK, but then are slightly less stealthy and have less chance
|
||||||
|
of sneaking through the firewall. Plus SYN|ACK is what they will
|
||||||
|
be receiving back from the target */
|
||||||
|
probes_returned++;
|
||||||
|
ipids[seq_response_num] = ntohs(ip->ip_id);
|
||||||
|
probe_returned[seq_response_num] = 1;
|
||||||
|
adjust_timeouts2(&probe_send_times[seq_response_num], &rcvdtime, &(proxy->host.to));
|
||||||
|
}
|
||||||
|
} else if (o.af() == AF_INET6) {
|
||||||
|
if (ip->ip_v != 6) {
|
||||||
|
error("Received a packet with version field != 6");
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
ip6 = (struct ip6_hdr *) ip;
|
||||||
|
newipid = ipv6_get_fragment_id(ip6, bytes);
|
||||||
|
if (newipid < 0 ) {
|
||||||
|
/* ok, the idle host does not seem to append the extension header for fragmentation. Let's try this once more,
|
||||||
|
* maybe the idle host just adjusted its Path MTU. If we keep on having the problem, we quit */
|
||||||
|
if (!retried_forcing_fragmentation) {
|
||||||
|
ipv6_force_fragmentation(proxy, target);
|
||||||
|
retried_forcing_fragmentation = true;
|
||||||
|
} else
|
||||||
|
fatal("IPv6 packet without fragmentation header received - issues with the zombie?");
|
||||||
|
}
|
||||||
|
/* now that the additional ipv6 stuff is done, we do as for IPv4 */
|
||||||
|
if (lastipid != 0 && newipid == (int)lastipid) {
|
||||||
|
continue; /* probably a duplicate */
|
||||||
|
}
|
||||||
|
lastipid = newipid;
|
||||||
|
|
||||||
|
ip6data = ipv6_get_data(ip6, &packetlen, &ip6hdr);
|
||||||
|
if (ip6hdr == IPPROTO_TCP && ip6data != NULL) {
|
||||||
|
tcp = (struct tcp_hdr *) ip6data;
|
||||||
|
/* Checking now for the source port, which we were not able to do in the libpcap filter */
|
||||||
|
if (ntohs(tcp->th_sport) != proxy->probe_port) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
error("Malformed packet received");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ntohs(tcp->th_dport) < (o.magic_port + 1) || ntohs(tcp->th_dport) - o.magic_port > NUM_IPID_PROBES || ((tcp->th_flags & TH_RST) == 0)) {
|
||||||
|
if (o.debugging > 1)
|
||||||
|
error("Received unexpected response packet from %s during initial IP ID zombie testing", inet_ntoa(ip->ip_src));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq_response_num = probes_returned;
|
||||||
|
|
||||||
|
/* The stuff below only works when we send SYN packets instead of
|
||||||
|
SYN|ACK, but then are slightly less stealthy and have less chance
|
||||||
|
of sneaking through the firewall. Plus SYN|ACK is what they will
|
||||||
|
be receiving back from the target */
|
||||||
|
probes_returned++;
|
||||||
|
ipids[seq_response_num] = newipid;
|
||||||
|
probe_returned[seq_response_num] = 1;
|
||||||
|
adjust_timeouts2(&probe_send_times[seq_response_num], &rcvdtime, &(proxy->host.to));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -535,9 +840,13 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
proxy->host.HostName(), proxy->host.targetipstr(),
|
proxy->host.HostName(), proxy->host.targetipstr(),
|
||||||
proxy->probe_port);
|
proxy->probe_port);
|
||||||
|
|
||||||
proxy->seqclass = get_ipid_sequence(probes_returned, ipids, 0);
|
if (o.af() == AF_INET)
|
||||||
|
proxy->seqclass = get_ipid_sequence_16(probes_returned, ipids, 0);
|
||||||
|
else
|
||||||
|
proxy->seqclass = get_ipid_sequence_32(probes_returned, ipids, 0);
|
||||||
switch (proxy->seqclass) {
|
switch (proxy->seqclass) {
|
||||||
case IPID_SEQ_INCR:
|
case IPID_SEQ_INCR:
|
||||||
|
case IPID_SEQ_INCR_BY_2:
|
||||||
case IPID_SEQ_BROKEN_INCR:
|
case IPID_SEQ_BROKEN_INCR:
|
||||||
log_write(LOG_PLAIN, "Idle scan using zombie %s (%s:%hu); Class: %s\n", proxy->host.HostName(), proxy->host.targetipstr(), proxy->probe_port, ipidclass2ascii(proxy->seqclass));
|
log_write(LOG_PLAIN, "Idle scan using zombie %s (%s:%hu); Class: %s\n", proxy->host.HostName(), proxy->host.targetipstr(), proxy->probe_port, ipidclass2ascii(proxy->seqclass));
|
||||||
break;
|
break;
|
||||||
@@ -568,19 +877,34 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
|
|||||||
changed. This will also catch the case where the Nmap user is
|
changed. This will also catch the case where the Nmap user is
|
||||||
behind an egress filter or other measure that prevents this sort of
|
behind an egress filter or other measure that prevents this sort of
|
||||||
sp00fery */
|
sp00fery */
|
||||||
if (first_target) {
|
/* this behavior gets quite common in IPv6 so now its even more important to check */
|
||||||
|
if (target->v4hostip() || target->v6hostip()) {
|
||||||
for (probes_sent = 0; probes_sent < 4; probes_sent++) {
|
for (probes_sent = 0; probes_sent < 4; probes_sent++) {
|
||||||
if (probes_sent != 0)
|
if (probes_sent != 0)
|
||||||
usleep(50000);
|
usleep(50000);
|
||||||
send_tcp_raw(proxy->rawsd, proxy->ethptr,
|
if (target->v4hostip()) {
|
||||||
first_target, proxy->host.v4hostip(),
|
send_tcp_raw(proxy->rawsd, proxy->ethptr,
|
||||||
o.ttl, false,
|
target->v4hostip(), proxy->host.v4hostip(),
|
||||||
o.ipoptions, o.ipoptionslen,
|
o.ttl, false,
|
||||||
o.magic_port, proxy->probe_port,
|
o.ipoptions, o.ipoptionslen,
|
||||||
sequence_base + probes_sent + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
o.magic_port, proxy->probe_port,
|
||||||
(u8 *) "\x02\x04\x05\xb4",
|
sequence_base + probes_sent + 1, ack, 0, TH_SYN | TH_ACK, 0, 0,
|
||||||
4, NULL, 0);
|
(u8 *) "\x02\x04\x05\xb4",
|
||||||
|
4, NULL, 0);
|
||||||
|
} else {
|
||||||
|
ipv6_packet = build_tcp_raw_ipv6(target->v6hostip(), proxy->host.v6hostip(),
|
||||||
|
0x00, 0x0000,
|
||||||
|
o.ttl,
|
||||||
|
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,
|
||||||
|
&packetlen);
|
||||||
|
res = send_ip_packet(proxy->rawsd, proxy->ethptr, &ss, ipv6_packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send IPv6 packet ");
|
||||||
|
free(ipv6_packet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sleep a little while to give packets time to reach their destination */
|
/* Sleep a little while to give packets time to reach their destination */
|
||||||
@@ -695,10 +1019,16 @@ static int idlescan_countopen2(struct idle_proxy_info *proxy,
|
|||||||
int lasttry = 0;
|
int lasttry = 0;
|
||||||
int dotry3 = 0;
|
int dotry3 = 0;
|
||||||
struct eth_nfo eth;
|
struct eth_nfo eth;
|
||||||
|
u8 *packet = NULL;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
size_t sslen;
|
||||||
|
u32 packetlen = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (seq == 0)
|
if (seq == 0)
|
||||||
seq = get_random_u32();
|
seq = get_random_u32();
|
||||||
|
|
||||||
|
target->TargetSockAddr(&ss, &sslen);
|
||||||
memset(&end, 0, sizeof(end));
|
memset(&end, 0, sizeof(end));
|
||||||
memset(&latestchange, 0, sizeof(latestchange));
|
memset(&latestchange, 0, sizeof(latestchange));
|
||||||
gettimeofday(&start, NULL);
|
gettimeofday(&start, NULL);
|
||||||
@@ -727,13 +1057,27 @@ static int idlescan_countopen2(struct idle_proxy_info *proxy,
|
|||||||
but doing it the straightforward way (using the same decoys as
|
but doing it the straightforward way (using the same decoys as
|
||||||
we use in probing the proxy box is risky. I'll have to think
|
we use in probing the proxy box is risky. I'll have to think
|
||||||
about this more. */
|
about this more. */
|
||||||
send_tcp_raw(proxy->rawsd, eth.ethsd ? ð : NULL,
|
if ( o.af() == AF_INET ) {
|
||||||
proxy->host.v4hostip(), target->v4hostip(),
|
send_tcp_raw(proxy->rawsd, eth.ethsd ? ð : NULL,
|
||||||
o.ttl, false,
|
proxy->host.v4hostip(), target->v4hostip(),
|
||||||
o.ipoptions, o.ipoptionslen,
|
o.ttl, false,
|
||||||
proxy->probe_port, ports[pr0be], seq, 0, 0, TH_SYN, 0, 0,
|
o.ipoptions, o.ipoptionslen,
|
||||||
(u8 *) "\x02\x04\x05\xb4", 4,
|
proxy->probe_port, ports[pr0be], seq, 0, 0, TH_SYN, 0, 0,
|
||||||
o.extra_payload, o.extra_payload_length);
|
(u8 *) "\x02\x04\x05\xb4", 4,
|
||||||
|
o.extra_payload, o.extra_payload_length);
|
||||||
|
} else {
|
||||||
|
packet = build_tcp_raw_ipv6(proxy->host.v6hostip(), target->v6hostip(),
|
||||||
|
0x00, 0x0000,
|
||||||
|
o.ttl,
|
||||||
|
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,
|
||||||
|
&packetlen);
|
||||||
|
res = send_ip_packet(proxy->rawsd, eth.ethsd ? ð : NULL, &ss, packet, packetlen);
|
||||||
|
if (res == -1)
|
||||||
|
fatal("Error occured while trying to send IPv6 packet");
|
||||||
|
free(packet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gettimeofday(&end, NULL);
|
gettimeofday(&end, NULL);
|
||||||
|
|
||||||
@@ -1044,7 +1388,7 @@ void idle_scan(Target *target, u16 *portarray, int numports,
|
|||||||
|
|
||||||
/* If this is the first call, */
|
/* If this is the first call, */
|
||||||
if (!*lastproxy) {
|
if (!*lastproxy) {
|
||||||
initialize_idleproxy(&proxy, proxyName, target->v4hostip(), ports);
|
initialize_idleproxy(&proxy, proxyName, target, ports);
|
||||||
strncpy(lastproxy, proxyName, sizeof(lastproxy));
|
strncpy(lastproxy, proxyName, sizeof(lastproxy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
nmap.cc
2
nmap.cc
@@ -2689,6 +2689,8 @@ const char *ipidclass2ascii(int seqclass) {
|
|||||||
return "Duplicated ipid (!)";
|
return "Duplicated ipid (!)";
|
||||||
case IPID_SEQ_INCR:
|
case IPID_SEQ_INCR:
|
||||||
return "Incremental";
|
return "Incremental";
|
||||||
|
case IPID_SEQ_INCR_BY_2:
|
||||||
|
return "Incrementing by 2";
|
||||||
case IPID_SEQ_BROKEN_INCR:
|
case IPID_SEQ_BROKEN_INCR:
|
||||||
return "Broken little-endian incremental";
|
return "Broken little-endian incremental";
|
||||||
case IPID_SEQ_RD:
|
case IPID_SEQ_RD:
|
||||||
|
|||||||
1
nmap.h
1
nmap.h
@@ -410,6 +410,7 @@ 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_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_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_ZERO 6 /* Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) */
|
||||||
|
#define IPID_SEQ_INCR_BY_2 7 /* simple increment by two each time */
|
||||||
|
|
||||||
#ifndef MAXHOSTNAMELEN
|
#ifndef MAXHOSTNAMELEN
|
||||||
#define MAXHOSTNAMELEN 64
|
#define MAXHOSTNAMELEN 64
|
||||||
|
|||||||
99
osscan2.cc
99
osscan2.cc
@@ -198,6 +198,7 @@ static struct AVal *make_aval_ipid_seq(struct AVal *av, const char *attribute,
|
|||||||
case IPID_SEQ_CONSTANT:
|
case IPID_SEQ_CONSTANT:
|
||||||
av->value = string_pool_sprintf("%X", ipids[0]);
|
av->value = string_pool_sprintf("%X", ipids[0]);
|
||||||
break;
|
break;
|
||||||
|
case IPID_SEQ_INCR_BY_2:
|
||||||
case IPID_SEQ_INCR:
|
case IPID_SEQ_INCR:
|
||||||
av->value = "I";
|
av->value = "I";
|
||||||
break;
|
break;
|
||||||
@@ -247,32 +248,9 @@ int get_initial_ttl_guess(u8 ttl) {
|
|||||||
one of the IPID_SEQ_* classifications defined in nmap.h . If the
|
one of the IPID_SEQ_* classifications defined in nmap.h . If the
|
||||||
function cannot determine the sequence, IPID_SEQ_UNKNOWN is returned.
|
function cannot determine the sequence, IPID_SEQ_UNKNOWN is returned.
|
||||||
This islocalhost argument is a boolean specifying whether these
|
This islocalhost argument is a boolean specifying whether these
|
||||||
numbers were generated by scanning localhost. NOTE: the "ipids" argument
|
numbers were generated by scanning localhost. */
|
||||||
may be modified if localhost is set to true. */
|
int identify_sequence(int numSamples, u32 *ipid_diffs, int islocalhost, int allipideqz) {
|
||||||
int get_ipid_sequence(int numSamples, int *ipids, int islocalhost) {
|
int i, j, k, l;
|
||||||
u16 ipid_diffs[32];
|
|
||||||
int i, j, k;
|
|
||||||
int allipideqz = 1; /* Flag that means "All IP.IDs returned during sequencing
|
|
||||||
* are zero. This is unset if we find a nonzero */
|
|
||||||
|
|
||||||
assert(numSamples < (int) (sizeof(ipid_diffs) / 2));
|
|
||||||
if (numSamples < 2)
|
|
||||||
return IPID_SEQ_UNKNOWN;
|
|
||||||
|
|
||||||
for (i = 1; i < numSamples; i++) {
|
|
||||||
if (ipids[i - 1] != 0 || ipids[i] != 0)
|
|
||||||
allipideqz = 0; /* All IP.ID values do *NOT* equal zero */
|
|
||||||
|
|
||||||
if (ipids[i - 1] <= ipids[i]) {
|
|
||||||
ipid_diffs[i - 1] = ipids[i] - ipids[i - 1];
|
|
||||||
} else {
|
|
||||||
ipid_diffs[i - 1] = (u16) (ipids[i] - ipids[i - 1] + 65536);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Random */
|
|
||||||
if (numSamples > 2 && ipid_diffs[i - 1] > 20000)
|
|
||||||
return IPID_SEQ_RD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ZERO */
|
/* ZERO */
|
||||||
if (allipideqz)
|
if (allipideqz)
|
||||||
@@ -321,11 +299,16 @@ int get_ipid_sequence(int numSamples, int *ipids, int islocalhost) {
|
|||||||
j = 1; /* j is a flag meaning "all differences seen are < 10" */
|
j = 1; /* j is a flag meaning "all differences seen are < 10" */
|
||||||
k = 1; /* k is a flag meaning "all difference seen are multiples of 256 and
|
k = 1; /* k is a flag meaning "all difference seen are multiples of 256 and
|
||||||
* no greater than 5120" */
|
* no greater than 5120" */
|
||||||
|
l = 1; /* l is a flag meaning "all differences are multiples of 2" */
|
||||||
for (i = 0; i < numSamples - 1; i++) {
|
for (i = 0; i < numSamples - 1; i++) {
|
||||||
if (k && (ipid_diffs[i] > 5120 || ipid_diffs[i] % 256 != 0)) {
|
if (k && (ipid_diffs[i] > 5120 || ipid_diffs[i] % 256 != 0)) {
|
||||||
k = 0;
|
k = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (l && ipid_diffs[i] % 2 != 0) {
|
||||||
|
l = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (j && ipid_diffs[i] > 9) {
|
if (j && ipid_diffs[i] > 9) {
|
||||||
j = 0;
|
j = 0;
|
||||||
}
|
}
|
||||||
@@ -336,13 +319,69 @@ int get_ipid_sequence(int numSamples, int *ipids, int islocalhost) {
|
|||||||
return IPID_SEQ_BROKEN_INCR;
|
return IPID_SEQ_BROKEN_INCR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Incremental */
|
/* Incrementing by 2 */
|
||||||
|
if (l == 1)
|
||||||
|
return IPID_SEQ_INCR_BY_2;
|
||||||
|
|
||||||
|
/* Incremental by 1 */
|
||||||
if (j == 1)
|
if (j == 1)
|
||||||
return IPID_SEQ_INCR;
|
return IPID_SEQ_INCR;
|
||||||
|
|
||||||
return IPID_SEQ_UNKNOWN;
|
return IPID_SEQ_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate the distances between the ipids and write them
|
||||||
|
into the ipid_diffs array */
|
||||||
|
int get_diffs(u32 *ipid_diffs, int numSamples, int *ipids, int islocalhost) {
|
||||||
|
int i;
|
||||||
|
int allipideqz = 1;
|
||||||
|
|
||||||
|
if (numSamples < 2)
|
||||||
|
return IPID_SEQ_UNKNOWN;
|
||||||
|
|
||||||
|
for (i = 1; i < numSamples; i++) {
|
||||||
|
if (ipids[i - 1] != 0 || ipids[i] != 0)
|
||||||
|
allipideqz = 0; /* All IP.ID values do *NOT* equal zero */
|
||||||
|
|
||||||
|
if (ipids[i - 1] <= ipids[i]) {
|
||||||
|
ipid_diffs[i - 1] = ipids[i] - ipids[i - 1];
|
||||||
|
} else {
|
||||||
|
ipid_diffs[i - 1] = (u32) (ipids[i] - ipids[i - 1] + 4294967296);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Random */
|
||||||
|
if (numSamples > 2 && ipid_diffs[i - 1] > 20000)
|
||||||
|
return IPID_SEQ_RD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allipideqz;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indentify the ipid sequence for 32-bit IPID values (IPv6) */
|
||||||
|
int get_ipid_sequence_32(int numSamples, int *ipids, int islocalhost) {
|
||||||
|
int allipideqz=1;
|
||||||
|
u32 ipid_diffs[32];
|
||||||
|
assert(numSamples < (int) (sizeof(ipid_diffs) / 2));
|
||||||
|
allipideqz = get_diffs(ipid_diffs, numSamples, ipids, islocalhost);
|
||||||
|
return identify_sequence(numSamples, ipid_diffs, islocalhost, allipideqz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indentify the ipid sequence for 16-bit IPID values (IPv4) */
|
||||||
|
int get_ipid_sequence_16(int numSamples, int *ipids, int islocalhost) {
|
||||||
|
int i;
|
||||||
|
int allipideqz=1;
|
||||||
|
u32 ipid_diffs[32];
|
||||||
|
assert(numSamples < (int) (sizeof(ipid_diffs) / 2));
|
||||||
|
allipideqz = get_diffs(ipid_diffs, numSamples, ipids, islocalhost);
|
||||||
|
/* AND with 0xffff so that in case the 16 bit counter was
|
||||||
|
* flipped over we still have a continuous sequence */
|
||||||
|
for (i = 0; i < numSamples; i++) {
|
||||||
|
ipid_diffs[i] = ipid_diffs[i] & 0xffff;
|
||||||
|
}
|
||||||
|
return identify_sequence(numSamples, ipid_diffs, islocalhost, allipideqz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Start the timeout clocks of any targets that aren't already timedout */
|
/* Start the timeout clocks of any targets that aren't already timedout */
|
||||||
static void startTimeOutClocks(OsScanInfo *OSI) {
|
static void startTimeOutClocks(OsScanInfo *OSI) {
|
||||||
@@ -2374,7 +2413,7 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (good_tcp_ipid_num >= 3) {
|
if (good_tcp_ipid_num >= 3) {
|
||||||
tcp_ipid_seqclass = get_ipid_sequence(good_tcp_ipid_num, hss->ipid.tcp_ipids, islocalhost(hss->target->TargetSockAddr()));
|
tcp_ipid_seqclass = get_ipid_sequence_16(good_tcp_ipid_num, hss->ipid.tcp_ipids, islocalhost(hss->target->TargetSockAddr()));
|
||||||
} else {
|
} else {
|
||||||
tcp_ipid_seqclass = IPID_SEQ_UNKNOWN;
|
tcp_ipid_seqclass = IPID_SEQ_UNKNOWN;
|
||||||
}
|
}
|
||||||
@@ -2382,13 +2421,13 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
hss->si.ipid_seqclass = tcp_ipid_seqclass;
|
hss->si.ipid_seqclass = tcp_ipid_seqclass;
|
||||||
|
|
||||||
if (good_tcp_closed_ipid_num >= 2) {
|
if (good_tcp_closed_ipid_num >= 2) {
|
||||||
tcp_closed_ipid_seqclass = get_ipid_sequence(good_tcp_closed_ipid_num, hss->ipid.tcp_closed_ipids, islocalhost(hss->target->TargetSockAddr()));
|
tcp_closed_ipid_seqclass = get_ipid_sequence_16(good_tcp_closed_ipid_num, hss->ipid.tcp_closed_ipids, islocalhost(hss->target->TargetSockAddr()));
|
||||||
} else {
|
} else {
|
||||||
tcp_closed_ipid_seqclass = IPID_SEQ_UNKNOWN;
|
tcp_closed_ipid_seqclass = IPID_SEQ_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (good_icmp_ipid_num >= 2) {
|
if (good_icmp_ipid_num >= 2) {
|
||||||
icmp_ipid_seqclass = get_ipid_sequence(good_icmp_ipid_num, hss->ipid.icmp_ipids, islocalhost(hss->target->TargetSockAddr()));
|
icmp_ipid_seqclass = get_ipid_sequence_16(good_icmp_ipid_num, hss->ipid.icmp_ipids, islocalhost(hss->target->TargetSockAddr()));
|
||||||
} else {
|
} else {
|
||||||
icmp_ipid_seqclass = IPID_SEQ_UNKNOWN;
|
icmp_ipid_seqclass = IPID_SEQ_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,8 +187,11 @@ typedef enum OFProbeType {
|
|||||||
void os_scan2(std::vector<Target *> &Targets);
|
void os_scan2(std::vector<Target *> &Targets);
|
||||||
|
|
||||||
int get_initial_ttl_guess(u8 ttl);
|
int get_initial_ttl_guess(u8 ttl);
|
||||||
int get_ipid_sequence(int numSamples, int *ipids, int islocalhost);
|
|
||||||
|
|
||||||
|
int identify_sequence(int numSamples, u32 *ipid_diffs, int islocalhost, int allipideqz);
|
||||||
|
int get_diffs(u32 *ipid_diffs, int numSamples, int *ipids, int islocalhost);
|
||||||
|
int get_ipid_sequence_16(int numSamples, int *ipids, int islocalhost);
|
||||||
|
int get_ipid_sequence_32(int numSamples, int *ipids, int islocalhost);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* CLASS DEFINITIONS *
|
* CLASS DEFINITIONS *
|
||||||
|
|||||||
Reference in New Issue
Block a user