COMMAND

    Shaft

SYSTEMS AFFECTED

    munices

PROBLEM

    Sven Dietrich  made following  analysis of  the Shaft  distributed
    denial of service tool.  Note: this is also available at:

        http://sled.gsfc.nasa.gov/~spock/shaft_analysis.txt

    This is an analysis of  the "Shaft" distributed denial of  service
    (DDoS) tool.  Denial of service is a technique to deny access to a
    resource by overloading it, such as packet flooding in the network
    context.   Denial  of  service  tools  have  existed  for a while,
    whereas  distributed   variants  are   relatively  recent.     The
    distributed  nature   adds  the   "many  to   one"   relationship.
    Throughout  this  analysis,  most  actual  host  names  have  been
    modified or removed.

    "Shaft" belongs in the family of tools discussed earlier, such  as
    Trinoo, TFN, Stacheldraht, and TFN2K.  Like in those tools,  there
    are handler (or master) and agent programs.  The general  concepts
    of  these  tools  can  be  found  in  a Distributed Intruder Tools
    Workshop Report held  in November 1999  at the Computer  Emergency
    Response  Team  Coordination   Center  (CERT/CC)  in   Pittsburgh,
    Pennsylvania:

        http://www.cert.org/reports/dsit_workshop.pdf

    In  chronological  order,  there  are  Trinoo,  TFN, Stacheldraht,
    Shaft, and TFN2K.  In the  first two months of 2000, DDoS  attacks
    against major  Internet sites  (such as  CNN, ZDNet,  Amazon etc.)
    have brought these tools further into the limelight.  There are  a
    few papers covering DDoS to be found at:

        http://packetstorm.securify.com/distributed/
        http://staff.washington.edu/dittrich/misc/ddos/
        http://www.cert.org/advisories/CA-99-17-denial-of-service-tools.html
        http://oliver.efri.hr/~crv/security/bugs/mUNIXes/dos3.html
        http://oliver.efri.hr/~crv/security/bugs/mUNIXes/dos5.html
        http://oliver.efri.hr/~crv/security/bugs/mUNIXes/dos6.html
        http://oliver.efri.hr/~crv/security/bugs/mUNIXes/ddos.html

    Shaftnode  was  recovered,  initially  in  binary  form,  in  late
    November 1999,  then in  source form  for the  agent.  Distinctive
    features are  the ability  to switch  handler servers  and handler
    ports on the  fly, making detection  by intrusion detection  tools
    difficult  from  that  perspective,  a  "ticket" mechanism to link
    transactions, and the particular interest in packet statistics.

    The network: client(s)-->handler(s)-->agent(s)-->victim(s)
    ==========================================================
    The "Shaft"  network is  made up  of one  or more handler programs
    ("shaftmaster")  and  a  large  set  of agents ("shaftnode").  The
    attacker  uses  a  telnet  program  ("client")  to  connect to and
    communicate with the handlers.  A "Shaft" network would look  like
    this:

                         +--------+             +--------+
                         | client |             | client |
                         +--------+             +--------+
                             |                      |
              . . . --+------+---------------+------+----------------+-- . . .
                      |                      |                       |
                      |                      |                       |
                +-----------+          +-----------+           +-----------+
                |  handler  |          |  handler  |           |  handler  |
                +-----------+          +-----------+           +-----------+
                      |                      |                       |
                      |                      |                       |
        . . ---+------+-----+------------+---+--------+------------+-+-- . . .
               |            |            |            |            |
               |            |            |            |            |
           +-------+    +-------+    +-------+    +-------+    +-------+
           | agent |    | agent |    | agent |    | agent |    | agent |
           +-------+    +-------+    +-------+    +-------+    +-------+

    Network Communication
    =====================
    - Client to handler(s):  20432/tcp
    - Handler to agent(s):   18753/udp
    - Agent to handler(s):   20433/udp

    "Shaft" (in the analyzed  version, 1.72) is modeled  after Trinoo,
    in  that  communication  between  handlers  and agents is achieved
    using the  unreliable IP  protocol UDP.   Remote control  is via a
    simple telnet  connection to  the handler.  "Shaft" uses "tickets"
    for keeping track  of its individual  agents.  Both  passwords and
    ticket  numbers  have  to  match  for  the  agent  to  execute the
    request.  A simple letter-shifting (Caesar cipher) is in use.

    The  command  structure  is  divided  into  the  agent and handler
    command syntax groups.   The attacker interacts  with the  handler
    via a command line.

    Agent Command Syntax
    ====================
    Accepted by agent and replies generated back to the handler:
    * size <size>
      - Size of the flood packets; generates a "size" reply.

    * type <0|1|2|3>
      - Type  of DoS  to run:  0 UDP,  1 TCP,  2 UDP/TCP/ICMP, 3 ICMP.
        Generates a "type" reply.

    * time <length>
      - Length of DoS in seconds; generates a "time" reply.

    * own <victim>
      - Add victim to list of  hosts to perform denial of service  on;
        generates a "owning" reply.

    * end <victim>
      - Removes victim from list of hosts (see "own" above); generates
        a "done" reply.

    * stat
      - Requests packet statistics  from agent; generates a  "pktstat"
        reply.

    * alive
      - Are you alive?; generates a "alive blah" reply.

    * switch <handler> <port>
      - Switch the agent to a new handler and handler port;  generates
        a "switching" reply.

    * pktres <host>
      - Request packet results for that host at the end of the  flood;
        generates a "pktres" reply.

    Sent by agent:
    * new <password>
      - Reporting for duty

    * pktres <password> <sock> <ticket> <packets sent>
      - Packets sents to the host identified by <ticket> number

    Handler (shaftmaster) Command Syntax
    ====================================
    Little is  known about  the handler,  but this  is a  speculation,
    pieced together  from clues,  of how  its command  structure could
    look like:

    * mdos <host list>
      - Start a distributed denial  of service attack (mdos =  massive
        denial of service?)  directed at <host  list>; sends out  "own
        host" messages to all agents.

    * edos <host list>
      - End  the above  attack on  <host list>;  sends out  "end host"
        messages to all agents.

    * time <length>
      - Set the duration of  the attack; sends out "time  <length>" to
        all agents.

    * size <packetsize>
      - Set  the  packetsize  for  the  attack (8K maximum as seen  in
        source); sends out "size <packetsize>" to all agents.

    * type <UDP|TCP|ICMP|BOTH>
       - Set the type of  attack, UDP packet flooding, TCP  SYN packet
         flooding, ICMP  packet flooding,  or all  three (here  BOTH =
         ICMP amd IP protocols); sends "type <type>" to all agents.

    * +node <host list>
       - Add new agents

    * -node <host list>
       - Remove agents from pool

    * ns <host list>
      - Perform a DNS lookup on <host list>

    * lnod
      - List all agents

    * ltic
       - List all tickets (transactions?)

    * pkstat
      - Show  total  packet  statistics  for agents; sends out  "stat"
        request to all agents.

    * alive
      - Send an  "alive" to all  agents, a possible  argument to alive
        is "hi"

    * stat
      - show status?

    * switch
      - become the handler for agents; send "switch" to all agents.

    * ver
      - show version

    * exit

    After  connecting  to  the  handler  using  the telnet client, the
    attacker is  prompted with  "login:".   Too little  is known about
    the handler or its encryption method for logging in.  A  cleartext
    connection to the handler port is obviously a weakness.

    As  with  previous  DDoS  tools,  the  methods used to install the
    handler/agent will  be the  same as  installing any  program on  a
    compromised  Unix  system,  with  all  the  standard  options  for
    concealing  the   programs  and   files  (e.g.,   use  of   hidden
    directories, "root  kits", kernel  modules, etc.)   The reader  is
    referred  to  Dittrich's  Trinoo  analysis  for  a  description of
    possible installation methods of this type of tool.

    Precautions have  been taken  to hide  the default  handler in the
    binary code.  In the analyzed code, the default handler is defined
    as follows:

        #define MASTER          "23:/33/75/28"

    which        would        translate        into       129.22.64.17
    (electrochem1.echem.cwru.edu)  using   the  same   simple   cipher
    mentioned above.  Port numbers are munged before actual use, e.g.

        #define MASTER_PORT     20483

    is really port 20433.

    All these techniques intend to hide the critical information  from
    prying eyes performing forensics on the code.  The program  itself
    tries to hide  itself as a  legitimate Unix process  (httpd in the
    default  configuration).   Looking  at  strings  in  the shaftnode
    application reveals the following:

        > strings -n 3 shaftnode
        pktres
        switch
        alive
        stat
        end
        own
        time
        type
        size
        httpd
        23:/33/75/28
        Unable to fork. (do it manually)
        shift
        new %s
        size %s %s %s %s
        type %s %s %s %s
        time %s %s %s %s
        owning %s %s %s %s
        switched %s %s %s
        done %s %s %s %s
        pktstat %s %s %s %lu
        alive %s %s %s blah
        %d.%d.%d.%d
        Error sending tcp packet from %s:%i to %lu:%i
        pktres %s %i %i %lu

    Upon launch, the "Shaft"  agent (the "shaftnode") reports  back to
    its  default  handler  (its  "shaftmaster")  by  sending  a   "new
    <upshifted  password>"  command.   For  the  default  password  of
    "shift"  found  in  the  analyzed  code,  this  would  be "tijgu".
    Therefore  a  new  agent  would  send  out  "new  tijgu",  and all
    subsequent messages would carry that  password in it. Only in  one
    case  does  the  agent  shift  in  the  opposite direction for one
    particular  command,  e.g.  "pktres  rghes".  It is unclear at the
    moment whether this is intentional or not.

    Incoming commands arrive in the format:

        command <upshifted password> <command arg> <socket> <ticket> <optional args>

    For most  commands, the  password and  socket/ticket need  to have
    the right magic in  order to generate a  reply and the command  to
    be executed.

    Message flow diagram between handler H and agent A:

        Initial phase:    A -> H: "new", f(password)
         Running loop:    H -> A: cmd, f(password), [args], Na, Nb
                          A -> H: cmdrep, f(password), Na, Nb, [args]

  	- f(X) is the Caesar cipher function on X
  	- Na, Nb are numbers (tickets, socket numbers)
  	- cmd, cmdrep are commands and command acknowledgments
  	- args are command arguments

    The flooding occurs  in bursts of  100 packets per  host, with the
    source  port  and  source  address  randomized.   This  number  is
    hard-coded, but it is believed that more flexibility can be added.
    Whereas  the  source  port  spoofing  only  works  if the agent is
    running  as  a  root  privileged  process,  the  author  has added
    provisions for  packet flooding  using the  UDP protocol  and with
    the correct source address in  the case the process is  running as
    a simple user process.  It is noteworthy that the random  function
    is not properly seeded, which may lead to predictable source  port
    sequences and source host IP sequences.

        Source port = (rand() % (65535-1024)+1024)   where % is the
                                                     mathematical 'mod' operator

    This will generate source ports greater than 1024 at all times.

        Source IP =  rand()%255.rand()%255.rand()%255.rand()%255

    The source IP numbers can (and will) contain a zero in the leading
    octet.  Additionally, the sequence  number for all TCP packets  is
    fixed, namely 0x28374839, which helps with respect to detection at
    the network  level.   The ACK  and URGENT  flags are randomly set,
    except  on  some  platforms.   Destination  ports  for TCP and UDP
    packet floods are randomized.

    The client  must choose  the duration  ("time"), size  of packets,
    and type  of packet  flooding directed  at the  victim hosts. Each
    set  of  hosts  has  its  own  duration, which gets divided evenly
    across all hosts. This is unlike TFN [2] which forks an individual
    process for each victim host. For the type, the client can  select
    UDP, TCP  SYN, ICMP  packet flooding,  or the  combination of  all
    three.  Even though there is potential of having a different  type
    and packet size for each set of victim hosts, this feature is  not
    exploited in this version.

    The  author  of  "Shaft"  seems  to  have a particular interest in
    statistics,  namely  packet  generation  rates  of  its individual
    agents.  The  statistics on packet  generation rates are  possibly
    used to  determine the  "yield" of  the DDoS  network as  a whole.
    This would allow the attacker  to stop adding hosts to  the attack
    network  when  it  reached  the  necessary  size  to overwhelm the
    victim  network,  and  to  know  when  it is necessary to add more
    agents to compensate  for loss of  agents due to  attrition during
    an  attack  (as  the  agent  systems  are  identified  and   taken
    off-line).

    Currently, the ability to switch host IP and port for the  handler
    exists, but the listening port for the agent remains the same.  It
    is foreseeable that this will change in the future.

    A sample attack
    ===============
    In this section we will look  at a practical example of an  attack
    carried out with the "Shaft" distributed denial of service  attack
    tool, as seen from the attacking network perspective.

    The shaftnode agent when in use, as seen by "lsof" [10]:

        # lsof -c shaftnode
        COMMAND    PID    USER   FD   TYPE       DEVICE    SIZE      NODE NAME
        shaftnode 13489   root  cwd   VDIR        0,0       400        2  /tmp
        shaftnode 13489   root  txt   VREG        0,0     19492       10  /tmp (swap)
        shaftnode 13489   root  txt   VREG       32,0    662764   182321  /usr/lib/libc.so.1
        shaftnode 13489   root  txt   VREG       32,0     17480   210757  /usr/platform/sun4u/lib/libc_psr.so.1
        shaftnode 13489   root  txt   VREG       32,0    566700   182335  /usr/lib/libnsl.so.1
        shaftnode 13489   root  txt   VREG       32,0     39932   182348  /usr/lib/libw.so.1
        shaftnode 13489   root  txt   VREG       32,0     15720   182334  /usr/lib/libmp.so.1
        shaftnode 13489   root  txt   VREG       32,0     15720   182327  /usr/lib/libintl.so.1
        shaftnode 13489   root  txt   VREG       32,0     68780   182342  /usr/lib/libsocket.so.1
        shaftnode 13489   root  txt   VREG       32,0      2564   182324  /usr/lib/libdl.so.1
        shaftnode 13489   root  txt   VREG       32,0    137160   182315  /usr/lib/ld.so.1
        shaftnode 13489   root   0u   inet 0x507dc770     0t116      TCP  hostname:ftp->electrochem1.echem.cwru.edu:53982 (CLOSE_WAIT)
        shaftnode 13489   root   1u   inet 0x507dc770     0t116      TCP  hostname:ftp->electrochem1.echem.cwru.edu:53982 (CLOSE_WAIT)
        shaftnode 13489   root   2u   inet 0x507dc770     0t116      TCP  hostname:ftp->electrochem1.echem.cwru.edu:53982 (CLOSE_WAIT)
        shaftnode 13489   root   3u   inet 0x5032c7d8       0t0      UDP  *:18753 (Idle)

    As one can see,  the agent is waiting  to receive commands on  its
    default UDP  port number  18753. The  TCP connection  back to  the
    handler remains unexplained to date.

    Packet flows:

        Date      Time    Protocol   Source IP/Port  Flow  Destination IP/Port

        Sun 11/28 21:39:22    tcp    129.22.64.17.53982 <->    x.x.x.x.21
        Sun 11/28 21:39:56    udp    x.x.x.x.33198  ->    129.22.64.17.20433
        Sun 11/28 21:45:20    udp    129.22.64.17.1765   ->    x.x.x.x.18753
        Sun 11/28 21:45:20    udp    x.x.x.x.33199  ->    129.22.64.17.20433
        Sun 11/28 21:45:59    udp    129.22.64.17.1866   ->    x.x.x.x.18753
        Sun 11/28 21:45:59    udp    x.x.x.x.33200  ->    129.22.64.17.20433
        Sun 11/28 21:45:59    udp    129.22.64.17.1968   ->    x.x.x.x.18753
        Sun 11/28 21:45:59    udp    129.22.64.17.1046   ->    x.x.x.x.18753
        Sun 11/28 21:45:59    udp    129.22.64.17.1147   ->    x.x.x.x.18753
        Sun 11/28 21:45:59    udp    129.22.64.17.1248   ->    x.x.x.x.18753
        Sun 11/28 21:45:59    udp    129.22.64.17.1451   ->    x.x.x.x.18753
        Sun 11/28 21:46:00    udp    x.x.x.x.33201  ->    129.22.64.17.20433
        Sun 11/28 21:46:00    udp    x.x.x.x.33202  ->    129.22.64.17.20433
        Sun 11/28 21:46:01    udp    x.x.x.x.33203  ->    129.22.64.17.20433
        Sun 11/28 21:48:37    udp    129.22.64.17.1037   ->    x.x.x.x.18753
        Sun 11/28 21:48:37    udp    129.22.64.17.1239   ->    x.x.x.x.18753
        Sun 11/28 21:48:37    udp    129.22.64.17.1340   ->    x.x.x.x.18753
        Sun 11/28 21:48:37    udp    129.22.64.17.1442   ->    x.x.x.x.18753
        Sun 11/28 21:48:38    udp    x.x.x.x.33204  ->    129.22.64.17.20433
        Sun 11/28 21:48:38    udp    x.x.x.x.33205  ->    129.22.64.17.20433
        Sun 11/28 21:48:38    udp    x.x.x.x.33206  ->    129.22.64.17.20433
        Sun 11/28 21:48:56    udp    129.22.64.17.1644   ->    x.x.x.x.18753
        Sun 11/28 21:48:56    udp    x.x.x.x.33207  ->    129.22.64.17.20433
        Sun 11/28 21:49:59    udp    x.x.x.x.33208  ->    129.22.64.17.20433
        Sun 11/28 21:50:00    udp    x.x.x.x.33209  ->    129.22.64.17.20433
        Sun 11/28 21:50:14    udp    129.22.64.17.1747   ->    x.x.x.x.18753
        Sun 11/28 21:50:14    udp    x.x.x.x.33210  ->    129.22.64.17.20433

    There is quite  some activity between  the handler and  the agent,
    as  they  go  through  the  command  request  and  acknowledgement
    phases.  There was also what appeared to be testing of the  impact
    on the local network itself  with ICMP packet flooding, for  which
    we omit the data here due to size limitations.

    Let us look at the individual phases from a later attack.

    Setup and configuration phase:

        date        time      src              dest         dest-port command

        4 Dec 1999  18:06:40  129.22.64.17     x.x.x.x       18753    alive tijgu hi 5 8170
        4 Dec 1999  18:09:14  129.22.64.17     x.x.x.x       18753    time tijgu 700 5 6437
        4 Dec 1999  18:09:14  x.x.x.x      129.22.64.17      20433    time tijgu 5 6437 700
        4 Dec 1999  18:09:16  129.22.64.17     x.x.x.x       18753    size tijgu 4096 5 8717
        4 Dec 1999  18:09:16  x.x.x.x      129.22.64.17      20433    size tijgu 5 8717 4096
        4 Dec 1999  18:09:23  129.22.64.17     x.x.x.x       18753    type tijgu 2 5 9003

    The handler issues an "alive" command, and says "hi" to its agent,
    assigning a socket number of "5"  and a ticket number of 8170.  We
    will see that  this "socket number"  will persist throughout  this
    attack.  A time  period of 700 seconds  is assigned to the  agent,
    which is acknowledged.  A packet size of 4096 bytes is  specified,
    which is  again confirmed.   The last  line indicates  the type of
    attack, in  this case  "the works",  i.e.   UDP, TCP  SYN and ICMP
    packet flooding combined.  Failure to specify the type would  make
    the agent default to UDP packet flooding.

    Now  the  list  of  hosts  to  attack  and  which  ones  they want
    statistics from on completion:

        date        time      src              dest         dest-port command

        4 Dec 1999  18:09:24  129.22.64.17     x.x.x.x       18753    own tijgu 207.229.143.6 5 5256
        4 Dec 1999  18:09:24  x.x.x.x      129.22.64.17      20433    owning tijgu 5 5256 207.229.143.6
        4 Dec 1999  18:09:24  129.22.64.17     x.x.x.x       18753    pktres tijgu 207.229.143.6 5 1993
        4 Dec 1999  18:09:24  129.22.64.17     x.x.x.x       18753    own tijgu 24.7.231.128 5 78
        4 Dec 1999  18:09:24  129.22.64.17     x.x.x.x       18753    pktres tijgu 24.218.58.101 5 8845
        4 Dec 1999  18:09:24  129.22.64.17     x.x.x.x       18753    own tijgu 18.85.13.107 5 6247
        4 Dec 1999  18:09:25  129.22.64.17     x.x.x.x       18753    own tijgu 24.218.52.44 5 4190
        4 Dec 1999  18:09:25  129.22.64.17     x.x.x.x       18753    own tijgu 207.175.72.15 5 2376
        4 Dec 1999  18:09:25  x.x.x.x      129.22.64.17      20433    owning tijgu 5 78 24.7.231.128
        4 Dec 1999  18:09:26  x.x.x.x      129.22.64.17      20433    owning tijgu 5 6247 18.85.13.107
        4 Dec 1999  18:09:27  x.x.x.x      129.22.64.17      20433    owning tijgu 5 4190 24.218.52.44
        4 Dec 1999  18:09:28  x.x.x.x      129.22.64.17      20433    owning tijgu 5 2376 207.175.72.15
        4 Dec 1999  18:21:04  x.x.x.x      129.22.64.17      20433    pktres rghes 5 1993 51600
        4 Dec 1999  18:21:04  x.x.x.x      129.22.64.17      20433    pktres rghes 0 0 51400
        4 Dec 1999  18:21:07  x.x.x.x      129.22.64.17      20433    pktres rghes 0 0 51500
        4 Dec 1999  18:21:07  x.x.x.x      129.22.64.17      20433    pktres rghes 0 0 51400
        4 Dec 1999  18:21:07  x.x.x.x      129.22.64.17      20433    pktres rghes 0 0 51400

    Now that all other parameters are set, the handler issues  several
    "own"  commands,  in  effect  specifying  the victim hosts.  Those
    commands are  acknowledged by  the agent  with an  "owning" reply.
    The flooding occurs as soon  as the first victim host  gets added.
    The handler also  requests packet statistics  from the agents  for
    certain victim hosts (e.g.  "pktres tijgu 207.229.143.6 5  1993").
    Note  that  the  reply  comes  back  with the same identifiers ("5
    1993") at the end of the 700 second packet flood, indicating  that
    51600 sets  of packets  were sent.   One should  realize that,  if
    successful, this means 51600 x 3 packets due to the  configuration
    of all three (UDP, TCP, and ICMP) types of packets.  In turn, this
    results in roughly 220 4096  byte packets per second per  host, or
    about 900  kilobytes per  second per  victim host  from this agent
    alone,  about  4.5  megabytes  per  second  total  for this little
    exercise.

    Note  the  reverse  shift  ("shift"  becomes  "rghes", rather than
    "tijgu") for the password on the packet statistics.

SOLUTION

    Detection at the network level
    ==============================
    Scanning the network for open port 20432 will reveal the  presence
    of a handler on  your LAN.  For  detecting idle agents, one  could
    write  a  program  similar  to  George  Weaver's  trinoo detector.
    Sending  out  "alive"  messages  with  the default password to all
    nodes on  a network  on the  default UDP  port 18753 will generate
    traffic  back  to  the  detector,  making  the  agent  believe the
    detector is a handler.

    This  program  does  not  provide  for  code  updates (like TFN or
    Stacheldraht).  This may  imply "rcp" or "ftp"  connections during
    the initial  intrusion phase.   The program  uses UDP  traffic for
    its communication between the handlers and the agents. Considering
    that the traffic is not encrypted, it can easily be detected based
    on  certain  keywords.  Performing  an  "ngrep"  for  the keywords
    mentioned in the syntax sections, will locate the control traffic,
    and looking for  TCP packets with  sequence numbers of  0x28374839
    may locate  the TCP  SYN packet  flood traffic.   Source ports are
    always above 1024, and source IP numbers can include zeroes in the
    leading octet.   Strings in this  control traffic can  be detected
    with  the  "ngrep"  program  using  the  same  technique  shown in
    previous analyses. For example,

        # ngrep -i -x "alive tijgu" udp

        # ngrep -i -x "pktres|pktstat" udp

    will locate the control traffic between the handler and the agent,
    independently  of  the  port  number  used.   There  are  also two
    excellent  scanners  for  detecting  DDoS  agents  on the network:
    Dittrich's "dds" and Brumley's "rid":

        http://theorygroup.com/Software/RID
        http://staff.washington.edu/dittrich/dds

    "dds" was written  to provide a  more portable and  less dependant
    means of scanning for various DDoS tools. (Many people encountered
    problems with Perl  and the Net::RawIP  library on their  systems,
    which prevented  them from  using the  scripts provided).   Due to
    time contraints during coding, "dds" does not have the flexibility
    necessary to specify arbitrary protocols, ports, and payloads.   A
    modified version of "dds",  geared towards detecting only  "Shaft"
    agents, is included in the below.

    A better means of detecting  "Shaft" handlers and agents would  be
    to  use  a  program  like  "rid",  which  uses  a  more   flexible
    configuration  file  mechanism  to  define  ports,  protocols, and
    payloads.  A sample configuration for "rid" to detect the  "Shaft"
    control traffic as described:

start shaft
      send udp dport=18753 data="alive tijgu hi 5 1918"
      recv udp sport=20433 data="alive" nmatch=1
end shaft

    To protect against the effects of the multiple types of denial  of
    service, we  suggest that  you review  the other  papers and other
    methods of dealing with DDoS attacks being discussed and promoted.
    For example,  rate-limiting is  considered effective  against ICMP
    packet  flooding  attacks,  while  anti-spoof  filters  and egress
    filters at  the border  routers can  limit the  problems caused by
    attacking agents faking source addresses.

    To date,  no source  for the  "Shaft" handler  ("shaftmaster") has
    been obtained of analyzed.

    dds ("Shaft" only variant):

    /*
     * dds $Revision: 1.6s $ - a distributed DoS tool scanner - Shaft only
     *
     * Based on the gag scanner, written by David Dittrich, University
     * of Washington, Marcus Ranum, Network Flight Recorder, with
     * code contributed by others, and based on an idea stolen from
     * George Weaver, Pennsylvania State University.
     *
     * Dave Dittrich <dittrich@cac.washington.edu>
     * Marcus Ranum <mjr@nfr.net>
     * George Weaver <gmw@psu.edu>
     * David Brumley <dbrumley@rtfm.stanford.edu>
     */

    /* Shaft only version, modified to that effect by
     * Sven Dietrich <spock@sled.gsfc.nasa.gov>
     */

    #if YOU_HAVE_NOT_READ_THIS_YET

    This software should only be used in compliance with all applicable laws and
    the policies and preferences of the owners of any networks, systems, or hosts
    scanned with the software

    The developers and licensors of the software provide the software on an "as
    is" basis, excluding all express or implied warranties, and will not be liable
    for any damages arising out of or relating to use of the software.

    THIS SOFTWARE IS MADE AVAILABLE "AS IS", AND THE UNIVERSITY OF WASHINGTON
    DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
    INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
    WASHINGTON BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    ACTION OF CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING
    OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

    #endif

    #define VERSION "$Revision: 1.6s $"

    #include <stdlib.h>
    #include <ctype.h>
    #include <signal.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <netinet/ip.h>
    #include <netinet/udp.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <netinet/ip_icmp.h>

    #define BS 1024
    #define __FAVOR_BSD

    /* The two arrays below are for address range calculations.  They
       should have been automatically generated, but
       1) I am lazy.
       2) There are a few special cases in them.

       I will not scan more than a /16.  When we do scan a CIDR block, we
       assume that it actually is a CIDR block, and do not scan the
       network or broadcast address.

       */

    static unsigned long MaskBits[] = {
      0x00000000,                   /* /0 */
      0x00000000,                   /* /1 */
      0x00000000,                   /* /2 */
      0x00000000,                   /* /3 */
      0x00000000,                   /* /4 */
      0x00000000,                   /* /5 */
      0x00000000,                   /* /6 */
      0x00000000,                   /* /7 */
      0x00000000,                   /* /8 */
      0x00000000,                   /* /9 */
      0x00000000,                   /* /10 */
      0x00000000,                   /* /11 */
      0x00000000,                   /* /12 */
      0x00000000,                   /* /13 */
      0x00000000,                   /* /14 */
      0x00000000,                   /* /15 */
      0xffff0000,                   /* /16, Class B */
      0xffff8000,                   /* /17, 128 * Class C */
      0xffffc000,                   /* /18, 64 * Class C */
      0xffffe000,                   /* /19, 32 * Class C */
      0xfffff000,                   /* /20, 16 * Class C */
      0xfffff800,                   /* /21, 8 * Class C */
      0xfffffc00,                   /* /22, 4 * Class C */
      0xfffffe00,                   /* /23, 2* Class C */
      0xffffff00,                   /* /24, Class C */
      0xffffff80,                   /* /25, 128 hosts */
      0xffffffc0,                   /* /26, 64 hosts */
      0xffffffe0,                   /* /27, 32 hosts */
      0xfffffff0,                   /* /28, 16 hosts */
      0xfffffff8,                   /* /29, 8 hosts */
      0xfffffffc,                   /* /30, 4 hosts (PPP link) */
      0xfffffffe,                   /* /31, invalid */
      0xffffffff,                   /* /32, host */
    };

    static int NumHosts[] = {
      0, 0, 0, 0,
      0, 0, 0, 0,
      0, 0, 0, 0,
      0, 0, 0, 0,                   /* don't scan more than a /16 */
      65534,                        /* These are all -2 so that we don't
                                       scan the broadcast addr or the
                                       network addr */
      32766,
      16382,
      8190,
      4094,
      2046,
      1022,
      510,
      254,
      126,
      62,
      30,
      14,
      6,
      2,
      0,
      1,
    };

    extern  char            *optarg;

    struct udppkt_t {
            struct ip       ipi;
            struct udphdr   udpi;
            char            buffer[BS];
    } udppkt;

    static void             listener();
    static int              usage();

    static int              vflg = 0;       /* verbosity */
    static int              dflg = 0;       /* debugging */

    /* shaft variables */
    static short            shaft_dstport = 18753;  /* handler listen port */
    static short            shaft_rctport = 20433;  /* agent listen port */
    char                    shaft_scmd[] = "alive";
    char                    shaft_spass[] = "tijgu";
    char                    shaft_echostr[] = "alive";

    int
    main(int argc, char **argv)
    {
            int             pid, host;
            char            target[128];
            unsigned long   target_host;
            struct in_addr  target_ip;
            int             mask;
            char *          mask_ptr;
            int             result;
            int             usock;
            char            buf[BS];
            struct sockaddr_in
                            usa;
            int             i;
            char            *jnk1;
            char            *jnk2;
            int             sleepytime = 500;
            int             bigsleep = 30;
            int             num_hosts;
            char            scmd[BS], spass[BS], sbuf[BS];

            while((i = getopt(argc,argv,"ds:S:v")) != -1) {
                    switch(i) {
                    case 'd':
                            dflg++;
                            break;
                    case 's':
                            sleepytime = atoi(optarg);
                            if(sleepytime <= 0) {
                                    fprintf(stderr,"WARNING: zero interping sleep time will probably overflow your sy
    stem's transmit buffers and yield poor results\n");
                                    sleepytime = 1;
                            }
                            break;
                    case 'S':
                            bigsleep = atoi(optarg);
                            if(bigsleep <= 0) {
                                    fprintf(stderr,"WARNING: negative sleep value - staying with default of %d\n", bi
    gsleep);
                            }
                            break;
                    case 'v':
                            vflg++;
                            break;
                    default:
                            exit(usage());
                    }
            }

            if(optind >= argc || argc - optind > 1)
                    exit(usage());

            mask_ptr = strchr(argv[optind], '/');

            /* if a CIDR block is passed in */
            if (mask_ptr) {
              *mask_ptr = '\0';
              mask_ptr ++;

              sscanf(mask_ptr, "%d", &mask);

            } else {
              printf("No mask passed, assuming host scan (/32)\n");
              mask = 32;
            }


            result = inet_aton(argv[optind], &target_ip);

            if (result == 0) {
              fprintf(stderr, "%s: Bad IP address: %s\n", argv[0],
                      argv[optind]);
              exit(-1);
            }

            if (mask < 16) {
              fprintf(stderr, "Bad Network Admin!  Bad!  Do not scan more than a /16 at once!\n");
              exit(-1);
            }

            num_hosts = NumHosts[mask];

            if (num_hosts == 0) {
              fprintf(stderr, "Cannot scan a /%d.  Exiting...\n", mask);
              exit(-1);
            }

            if(vflg) {
              printf("Mask: %d\n", mask);
              printf("Target: %s\n", inet_ntoa(target_ip));
              printf("dds %s - scanning...\n\n", VERSION);
            }

            sprintf(sbuf,"%s %s hi 5 1918",shaft_scmd,shaft_spass);

            target_host = ntohl(target_ip.s_addr);
            target_host &= MaskBits[mask];

            target_ip.s_addr = htonl(target_host);

            if((pid = fork()) < 0) {
                    perror("cannot fork");
                    exit(1);
            }

            /* child side listens for return packets */
            if (pid == 0)
                    listener();

            sleep(1);

            /* main sweep loop - COULD be expanded to whole Internet but... */
            /* but that would be _very_ bad.... */
            while (num_hosts) {
              if (mask != 32) {
                target_host ++;
              }
              target_ip.s_addr = htonl(target_host);

              num_hosts--;

              /* we really need to skip the network and broadcast addresses */
              if ((target_host & 0xff) == 0 || (target_host & 0xff) == 0xff)  {
                if(vflg)
                  printf("Skipping special address %s\n", inet_ntoa(target_ip));
                continue;
              }

              if(vflg)
                printf("Probing address %s\n", inet_ntoa(target_ip));

                            /* shaft check */
                            bzero((char *) &usa, sizeof(usa));
                            usa.sin_family = AF_INET;
                            usa.sin_addr.s_addr = target_ip.s_addr;
                            usa.sin_port = htons(shaft_dstport);

                            if (dflg)
                                    fprintf(stderr,"Sending UDP to: %s\n",
                                            inet_ntoa(usa.sin_addr));
                            if ((usock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
                                    perror("cannot open UDP socket");
                                    exit(1);
                            }

                            i = sendto(usock,sbuf,strlen(sbuf), 0,
                                    (struct sockaddr *)&usa,
                                    sizeof(usa));

                            if (i < 0) {
                                    char ebuf[BS];
                                    sprintf(ebuf,"sendto: udp %s",
                                            inet_ntoa(usa.sin_addr));
                                    perror(ebuf);
                                    break;
                            }
                            close(usock);

                            usleep(sleepytime);
                    }


            /* wait for any late responses */
            if (dflg)
                    fprintf(stderr,"Waiting %d seconds for late responses.\n",
                            bigsleep);
            sleep(bigsleep);

            /* shut listener. if this fails the listener exits on its own */
            (void)kill(pid, SIGHUP);
            exit(0);
    }


    static  void    listener()
    {
            int             usock;
            int             i, len;
            fd_set          fdset;
            char            buf[BS];
            char            rcmd[BS], filler[BS], rpass[BS];
            struct timeval  timi;
            struct udppkt_t
                            upacket;
            struct sockaddr_in
                            sa, from;

            /* child becomes a listener process */

            if ((usock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
                    perror("cannot open raw UDP listen socket");
                    exit(1);
            }

            bzero((char *) &sa, sizeof(sa));
            sa.sin_family = AF_INET;
            sa.sin_addr.s_addr = INADDR_ANY;
            sa.sin_port = htons(shaft_rctport);

            if (bind(usock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
                     perror("cannot bind to socket");
                    exit(-1);
            }

            while (1) {
                    /* if parent has exitted, die */
                    if(getppid() == 1)
                            exit(0);

                    FD_ZERO(&fdset);
                    FD_SET(usock, &fdset);
                    timi.tv_sec = 1;
                    timi.tv_usec = 0;
                    select(FD_SETSIZE, &fdset, NULL, NULL, &timi);
                    usleep(100);
                    if (FD_ISSET (usock, &fdset)) {
                            /* read data from UDP listen socket */
                            memset((void *) &upacket, 0, sizeof(struct udppkt_t));
                            len = sizeof(from);
    #if 1
                            if ((i = recvfrom(usock, buf, BS, 0,
                                    (struct sockaddr *) &from, &len)) < 0) {
                                    perror("recvfrom");
                                    continue;
                            }
    #else
                            i = read (usock, (char *) buf, BS) -
                                    (sizeof (struct ip) + sizeof (struct udphdr));
    #endif
                            sa.sin_addr.s_addr = upacket.ipi.ip_src.s_addr;
                            if(dflg)
                                    fprintf(stderr,
                                            "Listener got a UDP packet on port %s\n",
                                            shaft_rctport);

                            /* shaft check */
                            if (strstr(buf,shaft_echostr)) {
                                    printf("Received '%s' from %s",
                                            shaft_echostr,
                                            inet_ntoa(from.sin_addr));
                                    printf(" - probable shaft agent\n");
                            }
                            else {
                                    printf("Unexpected UDP packet received on port %d from %s\n",
                                            shaft_rctport, inet_ntoa(from.sin_addr));
                            }
                    }
            }
    }


    static int
    usage()
    {
            fprintf(stderr,"usage: dds [options] <target>\n");
            fprintf(stderr,"target is CIDR block to scan in form:\n");
            fprintf(stderr,"\tA.B.C.D/mask\n");
            fprintf(stderr,"Options:\n");
            fprintf(stderr,"\t[-v] turns on verbosity\n");
            fprintf(stderr,"\t[-d] turns on debugging\n");
            fprintf(stderr,"\t[-s] interpacket sleep in microseconds\n");
            fprintf(stderr,"\t[-S] delay for late packets\n");

            return(1);
    }