The other night, I found some code for a content management system that I was building about five years ago as a personal project. I couldn’t help but install it on my vagrant and see just how truly bad it was. Regardless of how many years of experience I felt I had, the coding was done by a very naive developer at best.
Strike One: User Authentication (Open to Anyone!)
One thing that I’ve noticed is that beginner PHP tutorials and books fail to warn aspiring developers of SQL injection. I had setup roles for each user that limited them to certain portions of the app. One of these roles was a super-admin; which had free-range over everything. With minimal effort, I was able to access the super-admin role without supplying the correct username or password.
Here is the main login query:
$q="SELECT `id` FROM `users` WHERE `user`='$user' AND `password`='$pass'";
The $user variable is simply an unsanitized $_POST[‘user’] string, while $pass is a md5 encrypted $_POST[‘password’] string. As you can see from the main login query above, all someone would need to do is input some SQL into the $user variable to gain access or even have the entire database at their fingertips.
Strike Two: Trusting User Input
What would a content management system be without the option to allow users to enter content? Unfortunately, one key rule to remember is to NEVER TRUST USER INPUT! Cross-Site Scripting is a vulnerability that allows an attacker to input some malicious code that could be executed/displayed to their victims. One example would be that an attacker could alter every link on a page to point to a malware download script or they could essentially snag your stored cookies for the site. This isn’t just limited to form input fields, but can also be implemented in URLs. In my example, I provided a simple search option that adds a query string of ?search=[what was searched] and then outputs the results. Unfortunately, it also outputs whatever is in the search query string.
So for this attack to occur, the attacker simply alters the search URL with their code:
When the search results page is displayed, an alert box will popup with the word “hacked” to the user.
Strike Three: Loading ANY File You Want!
In the admin part of my app I displayed admin pages based upon a query string. Sadly, this allows any user to see ANY file on the server.
include PLUGIN_PATH . "views/" . $_GET['page'];
Simply put, if you were to change the page query string to ?page=../../../../etc/passwd you could essentially take over the entire server.
Learning From Mistakes
Back then, I didn’t take web application security as seriously as I do now. Thankfully, I didn’t launch this application into the wild and instead chose to go with WordPress. WordPress has many built-in sanitization and escaping functions that will prevent these issues from occurring. In closing, I just want to point out that no one is perfect, but everyone should learn from my mistakes.