Nmap Development mailing list archives
udp scanning with ip_id prediction
From: poplix <poplix () papuasia org>
Date: Mon, 29 Aug 2005 21:53:29 +0200
I found a way to discover if an udp port is open even if a firewall blocks outgoing icmp destination-unreachable packets. This tecnique is very similar to Idlescan and can be done only if the remote machine generates icmp dest unreach (ie icmp packets are blocked by an external firewall and not by local kernel), if its ip stack uses an incremental ip_id field and if at least one icmp (of any type) can reach my computer. If the target machine generates icmp destunreach the ip_id counter for icmp packets is incremented by one, so if i can receive an icmp packet (i.e. echo-reply) i can track ip_id counter and discover if it has been incremented or not. A simple instance: I'm on the machine A(ttaccker) and i want to know if the machine T (arghet) has an application that ("blindly") binds udp port 1234. A sends and icmp echo request to T and waits for echo-reply T sends icmp echo reply to A A saves the ip_id of the T's reply, sends an udp packets to T's port 1234, sends and icmp echo request to T and waits for echo-reply T sends icmp echo reply to A A compute the difference between previous ip_id and current ip_id and stores result to R CASE 1: port is closed R sould be 2 (T sent destination-unreachable to A BUT the firewall blocked it) CASE 2: port is opened R sould be 1 (T didn't send destination-unreachable) I tested it against linux 2.4, linux 2.6, winXP SP2 and MacOSX Tiger and i noticed that both linux 2.4 and 2.6 use a different counter for any layer4 protocol (so use of an icmp packet is mandatory for ip_id tracking), but winxp and macosx use a global counter, is possible to track ip_id using any layer4 protocol. I've also noticed that linux 2.4 and 2.6 set ip_id counter to zero when initialise a tcp session, and when the session is estabilished they set counter to an inital *random* value that is incremented during session. Linux 2.4 responds with id=0 also if a send a SYN|ACK packet, linux 2.6 seems to increment another counter when it sends RST flag (I'm not really sure of that). I've tested it also against OpenBSD and i noticed that i'm a time waster ;) obsd uses a random ip_id.. I've used a linux box as firewall iptables -A PREROUTING -t nat -s 0/0 -d 10.0.0.110 -j DNAT --to 11.1.1.10 iptables -A FORWARD -p icmp --icmp-type destination-unreachable - j DROP eth0 = 10.0.0.10/24 eth1 = 11.1.1.1/24 My Target machine is 11.1.1.10 that has 11.1.1.1 set as default gw And i payed with: /udpck 10.0.0.68 eth0 10.0.0.110 3422 icmp when 11.1.1.10 was a linux box And with: /udpck 10.0.0.68 eth0 10.0.0.110 3422 tcp (or icmp) when 11.1.1.10 was a Win or Macosx box I hope someone can find it usefoul ciao poplix /* udpck.c proof of concept for finding closed udp ports even if a firewall blocks outgoing icmp destination-unreachable packets. based on a tcp/ip flaw that increments ip_id for every packet sent. compile with: gcc updck.c -o udpck -lnet -lpcap usage:./udpck srcip intf dsthost udpport icmp/tcp srcip ip address of intf intf interface name (ie eth0) dsthost Target udpport upd port to check icmp/tcp use icmp or tcp for ip_id tracking ex: ./udpck 10.0.0.68 eth0 10.0.0.110 1234 icmp tested on linux and MacOSX Tiger against linux 2.4, linux 2.6, winXP SP2, MacOSX Tigher 2005-08-28 poplix - poplix () papuasia org */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> //param.h defines BSD in bsd systems #include <sys/param.h> #include <libnet.h> #include <sys/types.h> #ifdef BSD #include <net/bpf.h> #endif #include <pcap.h> #include <netinet/tcp.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <limits.h> #include <errno.h> #define BALIGN 0 #define TCPDPORT 139 u_short udpport; u_int32_t ipdst,ipsrc; char intf[8]; int icmportcp; char *int_to_ip(u_int32_t ip){ u_char *tmp=(u_char *)&ip; static char ret[16]; sprintf(ret,"%d.%d.%d.%d",tmp[0] & 0xff,tmp[1] & 0xff,tmp[2] & 0xff,tmp[3] & 0xff); return ret; } u_int ip_to_int(char *ip,int *err){ int a, c=0, pos=0, tmpint; char t[4]; u_char addr[4]; for(a=0; pos<4; a++){ if(ip[a]=='.' || ip[a]==0){ t[c]=0; tmpint=strtol(t, (char **)NULL, 10); if(errno==EINVAL || (tmpint<0 || tmpint>255) )goto bad; addr[pos]=(u_char)tmpint; pos++; c=0; }else { t[c]=ip[a]; c++; } } if(pos!=4)goto bad; if(err!=NULL)*err=0; return *(u_int*)addr; bad: if(err!=NULL)*err=1; return 0; } int send_udp(libnet_t *libnet_hnd,u_short dstport){ libnet_ptag_t lnudp,lnip; u_int ip_size=LIBNET_IPV4_H + 3 +LIBNET_UDP_H; lnudp = libnet_build_udp( 1233, /* source port */ dstport, /* destination port */ LIBNET_UDP_H + 3, /* packet size */ 0, /* checksum */ (u_char*)"aaa", /* payload */ 3, /* payload size */ libnet_hnd, /* libnet handle */ 0); lnip = libnet_build_ipv4( ip_size, // length 0, // TOS 1234, // IP ID 0, // IP Frag 64, //TTL IPPROTO_UDP, // protocol 0, // checksum ipsrc, // source IP ipdst, // destination IP NULL, // payload 0, // payload size libnet_hnd, // libnet handle 0); // libnet ptag if(libnet_write(libnet_hnd)==-1){ printf("Write error: %s\n", libnet_geterror(libnet_hnd)); exit(0); } libnet_clear_packet(libnet_hnd); } int send_tcp(libnet_t *libnet_hnd){ libnet_ptag_t lntcp,lnip; u_int ip_size=LIBNET_IPV4_H + 0 +LIBNET_TCP_H; lntcp = libnet_build_tcp( 1234, // source port TCPDPORT, // destination port 0, // sequence number 0, // acknowledgement num TH_SYN, // control flags 65534, // window size 0, // checksum 0, // urgent pointer LIBNET_TCP_H, // TCP packet size NULL, // payload 0, // payload size libnet_hnd, 0); lnip = libnet_build_ipv4( ip_size, // length 0, // TOS 1234, // IP ID 0, // IP Frag 64, //TTL IPPROTO_TCP, // protocol 0, // checksum ipsrc, // source IP ipdst, // destination IP NULL, // payload 0, // payload size libnet_hnd, // libnet handle 0); // libnet ptag if(libnet_write(libnet_hnd)==-1){ printf("Write error: %s\n", libnet_geterror(libnet_hnd)); exit(0); } libnet_clear_packet(libnet_hnd); } int send_icmp(libnet_t *libnet_hnd){ libnet_ptag_t lnicmp,lnip; u_int ip_size=LIBNET_IPV4_H + 3 +8; lnicmp = libnet_build_icmpv4_echo( 8, /* type */ 0, /* code */ 0, /* checksum */ 1234, /* id */ 0, /* sequence number */ (u_char *)"aio", /* payload */ 3,//!!!! /* payload size */ libnet_hnd, /* libnet handle */ 0); lnip = libnet_build_ipv4( ip_size, // length 0, // TOS 1234, // IP ID 0, // IP Frag 64, //TTL IPPROTO_ICMP, // protocol 0, // checksum ipsrc, // source IP ipdst, // destination IP NULL, // payload 0, // payload size libnet_hnd, // libnet handle 0); // libnet ptag if(libnet_write(libnet_hnd)==-1){ printf("Write error: %s\n", libnet_geterror(libnet_hnd)); exit(0); } libnet_clear_packet(libnet_hnd); } void pcap_cb(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){ int size_link=14;//sizeof(struct ether_header); struct ip *ip; ip = (struct ip *) (BALIGN + pkt_data + size_link); *(u_short *)param=ntohs(ip->ip_id); } u_short get_ip_id(libnet_t* libnet_hnd){ int n=1; pcap_t *pcap_hnd; char p_errbuf[PCAP_ERRBUF_SIZE]; struct bpf_program filter; bpf_u_int32 mask; bpf_u_int32 net; u_short ipid; char filterstring[1024]; pcap_lookupnet(intf, &net, &mask, p_errbuf); pcap_hnd=pcap_open_live(intf, 96, 1, 0, p_errbuf); #ifdef BSD ioctl(pcap_fileno(pcap_hnd), BIOCIMMEDIATE, &n); #endif if(pcap_hnd==NULL){ printf("pcap Error: %s\n",p_errbuf); exit(0); } snprintf(filterstring, sizeof(filterstring),"ip and src host % s",int_to_ip(ipdst)); pcap_compile(pcap_hnd, &filter, filterstring, 0,mask); pcap_setfilter(pcap_hnd, &filter); if(icmportcp==0) send_icmp(libnet_hnd); else send_tcp(libnet_hnd); pcap_dispatch(pcap_hnd,1,pcap_cb,(u_char*)&ipid); pcap_close(pcap_hnd); return ipid; } main(int argc, char **argv){ libnet_t *libnet_hnd; char ln_errbuf[LIBNET_ERRBUF_SIZE]; u_short ipids[2]; if(argc != 6){ printf("usage:%s srcip intf dsthost udpport icmp/tcp\n",argv [0]); exit(0); } udpport=atoi(argv[4]); ipdst=ip_to_int(argv[3],NULL); ipsrc=ip_to_int(argv[1],NULL); strncpy(intf,argv[2],sizeof(intf)); if(!strcmp(argv[5],"icmp"))icmportcp=0; else icmportcp=1; libnet_hnd = libnet_init(LIBNET_RAW4,intf,ln_errbuf); if(libnet_hnd==NULL){ printf("libnet init failed: %s\n",ln_errbuf); exit(0); } ipids[0]=get_ip_id(libnet_hnd); printf("first ip_id=%u\n",ipids[0]); send_udp(libnet_hnd,udpport); ipids[1]=get_ip_id(libnet_hnd); printf("second ip_id=%u\n",ipids[1]); if((ipids[1]-ipids[0]) == 2)printf("PORT IS CLOSED\n"); if((ipids[1]-ipids[0]) == 1)printf("PORT IS OPEN\n"); exit(1); } _______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev
Current thread:
- udp scanning with ip_id prediction poplix (Aug 29)
- Re: udp scanning with ip_id prediction uzy (Aug 29)