It's true that all code has flaws, some of them security related.  It's also true that many of us didn't know (or potentially care) about security when we first started in development so our historic code is likely to be littered with issues.  In this blog post I'm going to look at hacking a version of my blog from 2007.  Let's dive in!

Getting the old blog running

My first problem was that this was old code, without any updates in at least ten years.  I tried running the site in a PHP 7.3 environment, literally just copying my code across, but that threw fatal PHP errors:

[Mon Dec 14 07:49:14.493182 2020] [php7:error] [pid 462] [client 10.233.2.1:40324] PHP Fatal error:  Uncaught Error: Call to undefined function mysql_connect() in /var/www/web/inc/db.inc.php:10
Stack trace:
#0 /var/www/web/inc/header.inc.php(11): include()
#1 /var/www/web/index.php(3): include('/var/www/web/in...')
#2 {main}
thrown in /var/www/web/inc/db.inc.php on line 10

After checking the PHP site we can see the function mysql_connect() was deprecated in PHP 5.5.0 and removed in PHP 7.0.0:

Screenshot of the PHP manual showing the mysql_connect function page.
Warning on the PHP manual website advising the mysql_connect() function was long gone!

This meant I had a few options:

  • Find a way to tell my new environment to use version 5.x of PHP
  • Recode my old blog to use newer functions
  • Use an old Linux virtual machine

I wasn't about to spend potentially hours recoding my old blog engine, as much as this blog post will be interesting for me to write.  Instead I found a VM that I keep lying around for penetration testing workshops and spun up my old blog on that.  

Screenshot showing the lab virtual machine is running PHP 5.3.10.
This version of PHP will work for my old blog.

After copying across my code and restoring an old database backup we're good to go with a potentially embrassing old site.  My operational security [1] wasn't as good then as it is now (my age is listed) but there's no point me hiding that in the screenshot - the Internet never forgets.

Screenshot of my old website showing a grey background with black text in a very boxy style.
How my site used to look. Fair to say it's dated?

Attacking the site as a visitor

Before we look at getting administrative permissions let's see what we can do as a standard user of this site.  Heading over to the blog we can see there's the ability to add and read comments, one such example below:

Blog post showing a comment below.
Stargate SG-1 fans may recognise the quote, although spelling in Goa'uld isn't my strong point.

Using the "add comment" link we should be able to insert something to the site's database.  We'll start with some injection attacks.

What is injection?

Injection has been in the OWASP Top Ten vulnerabilities for a long time, holding the top slot in the 2017 edition.  By causing the site to run or store our own arbitrary code (code we supply) we perform what's known as injection.  There's two types I tend to focus on: SQL injection (SQLi) where we cause the application to ask database queries that we provide, and cross site scripting (XSS).

Stored XSS is saved into the database, so persists between visits.  Alternatively there's reflected XSS where code is executed as a result of clicking a specifically crafted link or input.

XSS in a comment

We'll start with XSS on a comment.  The aim here is to get some stored XSS that will either impact the administrator or visitors to this site.  An attacker could use this to steal information or redirect the user to another site, but for our testing we'll just display a pop up.

Screenshot showing cross site scripting attempted in three form boxes.
Three potential payloads.

Sadly for the attacker intent on directing readers to another site the comment won't be available to the public until it's been approved, but the administrator should still be affected.  Logging in as an admin does indeed show that the XSS was stored, and triggers:

Screenshot showing a popup with the word "body" in it.

Interestingly only the XSS placed in the body triggers.  A look at the HTML shows there must have been a length limit on the name field as the script tag doesn't close (we're left with </sc) meaning the HTML is broken.  This information may be useful in later attacks.

While testing I noted that the comment form rejects any input that includes an apostrophe, telling the user that "comment addition failed".  It's possible I blocked apostrophes in a half hearted attempt to block SQL injection, which often includes an apostrophe.

Testing SQL injection

Kali Linux includes sqlmap, a tool that scans for SQL injection vulnerabilities.  I pointed sqlmap at the comment form so it would scan for issues:

[email protected]:~# sqlmap -u http://192.168.56.3/PERSONAL/blog.php?comment=1005

Only to be told that the form was not vulnerable:

[CRITICAL] all tested parameters do not appear to be injectable.  Try to increase values for '--level' / '--risk- options if you wish to perform more tests...

There's also a user form for requesting a copy of my CV (bad opsec again!).  That was also not vulnerable to SQL injection, partly because after submitting the form the user is not given anything from the database, just a message that they should check their email.

What's next?

Having access to the public facing site is one thing, and it's useful that we can perform cross site scripting, but there's not a lot else that we've achieved as yet.  We only know that the XSS succeeded because I already had access to the admin portion of the blog.  In the next post in this series we'll be working out how to gain access to the admin back end of the site.


Banner image:

[1] Operational security, or opsec is protecting oneself in the real world.  For example, if at a conference that requires you to wear a name badge, not wearing that badge outside the conference.  Alternatively, not posting photos with your address details in them / scrubbing EXIF data etc.