- As said in the description, this is NOT a write-up, there are many online that get straight to the point (what is required to solve the challenge) 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 !
- 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 / multuple 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>";
}
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 (It didn't)
- 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 much more dangerous version of this injection would be something like
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
mySQL has very handy functions like user() that returns who the current user is, version() that returns the running version , etc ...
Starting off with a simple query like this : SELECT * from users where username="" OR user() LIKE "%"
- % when used alone matches everything so when saying user() LIKE "%" its basically saying user() matches ANYTHING, which is true as long as the thing that user() 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 replace 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"
-
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