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: