HackMe Contest PHPro

Introduction

PHProΒ designed a hacking competition in which the participants had to find a way to change the image on the website. The tip mentioned on the website was: “Search for clues in the source code and combine those with your security knowledge”.
The site showed only this:

website hackme PHPro

This is a write-up of my process of solving this “puzzle”. Note that this may look simple while I describe it here, but figuring this all out without knowing where to end is quite challenging (and in my opinion a fun) experience. I would like to thank the creators of this contest for all the effort they put into this challenge. It was a combination of logically thinking, failing at multiple points and staying determined to continue to poke around.

Let’s go!

Before I started following the tip, I investigated which requests were send to the server.

server traffic

I was hoping on a certain parameter in a request which sometimes lead to a good old SQL-injection. Unfortunately, it was just an empty request to the homepage and a few requests to some static resources (CSS, JS, images,…). The file “xss.js” directly caught my attention. It turned out that the file blocks every change made in the client-side source code (lol’ed hard at the image which appears when triggered ).

I quickly checked robots.txt (on some websites you find interesting things there), but it was non-existing.
The urge to start dirbuster was intensifying. It’s a great tool to find some juicy control panels or hidden pages, however it was to soon to start smashing the server with lot’s of requests.

Time to look into the source code (client side). The head HTML looked normal, however there was a CSS-file missing (assets/stylesheets/pygment_trac.css->404). Could be a lead or just a f*ckup by the admin.
When searching further in the body HTML, I found a HUGE comment. Actually 15604 lines of pure reading joy about a captain with a strong urge to abuse a white whale because it bit his leg off.

Spoiler

The captain got owned (killed) by Moby dick.

At the very end of that comment, there was one line that was not related to some random sperm whale:

That was fun … If only we could add some layout to the book πŸ˜‰

That’s definitely a lead! Likely a CSS-file with the next riddle, or maybe a javascript script responsible for some layout tasks. So I looked in all the these files, but there was nothing hidden in it at first sight.

CSS files

I was hoping to find another comment, but that was not the case. The next thing I searched for, were links. Great way to include extra code, or to hide a new lead. I searched for “http” through the file, when I noticed something unusual.

Github reference

Wow, it seems that they used a repo on Github for this website. That means we can look into the source code!

<?php
include('config/dbcon.php');
try {
  $dbh = new PDO("mysql:host=$host;port=$port;dbname=$dbname;charset=utf8", $username, $password);
  $sql = 'SELECT imageURL FROM hackmeContest.images ORDER BY id DESC LIMIT 1';
  $q = $dbh->query($sql);
  $q->setFetchMode(PDO::FETCH_ASSOC);
  // PDO closes connection at end of script
} catch (PDOException $e) {
  echo 'PDO Exception: ' . $e->getMessage();
  exit();
}
?>

The previous code snippet shows a PDO connection to a MySQL server. It gets the image-URL of the latest record from the images table and saves it to $q.
A few lines later we see the following code.

<?php while ($r = $q->fetch()): ?>
<p><img src="<?php echo $r['imageURL'];?>" alt="De winnaar!"></p>
<?php endwhile; ?>

In the previous code-snippet we see that the link is put inside a img-tag. And that is exactly where we are after!
Now we should know where the database and credentials are. On top of the index.php file we see the following:

include('config/dbcon.php');

Unfortunately, there was a problem:

git ignore file

The database configuration was not included into the repository (because of the gitignore file). At that point, I was stuck for a while. Luckely, a friend of mine found out that the commit history was very interesting (Thank you Yon!):

Repo commit history

The credentials were once included in the index.php file, but removed afterwards. Unfortunately Github keeps track of everything a user commits, so fortunately for us we got the credentials!

<?php
// Begin Vault (this is in a vault, not actually hard-coded)
$host="178.62.246.226";
$username="hackme";
$password="mduTa3fkKwrF9ne744WVCNYCg";
$dbname="hackmeContest";
$port="9999";
// End Vault

Bingo! We found the credentials and server!
I threw the information into “Sequel Pro”:

Connecting to the database

Smashed the connect button and… this happened:

Disappointed...

This was my exact reaction:

Mr robot what-are-you-doing

The flow was going so well, and it crashed right here. Then I realised that I skipped the reconnaissance part in this challenge. Every hack start with a good recon of the server: what ports are open, which services are used and most importantly which versions (to exploit flaws in it).
At that moment I decided it was time to use dirbuster (yay, slamming the server with thousands of requests as a revenge for not letting me in), nmap and some other OSINT tools to gather intel.
Nmap showed me the following results:

Screen Shot 2016-08-15 at 19.58.55

So the MySQL server was 1 port lower than in the github file…

ezgif-2107733327

After retrying the connection on port 9998 we finally got in. However, we directly face an error:

Screen Shot 2016-08-15 at 20.35.55

Apparently we cannot use the “SELECT” command on the database (I double checked that in the “information_schema” database which contains info like permissions).
At that point I somehow didn’t get it why we couldn’t use the select command. How does the website show the image URL (assuming they used the exact same code from github) if it can’t use the “SELECT” command? That confusion pushed me in the wrong direction: I tried privilege escalations (used metasploit for that) on the MySQL server to obtain more rights, but that was unsuccessful.
Suddenly it became obvious for me: we only had to insert a image URL record and then we have our picture on that page! The “SELECT” Query would get the latest URL record and show it as an image. Only the “SELECT” command was restricted (probably to protect the information of other participants), but the “INSERT” command is allowed.
I used “MySQL workbench” to obtain the columns information:

MySQL workbench

Now we only had to make a query like this:

INSERT INTO `hackmeContest`.`images`
(`imageURL`,
`name`,
`email`,
`location`,
`opt_in_newsletter`,
`host`)
VALUES
("https://vincentcox.com/profielfoto.png",
"Vincent Cox",
"<OMITTED>",
"<OMITTED>",
0,
"vincentcox.com");

And when we execute that query:

Query inserted!

If we reload the website, I can see my picture there!

Solved!

Extra

Before we call it a day, let’s view the code of the image again

<img src="<?php echo $r['imageURL'];?>" alt="De winnaar!">

What if we inserted the following code instead of the image-URL:

https://vincentcox.com/profielfoto.png"><script>alert("XSS for breakfast")</script>

( Ν‘Β° ΝœΚ– Ν‘Β°)