This is a writeup for the public CTF hosted by NotSoSecure for the celebration of SQLi Labs’s launch. It started 16:00 BST on Friday 25th October and ended 21:00 BST on Sunday 27th October. Three PizzaEaters’ members participated.
In the mail containing the instructions to start the CTF, the following URL was supplied:
http://ctf.notsosecure.com/71367217217126217712/
This page requires an username and password, but there was no mention of it in the email.
We started with the classic attempt of injecting 1' or '1'='1
string for
both username and password. Having no luck, we started looking around a bit
closer.
We submitted the form empty, and noticed an HTTP 302 redirect with the following information:
7365637265745f72656769737465722e68746d6c
We noticed the hex encoding and we decoded the string with this simple Python script:
s = '7365637265745f72656769737465722e68746d6c'
print ''.join([chr(int(s[n:n+2], 16)) for n in xrange(0, len(s), 2)])
The script basically takes those numbers 2 at a time and convert them to their respective ascii char. The output for it was ‘secret_register.html’.
Great! We now have a different page name to play with. Accessing it we were greeted with a registration form that we filled with some dummy values just to test.
After submitting our registration, we tried to login with our newly created user. At this point we found ourselves in a page with a crying figure lamenting that we were not Admin. :(
Looking at the requests that were made during the login phase, we noticed the following cookie being set:
Set-Cookie: session_id=Zm9vQGJhci5jb20%3D
This looks a lot like a base64 encoded value.
$ echo -n "Zm9vQGJhci5jb20=" | base64 -d
foo@bar.com
So, the page is setting a cookie containing the user’s email. And that is it, it seems.
At this point, nothing too interesting. Perhaps it was time to try the classic SQL Injection approach in the registration form, as doing it in the login form resulted on nothing.
We tried creating an user called !!' or name = 'admin
just to see what
would happen (after all, the name of the field in the form was ‘name’
so why not give it a shot?). We logged in with our new user and to our
surprise the following cookie was set:
Set-Cookie: session_id=YWRtaW5Ac3FsaWxhYnMuY29t
Decoding that
$ echo -n "Zm9vQGJhci5jb20=" | base64 -d
admin@sqlilabs.com
Perfect! We just found the flaw. Now we need to figure out the password column
and the table name to retrieve the password of the admin
user. We assumed
the column would be called password
so we now only had to discover the table
name. We looked up for tables with password
-named columns with the following
SQL:
!!' union select (select table_name from information_schema.columns where column_name = 'password'), 'a
Turns out it was called users
. How predictable! Why didn’t we try users
before typing all that SQL?
Now we only needed to know the user’s password. So we injected the following:
!!' union select password, name from users where name = 'admin
Which gave us sqlilabRocKs!!
as the admin
password.
Logging in with our newly found credentials we get:
Well done, Flag is 815290. 2nd flag is in file secret.txt
The first flag revealed that the server had a secret.txt
file, which we
tried to read using load_file()
in a SQLi only to find that we were unable to
do so. How foolish of us! Of course it wouldn’t be that easy.
After we put some thought on it, sigsegv (a team member) suggested trying to read
/etc/passwd
. We did it by injecting this:
!!' union select load_file('/etc/passwd'), 'a
Guess what we found? An user which had his password field set:
temp123:x:1001:1001:weakpassword1:/home/temp123:/bin/sh
We ssh’d into ctf.notsosecure.com
using that username and password and it
worked. Now we only had to read /secret.txt
:
$ cat /secret.txt
cat: /secret.txt: Permission denied
Oh snap! Why can’t we read it? ls -l
revealed it could only be read by
www-data
:
$ ls -l
-r-------- 1 www-data www-data 684 Oct 25 07:46 secret.txt
We couldn’t use sudo
or su
, we didn’t find any exploitable suid executable
(we didn’t search thoroughly actually) and we could not put a script into
/var/www
to dump the contents of the file.
“Damn”, we thought, “how the hell are we going to read that file?”.
Looking for more options, we went to apache’s configuration directory and then into it’s mods-enabled
folder:
$ pwd
/etc/apache2/mods-enabled
$ ls -l
...
lrwxrwxrwx 1 root root 30 Oct 6 17:17 userdir.conf -> ../mods-available/userdir.conf
lrwxrwxrwx 1 root root 30 Oct 6 17:17 userdir.load -> ../mods-available/userdir.load
“Mua-ha-ha!” Now everything seemed clear! Mod userdir lets us create a directory at the users home and access it via the webserver.
We then created the directory ~/public_html
and put a little PHP script to dump the
secret.txt
file:
<?php echo file_get_contents('/secret.txt');
We opened the URL http://ctf.notsosecure.com/~temp123/
and there it was, the flag.
Well done, 2nd Flag is 128738213812990. email both the flags to ctf@notsosecure.com [...]
We had finally reached the goal of our quest. It was a pleasant challenge!
Thanks to SQLi Labs and NotSoSecure for all the fun.
See you next time!