idle_scan.cc
来自「Ubuntu packages of security software。 相」· CC 代码 · 共 1,063 行 · 第 1/3 页
CC
1,063 行
the pr0bez */ proxy->host.TargetSockAddr(&ss, &sslen); if (!route_dst(&ss, &rnfo)) fatal("Unable to find appropriate source address and device interface to use when sending packets to %s", proxyName); if (o.spoofsource) { o.SourceSockAddr(&ss, &sslen); proxy->host.setSourceSockAddr(&ss, sslen); proxy->host.setDeviceNames(o.device, o.device); } else { proxy->host.setDeviceNames(rnfo.ii.devname, rnfo.ii.devfullname); proxy->host.setSourceSockAddr(&rnfo.srcaddr, sizeof(rnfo.srcaddr)); } if (rnfo.direct_connect) { proxy->host.setDirectlyConnected(true); } else { proxy->host.setDirectlyConnected(false); proxy->host.setNextHop(&rnfo.nexthop, sizeof(rnfo.nexthop)); } proxy->host.setIfType(rnfo.ii.device_type); if (rnfo.ii.device_type == devt_ethernet) proxy->host.setSrcMACAddress(rnfo.ii.mac); /* Now lets send some probes to check IP ID algorithm ... */ /* First we need a raw socket ... */ if ((o.sendpref & PACKET_SEND_ETH) && proxy->host.ifType() == devt_ethernet) { if (!setTargetNextHopMAC(&proxy->host)) fatal("%s: Failed to determine dst MAC address for Idle proxy", __func__); memcpy(proxy->eth.srcmac, proxy->host.SrcMACAddress(), 6); memcpy(proxy->eth.dstmac, proxy->host.NextHopMACAddress(), 6); proxy->eth.ethsd = eth_open_cached(proxy->host.deviceName()); if (proxy->eth.ethsd == NULL) fatal("%s: Failed to open ethernet device (%s)", __func__, proxy->host.deviceName()); proxy->rawsd = -1; proxy->ethptr = &proxy->eth; } else { if ((proxy->rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0 ) pfatal("socket troubles in %s", __func__); unblock_socket(proxy->rawsd); broadcast_socket(proxy->rawsd);#ifndef WIN32 sethdrinclude(proxy->rawsd);#endif proxy->eth.ethsd = NULL; proxy->ethptr = NULL; }/* Now for the pcap opening nonsense ... */ /* Note that the snaplen is 152 = 64 byte max IPhdr + 24 byte max link_layer * header + 64 byte max TCP header. */ proxy->pd = my_pcap_open_live(proxy->host.deviceName(), 152, (o.spoofsource)? 1 : 0, 50); p = strdup(proxy->host.targetipstr()); q = strdup(inet_ntoa(proxy->host.v4source())); Snprintf(filter, sizeof(filter), "tcp and src host %s and dst host %s and src port %hu", p, q, proxy->probe_port); free(p); free(q); set_pcap_filter(proxy->host.deviceName(), proxy->pd, filter);/* Windows nonsense -- I am not sure why this is needed, but I should get rid of it at sometime */ sequence_base = get_random_u32(); /* Yahoo! It is finally time to send our pr0beZ! */ while(probes_sent < NUM_IPID_PROBES) { if (o.scan_delay) enforce_scan_delay(NULL); else if (probes_sent) usleep(30000); /* TH_SYN|TH_ACK is what the proxy will really be receiving from the target, and is more likely to get through firewalls. But TH_SYN allows us to get a nonzero ACK back so we can associate a response with the exact request for timing purposes. So I 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 */ send_tcp_raw(proxy->rawsd, proxy->ethptr, proxy->host.v4sourceip(), proxy->host.v4hostip(), o.ttl, false, o.ipoptions, o.ipoptionslen, 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); gettimeofday(&probe_send_times[probes_sent], NULL); probes_sent++; /* Time to collect any replies */ while(probes_returned < probes_sent && !timedout) { to_usec = (probes_sent == NUM_IPID_PROBES)? hardtimeout : 1000; ip = (struct ip *) readip_pcap(proxy->pd, &bytes, to_usec, &rcvdtime, NULL); gettimeofday(&tmptv, NULL); if (!ip) { if (probes_sent < NUM_IPID_PROBES) break; if (TIMEVAL_SUBTRACT(tmptv, probe_send_times[probes_sent - 1]) >= hardtimeout) { timedout = 1; } continue; } else if (TIMEVAL_SUBTRACT(tmptv, probe_send_times[probes_sent - 1]) >= hardtimeout) { timedout = 1; } if (lastipid != 0 && ip->ip_id == lastipid) { continue; /* probably a duplicate */ } 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; } 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] = (u16) ntohs(ip->ip_id); probe_returned[seq_response_num] = 1; adjust_timeouts2(&probe_send_times[seq_response_num], &rcvdtime, &(proxy->host.to)); } } } /* Yeah! We're done sending/receiving probes ... now lets ensure all of our responses are adjacent in the array */ for(i=0,probes_returned=0; i < NUM_IPID_PROBES; i++) { if (probe_returned[i]) { if (i > probes_returned) ipids[probes_returned] = ipids[i]; probes_returned++; } } if (probes_returned == 0) fatal("Idle scan zombie %s (%s) port %hu cannot be used because it has not returned any of our probes -- perhaps it is down or firewalled.", proxy->host.HostName(), proxy->host.targetipstr(), proxy->probe_port); proxy->seqclass = get_ipid_sequence(probes_returned, ipids, 0); switch(proxy->seqclass) { case IPID_SEQ_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)); break; default: fatal("Idle scan zombie %s (%s) port %hu cannot be used because IP ID sequencability class is: %s. Try another proxy.", proxy->host.HostName(), proxy->host.targetipstr(), proxy->probe_port, ipidclass2ascii(proxy->seqclass)); } proxy->latestid = ipids[probes_returned - 1]; proxy->current_groupsz = MIN(proxy->max_groupsz, 30); if (probes_returned < NUM_IPID_PROBES) { /* Yikes! We're already losing packets ... clamp down a bit ... */ if (o.debugging) error("Idle scan initial zombie qualification test: %d probes sent, only %d returned", NUM_IPID_PROBES, probes_returned); proxy->current_groupsz = MIN(12, proxy->max_groupsz); proxy->current_groupsz = MAX(proxy->current_groupsz, proxy->min_groupsz); proxy->senddelay += 5000; } /* OK, through experimentation I have found that some hosts *cough* Solaris APPEAR to use simple IP ID incrementing, but in reality they assign a new IP ID base to each host which connects with them. This is actually a good idea on several fronts, but it totally frustrates our efforts (which rely on side-channel IP ID info leaking to different hosts). The good news is that we can easily detect the problem by sending some spoofed packets "from" the first target to the zombie and then probing to verify that the proxy IP ID changed. This will also catch the case where the Nmap user is behind an egress filter or other measure that prevents this sort of sp00fery */ if (first_target) { for (probes_sent = 0; probes_sent < 4; probes_sent++) { if (probes_sent) usleep(50000); send_tcp_raw(proxy->rawsd, proxy->ethptr, first_target, proxy->host.v4hostip(), o.ttl, false, o.ipoptions, o.ipoptionslen, 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); } /* Sleep a little while to give packets time to reach their destination */ usleep(300000); newipid = ipid_proxy_probe(proxy, NULL, NULL); if (newipid == -1) newipid = ipid_proxy_probe(proxy, NULL, NULL); /* OK, we'll give it one more try */ if (newipid < 0) fatal("Your IP ID Zombie (%s; %s) is behaving strangely -- suddenly cannot obtain IP ID", proxy->host.HostName(), proxy->host.targetipstr()); distance = ipid_distance(proxy->seqclass, proxy->latestid, newipid); if (distance <= 0) { fatal("Your IP ID Zombie (%s; %s) is behaving strangely -- suddenly cannot obtain valid IP ID distance.", proxy->host.HostName(), proxy->host.targetipstr()); } else if (distance == 1) { fatal("Even though your Zombie (%s; %s) appears to be vulnerable to IP ID sequence prediction (class: %s), our attempts have failed. This generally means that either the Zombie uses a separate IP ID base for each host (like Solaris), or because you cannot spoof IP packets (perhaps your ISP has enabled egress filtering to prevent IP spoofing), or maybe the target network recognizes the packet source as bogus and drops them", proxy->host.HostName(), proxy->host.targetipstr(), ipidclass2ascii(proxy->seqclass)); } if (o.debugging && distance != 5) { error("WARNING: IP ID spoofing test sent 4 packets and expected a distance of 5, but instead got %d", distance); } proxy->latestid = newipid; } }/* Adjust timing parameters up or down given that an idlescan found a count of 'testcount' while the 'realcount' is as given. If the testcount was correct, timing is made more aggressive, while it is slowed down in the case of an error */static void adjust_idle_timing(struct idle_proxy_info *proxy, Target *target, int testcount, int realcount) { static int notidlewarning = 0; if (o.debugging > 1) log_write(LOG_STDOUT, "%s: tested/true %d/%d -- old grpsz/delay: %f/%d ", __func__, testcount, realcount, proxy->current_groupsz, proxy->senddelay); else if (o.debugging && testcount != realcount) { error("%s: testcount: %d realcount: %d -- old grpsz/delay: %f/%d", __func__, testcount, realcount, proxy->current_groupsz, proxy->senddelay); } if (testcount < realcount) { /* We must have missed a port -- our probe could have been dropped, the response to proxy could have been dropped, or we didn't wait long enough before probing the proxy IP ID. The third case is covered elsewhere in the scan, so we worry most about the first two. The solution is to decrease our group size and add a sending delay *//* packets could be dropped because too many sent at once */ proxy->current_groupsz = MAX(proxy->min_groupsz, proxy->current_groupsz * 0.8); proxy->senddelay += 10000; proxy->senddelay = MIN(proxy->max_senddelay, proxy->senddelay); /* No group size should be greater than .5s of send delays */ proxy->current_groupsz = MAX(proxy->min_groupsz, MIN(proxy->current_groupsz, 500000 / (proxy->senddelay + 1))); } else if (testcount > realcount) { /* Perhaps the proxy host is not really idle ... */ /* I guess all I can do is decrease the group size, so that if the proxy is not really idle, at least we may be able to scan cnunks more quickly in between outside packets */ proxy->current_groupsz = MAX(proxy->min_groupsz, proxy->current_groupsz * 0.8); if (!notidlewarning && o.verbose) { notidlewarning = 1; error("WARNING: idle scan has erroneously detected phantom ports -- is the proxy %s (%s) really idle?", proxy->host.HostName(), proxy->host.targetipstr()); } } else { /* W00p We got a perfect match. That means we get a slight increase in allowed group size and we can lightly decrease the senddelay */ proxy->senddelay = (int) (proxy->senddelay * 0.9); if (proxy->senddelay < 500) proxy->senddelay = 0; proxy->current_groupsz = MIN(proxy->current_groupsz * 1.1, 500000 / (proxy->senddelay + 1)); proxy->current_groupsz = MIN(proxy->max_groupsz, proxy->current_groupsz); } if (o.debugging > 1) log_write(LOG_STDOUT, "-> %f/%d\n", proxy->current_groupsz, proxy->senddelay);}/* OK, now this is the hardcore idle scan function which actually does the testing (most of the other cruft in this file is just coordination, preparation, etc). This function simply uses the idle scan technique to try and count the number of open ports in the given port array. The sent_time and rcv_time are filled in with the times that the probe packet & response were sent/received. They can be NULL if you don't want to use them. The purpose is for timing adjustments if the numbers turn out to be accurate */static int idlescan_countopen2(struct idle_proxy_info *proxy, Target *target, u16 *ports, int numports, struct timeval *sent_time, struct timeval *rcv_time) {#if 0 /* Testing code */ int i; for(i=0; i < numports; i++) if (ports[i] == 22) return 1; return 0;#endif int openports; int tries; int proxyprobes_sent = 0; /* diff. from tries 'cause sometimes we skip tries */ int proxyprobes_rcvd = 0; /* To determine if packets were dr0pped */ int sent, rcvd; int ipid_dist; struct timeval start, end, latestchange, now; struct timeval probe_times[4]; int pr0be; static u32 seq = 0; int newipid = 0; int sleeptime; int lasttry = 0; int dotry3 = 0; struct eth_nfo eth; if (seq == 0) seq = get_random_u32(); memset(&end, 0, sizeof(end)); memset(&latestchange, 0, sizeof(latestchange)); gettimeofday(&start, NULL); if (sent_time) memset(sent_time, 0, sizeof(*sent_time)); if (rcv_time) memset(rcv_time, 0, sizeof(*rcv_time)); if (proxy->rawsd < 0) { if (!setTargetNextHopMAC(target)) fatal("%s: Failed to determine dst MAC address for Idle proxy", __func__); memcpy(eth.srcmac, target->SrcMACAddress(), 6); memcpy(eth.dstmac, target->NextHopMACAddress(), 6); eth.ethsd = eth_open_cached(target->deviceName()); if (eth.ethsd == NULL) fatal("%s: Failed to open ethernet device (%s)", __func__, target->deviceName()); } else eth.ethsd = NULL; /* I start by sending out the SYN pr0bez */ for(pr0be = 0; pr0be < numports; pr0be++) { if (o.scan_delay) enforce_scan_delay(NULL); else if (proxy->senddelay && pr0be > 0) usleep(proxy->senddelay); /* Maybe I should involve decoys in the picture at some point -- 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 about this more. */ send_tcp_raw(proxy->rawsd, eth.ethsd? ð : NULL, proxy->host.v4hostip(), target->v4hostip(), o.ttl, false, o.ipoptions, o.ipoptionslen, 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); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?