It’s been a while since I posted something, and this is mainly due to being pretty busy learning and messing around with various side projects. I like to have several projects on the go at once, that way I never really have an excuse to sit down and do nothing. There is always something I can be doing on one of them, so whenever I am blocked by one project, I skip to another.
The Damn Vulnerable Web App (DVWA) is one of these projects that I just finished part of, so thought I would write up how it went, just in case you wanted to follow along at home. It is pretty much exactly what it sounds like, and is meant to be used as a training tool to teach people how to attack web applications in a legal environment.
The DVWA reflects the lions share of the Top 10 vulnerabilities in web applications according to the Open Web Application Security Project (OWASP). The most recent OWASP 10 vulnerabilities includes;
- Injection (Which we will be dealing with today)
- Cross site scripting (XSS)
- Cross Site Request Forgery (CSRF)
Now there are a bunch more in the Top 10 (about 7, maybe?), but the DVWA was made around 2007, and the OWASP Top 10 changes about once every 3 years, so some of the vulnerabilities are not so relevant anymore, as they have been fixed, mitigated or merged with other vulnerabilities. Injection, though, is always in season.
The web app is pretty easy to set up as it is on a virtual machine. This is the 1.0.7 version being used, as the 1.0.9 version is actually just the web app, ready to be deployed to your environment of choice. I like the VM as it is super easy to set up on its own sub-net with extremely limited access.
I chose to have my Kali VM access the DVWA, and nothing else. If you choose to set up the app yourself, then please pay attention to the warnings noting that it is, in fact, “Damn Vulnerable” and if you leave it on a server visible to the internet, it will get hacked.
So with that said, lets dive into the exercise. This is what it looks like once you have performed your mandatory nmap scan.
Obviously we are going to check out the web server, and once connected we are given this interface to play with.
I skipped ahead and hit the “Create Database button, which adds some data into the tables, ready for us to
As you can see there are a bunch of exercises, and hopefully I will write them all up, as they are pretty much required reading for the OSCP, which I hope to take sometime this year.
In the SQL Injection section we are given an input form field asking for an ID. I entered 1 as a test parameter, and was greeted with the following.
Well that seemed a bit easy. Ideally we would be able to get the username and password though, so on to some more probing. I hooked up Burp Suite to analyse all the requests but nothing seemed out of the ordinary. Rightly so too. Next I tried running some automated tools against the app, specifically sqlmap, which has given some amazing success previously.
I was greeted with a LOT of red text, telling me that there were no injectable parameters. None. That seemed strange. I continued to try some classically injectable inputs, such as:
1' OR 1=1--
1" OR "2"="2;
Not even a SQL error message.
After a further couple of hours, I had exhausted pretty much every input I could find, even those in injection cheat sheets online. I decided to look at another persons write up, and as I was going through their set-up I noticed exactly where I had gone wrong. It was here.
There are varying levels of security for the web app, for varying amounts of challenge I assume. I had not changed it since boot up, so lowered the level to low, and tried again.
At this point, it is perhaps prudent to explain exactly what SQL injection is. If you already know, then skip the next 7 paragraphs.
SQL injection in this case, is where you submit a value for the database to search for. The database has a particular language it uses for searching for things in the database tables. It uses something called Structured Query Language (SQL), which is just a fancy way of asking the server for the answer to questions from the user.
The problem arises when there is no sanitation of user input. If the user enters some SQL in their question, and the web application does not strip it out, then the database will interpret that and reply. This might not sound like a problem for asking questions, but SQL also contains the language for manipulating data.
That means that if you know how to talk to the underlying database, then you know how to read any data, write any data or remove and data. That includes passwords, access rights, all kinds of things. No wonder Injection is the number 1 vulnerability on the OWASP Top 10.
A lot of the time, an easy way to escape the sanitisation the web application is performing is to use a single tick ‘ as the app will add its own ‘ mark at the end of whatever data you supply, meaning that you can squeeze in some SQL in the meantime.
In the screenshot above, that is exactly what I have done, as the first two characters are 1’, which gives the web app the UserID of 1 to search for, then a single tick for me to add some SQL afterwards. I add in OR ‘1’=’1 which when the web app adds its own tick mark at the end will send OR ‘1’=’1′ to the database. As 1 does equal 1, that will evaluate to True.
The final query that is sent to the database is therefore ‘1’ OR ‘1’=’1′, which tells the database to search for UserID 1 or UserID True. That means it will return anything that has a UserID, as that value will be True.
That is essentially what we are going to be doing for the rest of this write-up too, sending the database statements or questions that evaluate to True so that the database sends us data. We will also add in some questions to get more specific data. OK, onto the SQLi!
Now that we know there is an injection point, we need to know where it is to be able to ask the right questions. After some digging I figured out that the string
1' OR 1=1 union select null, XXX #
would return the answer to my questions, where XXX was the question. The union select null part is essentially telling the database to join the answer to my question with “select nothing”, so nothing. So just answer the question.
Above I asked the database what version it was, and you can see, down at the 6th area, after the Bob Smith user, that the Surname parameter reveals the answer to my question. Version number of the database can tell us quite a lot about how it works, but not really anything we need to know here.
It was running as root! That’s pretty bad, but this is supposed to be vulnerable. Asking the database what it was called returned the completely unsurprising name of dvwa.
You would know this if you had been paying attention to the setup database screenshot. I however, was not paying attention when I set it up. Next off is to figure out which tables are in this database, which gives us the values of “guestbook” and “users”.
Users looks like it could be pretty interesting, so let’s ask the database what the names of the columns are. We can do that using this command.
group_concat(column_name) FROM information_schema.columns WHERE table_name="users"
The “information_schema” part is in reference to something that contains data or information about the other tables in the database. We get this in return.
“user” and “password” look particularly interesting. Asking the database for all the values stored in those would look something like this.
group_concat(user_id,:,user,:,password) from dvwa.users
Surprisingly (to me at least), this gave me an error declaring that I had an error in my syntax. This usually occurs if you have made a spelling mistake, but I had not. Fortunately the error message was somewhat descriptive, saying it was near ‘:,login,:,password) from dvwa.users #’. It turns out that the colon character ( : ) is not interpreted well. Fortunately, we can hex encode characters, and the database will merrily accept them, and then decode them. We just need to change a couple of parts.
group_concat(user_id,:,user,:,password) from dvwa.users
group_concat(user_id,0x3a,user,0x3a,password) from dvwa.users
Now we are greeted with the following.
Those look suspiciously like password hashes. John the Ripper should make short work of them, and I planned on starting John up, and then googling them too, as SQL passwords are MD5, which is pretty exceptionally weak. I need no have bothered spreading the risk of finding the passwords across two methods though, as the admin password was “password”. I am no sure which found it faster, Google or John. John cracked all 5 passwords in under a second using the 10k most common passwords list that comes with Kali.
If you remember from the port scan, we could see port 3306 open, which is the MySQL port. If inbound connections are accepted, which is highly likely, then we can now log in with admin credentials, running as root. We can pretty much do anything to this web app at this point.
There is a reason that injection is such a big deal, and I hope that I have helped you understand a little more about why in this post. Sure, this is a training tool that is purposely built to be exceptionally vulnerable, but it is pretty normal for injection to be used against databases in the real world.
I hope to get around to writing up the rest of the DVWA sections, and to trying out these techniques on higher security levels as I progress, if indeed that is how it works.
I hope you have an awesome week!