D/DoS Testing Network Applications

April 10th, 2009 by kowsik

If you Google for “denial of service tools” or look in the “VoIP flooding tools“, you’ll find that all of these tools have a very similar pattern. Any engineer worth a dime hates writing the same code over and over again. So we are going to refactor these tools to abstract away the common boiler-plate code and end up with something that’s reusable, yet more powerful.

We announced mudos on pcapr a while back and I figured I’ll spend some time explaining what it is and how this can make your DoS testing super simple. The mudos executable contains a subset of the functionality that we offer on the Mu-4000, but is incredibly effective in DoS testing. Like any tool that generates packets, standard disclaimers about not abusing it to cause collateral damages apply.

Taxonomy

DoS, as exemplified in mudos, is inherently stateless. It’s a whole bunch of packets thrown against a server or against the network in order to flood the server/network into thinking these are legitimate connections. The net result is that legitimate requests go unanswered or systems start crashing left and right. Broadly speaking there are a few different kinds of DoS situations:

Unsolicited notifications
  • MGCP Notification
  • ISAKMP Notification
  • RTP flood
Lack of rate limiting responses
  • ICMP ping’s
  • Broadcast ping’s
  • MSSQL echo packets (slammer used this one)
Incomplete session setup
  • SIP invite/register
  • TCP SYN floods
  • SCTP init
  • DHCP discover
1-N amplification
  • Multicast floods (MDNS)
  • Broadcast floods (ARP, ICMP)

If you break down these to synthesize a software abstraction, you’ll realize that DoS generation involves 3 key components:

  • The transport used to deliver the packet (Ethernet, IP4/6, UDP, TCP, etc)
  • The traffic pattern (1 minute ramp up from 10,000 to 20,000 pps)
  • The payload carried by these transport

If we can configure these three components with a generalized packet generator, we can then DoS pretty much anything. mudos, specifically uses a JSON configuration file to model these three abstractions.

Transport

We intentionally separate the L2/L3/L4 header from the payload that it carries since it gives us a degree of freedom. In our terminology, the transports are objects like Ethernet, IPv4, IPv6, UDP and TCP (the latter two defined independently of IPv4/6). Given this abstraction, it’s pretty easy now to generate source/destination IP addresses in one of the following ways:

  • Static addresses
  • Auto configured from the interface used for testing
  • A range of addresses (subnets)

In addition, we can also define the source address to be the same as the destination address (for generating land attacks). Finally, every possible field within these headers can either be fixed or randomized independently. We’ll talk more about randomization further down. Here’s a snippet of the TCP SYN-flood in JSON:

