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)
