Overview / TL;DR
-
As said in the description, this is NOT a writeup, there are many writeups online that get straight to the point
(how2solve challenge pls)which unfortunately this gist is not -
I didn’t solve the challenge mainly because I got ahead of myself and missed a crucial detail in one of the many approcahes I took, in a sense I dived too deep down a rabbit hole which closed me off from the real answer, while I was digging deeper for one that simply wasn’t there
-
natas15 is a
Blind SQL Injection
challenge, which I did not have knowledge of before (but I do now), in fact the only SQLi I knew of before this was the simple auto bypass method (basically' OR 1=1; --
), so I’m actually glad I did this challenge til the very end because I ended up learning a lot !
Wtf is a “Blind” SQL Injection ?
It’s basically an SQL Injection but under the circumstances where the results aren’t returned directly to you
-
More often than not you will only get responses along the lines of:
The query didn’t return anything (which means False ) The query returned a row/ or multiple rows (which means True ) An error in your query (which also might return nothing)
- As you can imagine it makes things a lot harder for an attacker (but not imppossible), as they can only ask the database True/False questions
An example implementation in the natas15 sourcecode:
$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
if(array_key_exists("debug", $_GET)) { // ^^^^^^^^^^^^^^^^^^
echo "Executing query: $query<br>";
}
$res = mysql_query($query, $link);
if($res) {
if(mysql_num_rows($res) > 0) {
echo "This user exists.<br>";
} else {
echo "This user doesn't exist.<br>";
}
} else {
echo "Error in query.<br>";
}
In this case the username variable is exploitable as it isn’t being sanitized properly
What I did at the beginning
Although this approach was incorrect it taught me a lot about the UNION and INTO OUTFILE clauses and how they can be abused
One of my first ideas was that since the results weren’t returned directly to the user, I could use UNION
to link a new select statement which would ignore the old results and dump any new results into a temporary file to be read later. The many possible issues with this approach is :
- The user currently executing the query may not have write access
- The file has to be written to somewhere accessible by the user and within the webroot directory
- The user has to have the privileges (in this case
FILE
privileges) to even use commands likeLOAD FILE
orINTO OUTFILE
Example URL:
http://natas15.natas.labs.overthewire.org/?username=" AND 1=2 UNION SELECT * INTO OUTFILE '/tmp/out' FROM users ; --
Server-side query:
SELECT * from users where username="" AND 1=2 UNION SELECT * INTO OUTFILE '/tmp/out' FROM users ; -- "
Side Note: A more dangerous version of this injection would be similar to:
SELECT * from users where username="" AND 1=2 UNION SELECT '1','<?php system($_GET['cmd']) ?>' INTO OUTFILE '/whateverpath/directory/script.php'; --
which basically stores a PHP script containing a shell that you can then use to execute arbitrary commands on
I executed variations of this query mutliple times to no success, so I began to suspect that this user account had very limited privileges, unfortunately I was right
Using the built-in functions
mySQL has very handy functions like user() that returns who the current user is, version() that returns the running version , etc …
I also found out that SQL supports the LIKE clause, which is perfect for avoiding true equality “=”
Starting off with a simple query like this :
SELECT * from users where username="
" OR user() LIKE "%
"
-
% when used alone matches everything so the expression
user() LIKE "%"
is basically saying user() matches ANYTHING, which is true as long as the thing thatuser()
returns is not NULL -
% when used with other characters will also match up to a certain pattern such as
"%a"
matching everything that ends with"a"
and"a%"
matching everything starting with"a"
-
The _ character functions similarly to
"."
in regex. It matches any character, so as you can see in the gif below, it can be used to guess the length of a certain field, while combined with the % character can also be used to match patterns
(After guessing the value of a certain field the LIKE
can be replaced with =
to ensure the correct value, since the query would evaluate to False otherwise)
-
Using trial-and-error method or even a brute-force method its a slow but surefire method of leaking useful data from the database such as
-
The current user (as shown above)
-
What privileges this user had
(USAGE = no privileges besides logging in and SELECT’ing) -
The version of mySQL running
URL:
http://natas15.natas.labs.overthewire.org/?username=" OR @@version LIKE "5.5.55-0%2Bdeb8u1& debug (%2B = +)
Query:
SELECT * from users where username="" OR @@version LIKE "5.5.55-0+deb8u1"
-
The dummy user accounts being used
-
I was stupid
This is where I screwed up, I had already acquired a method to leak usernames and passwords from the users table, but somehow it never occured to me to look for a user called natas16, instead my smart-ass brain kept pestering me to find a way to execute arbitrary commands so I could cat
the password file:/etc/natas_webpass/natas16
Although I did most of this brute-forcing stuff by hand (since it was fairly short) a proper script is recommended for brute-forcing the password since it is 32 characters long and there are 26 lowercase letters + 26 uppercase + 10 digits = 62
possible characters for each of the 32 character slots, which is 62 ^ 32
possible combinations