"tcp": {
"flags": "rst",
"source": {
"randomize": true,
"value": 31337
},
"destination": {
"randomize": false,
"value": 80
},
"seq": {
"randomize": true
},
....

Pattern

This one’s pretty straight forward. If you look at most DoS tools, they all have a while loop around the packet generation (which is typically sendto on a raw socket) and control rates using gettimeofday. In mudos, we use a similar mechanism, except the pattern is made of multiple intervals. Each interval has a start and end packets/sec along with the duration. This allows us to easily model ramp up/down, warm up, cool down and a host of other stair-master patterns, independently of the transport and the payload. Here’s an example pattern in JSON which is a ramp up to 10,000 packets/second for 60 seconds followed by a ramp down over 60 seconds.

"intervals": [
{ "duration": 60, "start_rate": 1, "steps": 0, "end_rate": 10000, "repeat": 1},
{ "duration": 60, "start_rate": 10000, "steps": 0, "end_rate": 1, "repeat": 1}
]

Payload

The payload is merely a bunch of bytes (specified either in hex or as ascii) that the underlying transport carries. This means you only need to model SIP INVITE once and can switch between UDPv4 or UDPv6 by just changing the configuration file. No need to write a whole another tool just to test DoS over IPv6. Here’s an example payload in JSON:

"payload": {
"type": "ascii",
"data": [
"INVITE sip:bob@192.168.1.2 SIP/2.0\r\n",
"Via: SIP/2.0/UDP 192.168.1.254:5060;branch=z9hG4bKOvWWTphl;rport\r\n",
"To: \"Bob\" <sip:bob@192.168.1.2>\r\n",
"From: \"Alice\" <sip:alice@192.168.1.1>;tag=AAmhnpRM\r\n",
"Call-ID: esUcrsXK@192.168.1.1\r\n",
"CSeq: 1 INVITE\r\n",
"Contact: <sip:alice@192.168.1.1>\r\n",
"Max-Forwards: 70\r\n",
"Content-Type: application/sdp\r\n",
"Content-Length: 0\r\n",
"\r\n"
]
}

Update regions

This is by far the most important part of DoS generation that gets us the biggest bang for the buck even under really low packet rates. If you look at the SIP INVITE message there are a number of regions within the payload that either need to be randomized or need to be tied to the L2/L3/L4 header values. In other words if we are generating random IP addresses and/or ports for each packet, then the payload needs to reflect that to make the server think it’s unique and valid. Obviously, the various L2/L3/L4 checksums (if any) need to be recomputed. But this can be done incrementally. So here’s the JSON again with the highlighted regions:

"payload": {
"type": "ascii",
"data": [
"INVITE sip:bob@192.168.1.2 SIP/2.0\r\n",
"Via: SIP/2.0/UDP 192.168.1.254:5060;branch=z9hG4bKOvWWTphl;rport\r\n",
"To: \"Bob\" <sip:bob@192.168.1.2>\r\n",
"From: \"Alice\" <sip:alice@192.168.1.1>;tag=AAmhnpRM\r\n",
"Call-ID: esUcrsXK@192.168.1.1\r\n",
"CSeq: 1 INVITE\r\n",
"Contact: <sip:alice@192.168.1.1>\r\n",
"Max-Forwards: 70\r\n",
"Content-Type: application/sdp\r\n",
"Content-Length: 0\r\n",
"\r\n"
]
}

So mudos allows you to specify fixed length update regions that are automatically computed for each generated packet. These regions can be references to dynamically generated L2/L3 values or strings, randomized using a specific character set. If you mouse over the highlights above, you’ll see what those regions are. All in all mudos defines 35 unique regions that can be used to update the payload before each packet it sent.

Here’s the JSON snippet that describes the update regions:

"regions": [
{ "name": "sip.Via.branch", "type": "STRING_ALPHA", "offset": 91, "length": 8 },
{ "name": "sip.tag", "type": "STRING_ALPHA", "offset": 182, "length": 8 },
{ "name": "sip.Call-ID", "type": "STRING_ALNUM", "offset": 201, "length": 8 },
{ "name": "sip.CSeq.seq", "type": "STRING_DIGIT", "offset": 232, "length": 1 },
...
]

Execution

The pcapr user interface for generating the JSON configuration file for mudos makes it incredibly easy to convert any one of the ~50,000 packets (as I write this blog) into DoS generators. Once you generate and save the JSON file, running mudos is pretty easy:

mudos -i eth0 -f dos.json

One thing to note is that mudos uses fixed-length packets during the entire duration of DoS. This allows us to preallocate the packet buffer and replace values in-place without malloc’ing a packet for each send. For each packet generated, mudos first computes the appropriate L2/L3/L4 randomized values (if they need to be randomized) and then updates the various regions (if specified). Finally it also does incremental checksum computation for IP, UDP and TCP headers.

Results

Here’s an example of a SIP OPTIONS DoS at a measly 5,000 packets/second with update regions. Obviously the server will go unnamed, but the results are super interesting. The candle sticks indicate the response time values for a normal SIP OPTIONS request and as you can see, in the second iteration after the full ramp up/down the server is officially dead.

So next time you think of DoS testing, try mudos. You’ll save yourself a lot of time and won’t have to write another loop like this again:

while (true) {
char buf[] = "...";
sendto(...);
}

Posted in DoS, C++, Tools | Permalink | Trackback

3 Responses

  1. Mu DoS – iniqua

    […] Lo más interesante de toda esta aplicación es lo que denominan “regions”. En resumen se trata de una serie de parámetros que podemos modificar del payload para cada paquete en función de valores de las capas 2 y 3 del mismo. Para ello tendremos que indicar el tipo del valor que vamos a modificar, por ejemplo IP_SRC_ASC_ZERO, el offset para saber donde buscarlo en el payload y la longitud del cambio, en este caso 8 bytes. Para ver un ejemplo con un payload para SIP podeis verlo en el blog de labs.mudynamic. […]

  2. Mu Dynamics Research Labs » Blog Archive » IPv6 Fuzzing and Testing

    […] and with just three steps convert a packet into a DoS template. You can read more about our DoS methodology in my earlier […]

  3. Mu Dynamics Research Labs » Blog Archive » 7 things you didn’t know about pcapr

    […] the transport, the payload and the pattern. You can read more about mudos in our earlier blog on D/DoS Testing Network Applications. With mudos you can easily convert any one of the 310K packets into a D/DoS configuration for our […]

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.