How to Set up a Web Application Hacking Lab

To learn something well requires practice, and ethical hacking is no exception. Unlike say, practicing the trumpet, practicing hacking has potential legal implications. This means that if you want to practice hacking, you need an environment. In this article, I’ll show you how to set up a basic web application hacking lab, and I’ll give a brief overview of how to get started.
If you’re a developer, operations engineer, an aspiring security analyst, or just someone who enjoys learning new things, then you’re in the right place!
To follow along, you’ll need the following software installed on your computer:

If you’re new to these tools, VirtualBox is a free virtualization tool, which means that it will run virtual machines. Vagrant is a virtual machine management tool used to start up and configure different operating systems.
Once you have these installed, you’ll need to download the latest copy of the Kali Linux VM for VirtualBox.
It's dangerous to go alone
Kali Linux is a distribution of Linux specifically used for penetration testing. It contains hundreds of tools used throughout the different phases of a penetration test. It will serve as your arsenal as you learn to hack.
Kali isn’t a prerequisite for hacking. However since it’s preloaded with the most common tools, it’s easier to install the one VM instead of all the other tools.
Reset the root passwordOnce you’ve downloaded Kali, you can start it up and log in. The default username and password are root / toor. Once you’ve logged in, the first thing you should do is change the default password to something more secure.
To do that, open up a terminal window and type passwd . When prompted, type your new password, and then again to confirm.
Next, we’ll use Vagrant to set up the VM that you’ll be practicing your hacking skills on. The cool thing about Vagrant is that it can start up a virtual machine and configure it based on a file named Vagrantfile . The next step is to download the Vagrantfile, as well as some other source code from Github.
Download with git:

$ git clone

Download zip file 
Once you have the code extracted to its final destination, you’re ready to use Vagrant. On your OS (not Kali), open up a terminal window and change directories into wherever you downloaded the code to and run the vagrant up  command.
Vagrant up
Vagrant can take awhile to get everything set up. This is especially true the first time you run it since it will need to download the Ubuntu VM image. Now is probably a good time to go get some coffee, or a beer, depending on the time of day.
Once Vagrant is done, you can test that it’s working by opening a browser on your OS and browsing to this link: http://localhost:8080/login.php.
Another cool thing about Vagrant is that it allows you to bind ports on the VM to ports on your OS. That’s why you can use “localhost” because I’ve bound port 80 on the VM to port 8080 on the host OS in the Vagrantfile.
Vagrant binding the host port 8080 to port 80 on the VM

DVWA Login If it all worked…

If everything worked, you should see a Login window in your browser. If you do, then it’s almost time for the fun to begin.
The web app that you’ll be attacking is called “Damn Vulnerable Web Application.” It’s a web application designed for security professionals to practice web application hacking.
Before switching over to using Kali, you just need one more piece of information: the local IP address of your computer. If you’re on a Mac or Linux system, you can use the ifconfig  command. If you’re on Windows, you can use the ipconfig  command.
Your local IP address is necessary because Kali needs to be able to access the web application, which is bound to port 8080 on your IP address.
If you have the IP address, now it’s time to switch over to Kali. Start by opening up Firefox and verify that you can access the website. You can access Firefox from the applications menu.
Launch Firefox from the application menu
Using Firefox, browse to the web app to make sure you have the correct IP and that everything is connecting correctly from Kali to your host machine.
For me, the URL is, however, yours is likely to be different. If you’re looking at the login page, then your web hacking lab is ready. Congratulations, you now have your very own lab and the tools to successfully compromise the web application’s host.
I want to give you a quick tour of how this application works, so you will need to log in. While the username and password are freely available in the app documentation, using them kind of defeats the purpose of practicing hacking.
So, I want to start by teaching you to brute force a login page to obtain credentials.

Brute Force

For years, applications have had admin users, often named “admin.” Predictability tends to be good for hacking, so let’s take a shot in the dark and assume there is an admin user, aptly named “admin.”
Login failed
Start by entering a username of admin, and password of 1234 and submit that, just to see what happens. You’ll see “Login failed” at the bottom of the page. Next, I want you to try the same username and password you just tried 4 or 5 times in a row.
What stands out to you? If you’re new to this, it’s okay to say “nothing,” you’re here to learn after all. What stood out to me is that after getting the password wrong several times, there’s no mechanism in place to either throttle the requests, or display some sort of challenge-response.
Godzilla in Tokyo
This is a prime candidate for a brute force attack. As the name suggests, brute force attacks are as covert as Godzilla casually strolling the streets of Tokyo. However, brute force attacks are common and effective.
Conceptually, a brute force attack works by trying all the possible combinations of a username and password. In reality, there are limitations that make that impractical. You can’t actually try every possible password combination for every user. So, you need to try and hone in on the most salient potential passwords. One method is to use actual passwords from production systems. Because there have been so many data breaches over the years, there are downloadable word lists containing millions of leaked passwords. By using a word list like this, you can quickly try a lot of common passwords before moving on to more complex options.
The tool I’ll use for this is Hydra, which is a relatively easy to use brute force tool that supports multiple protocols. Below is an example of using Hydra’s http-post-form module to post some usernames and passwords to the login page of the web app.
Try it out for yourself, but make sure you change the IP address to use your host’s IP. For me, this takes about 60 seconds to run.

$ hydra -s 8080 -l admin -P /usr/share/wordlists/dirb/small.txt http-post-form "/login.php:username=^USER^&password=^PASS^&Login=Login:S=Location\: index.php:H=Cookie: security=medium;" -f

Command breakdown:

-sThe port number the web app is running on (80 is the default)
-lThe username to try and log in with
-PA file containing words to try as a password
http-post-formThe name of the module to use
-fStops the process when a username / password combo is successful
That long string of chaosThis is a colon delimited string that the module knows how to parse. The first argument is the URL to post to, followed by the name of the username and password fields; those tokens for ^USER^ and ^PASS^ are automatically replaced by Hydra.
The S=Location\: index.php is what to look for in the request to indicate that the login was successful because we’ll be redirected to the index.php page.
H=Cookie: security=medium sets a cookie in the header of the request.

If you ran that command, then know that it didn’t work. That’s because there’s a CSRF token being used on the site. The reason I know this is that I added the -d flag to the command and sifted through some pretty ugly debug text. It’s a common misconception that CSRF tokens have the secondary benefit of preventing brute force attacks. Anecdotally, you might think this supports that claim. However, while a CSRF token is effective at preventing cross-site request forgery, it doesn’t prevent brute force attacks. At best, it forces you to write a bit of code.

An aside on cross-site request forgery

Imagine that your bank’s website allows you to transfer funds from one account to another; that’s a pretty common thing for a bank to support, after all.
The URL to do that might look like this:

If your “spidey sense” isn’t going off yet, that’s okay. The implied functionality here is that this URL accepts an amount to transfer, the account to transfer from, and the account number to transfer into. This is a useful transfer feature if you’re using it from inside the bank’s website. However, what’s to stop an attacker from editing the URL and getting you to click it?
If you’re already logged in, in theory, the transfer could kick off and send money from your account to the attacker.
This is what CSRF tokens are used to prevent. For each session and/or request, a token is generated and sent along in the HTTP response. The server expects that same token to be passed back with new requests. If you click on the URL outside the context of the bank’s website, the token won’t exist and the request will fail. By the way, this isn’t limited to GET requests, that’s just an easy example.

Back to the beaten path

So, to get a working solution you need to issue a GET request and grab the CSRF token and PHPSESSIONID. Once you have those, you can pass them off to the POST request that Hydra sends.
As a general rule, you shouldn’t run any code that you don’t understand. Make sure you take the time to look over the code. If there’s anything you don’t understand, it’s worth the extra time and effort to look it up.
Here’s a working script to brute force this login:

# This is a modified version of the script found here:
echo 'Starting bruteforcing...'
CSRF=$(curl -s -c dvwa.cookie "${ATTACKIP}:${ATTACKPORT}/login.php" | awk -F 'value=' '/user_token/ {print $2}' | cut -d "'" -f2)
SESSIONID=$(grep PHPSESSID dvwa.cookie | awk -F ' ' '{print $7}')
echo "Attacking host: ${ATTACKIP} on port: ${ATTACKPORT}"
echo "Using CSRF Token of: ${CSRF} for session ID: ${SESSIONID}"
hydra -s ${ATTACKPORT} -l admin -P /usr/share/wordlists/rockyou.txt ${ATTACKIP} http-post-form "/login.php:username=^USER^&password=^PASS^&user_token=${CSRF}&Login=Login:S=Location\: index.php:C=fake_cookie:H=Cookie: PHPSESSID=${SESSIONID} security=medium;" -v -f

To run this for yourself, you need to set the IP address, save this, and make it executable. Once you do, run the script and it should print out the password on the screen.
Brute forcing a login with Hydra
If you’ve successfully run this for yourself, then congratulations! You’ve just brute forced your first application.
DVWA Home PageNow that you have credentials, you can log into the app with the username “admin” and the password “password.”
The home page is a set of general instructions, and along the side is a navigation bar broken out by the various types of vulnerabilities.
Change DVWA DifficultyThe application is designed with difficulty levels that you can change by clicking on DVWA Security, and editing the difficulty in the drop down.
Before setting you loose to practice your ethical hacking skills, I want to talk about the different types of vulnerabilities.

Brute Force

As you’ve already seen, this is an attack where you try multiple possible values until you get the correct one. Humans are awful at remembering passwords, so we opt for something simple, and that makes dictionary attacks effective. When dictionary attacks aren’t successful, there are other options that involve modifying the words in the dictionary with different filters. This might include, for example, replacing certain letters with numbers, adding numbers to the beginning or end, trying different variations of capitalization, etc.
Brute forcing is a “noisy” option because of all the requests made to a service, however, it remains a highly effective attack.

Command Injection

I don’t often see command injection in modern apps, however, it’s always worth knowing about these sorts of things.
Imagine that you wanted to develop a website where people could run DNS queries. You don’t want to re-engineer the wheel, so you create a wrapper around the nslookup command.
The code looks something like this:

shell_exec( 'nslookup  ' . $users_query );

This code runs the nslookup command combined with whatever the user passed in. If the user isn’t being malicious and entered in “,” then the command that is run will be:

$ nslookup

However, what if the user is malicious and enters something like “ && id”
The command that will be executed would be:

$ nslookup && id

This will run the nslookup  command and the id  command. Once you can run commands on a system, you’re not far off from gaining root/admin access.

File Inclusion

Unlike command injection, I’ve seen more than a few file inclusion issues in production systems. File inclusion is used to dynamically determine which file should be rendered. It’s common with dynamic languages such as PHP because of the ease of having included files processed by the server. Outside of PHP, the more common use is file inclusion for view templates.
The url for something like this may be:

In this example, the view is the file welcome.tmplt . However, if the developers didn’t lock things down, you might be able to do something like:

Here, each ../  moves up one directory from the current directory. It may be necessary to try out different paths. If you’re lucky, you’ll be able to read arbitrary files on the system.

File Upload

File uploads are pretty common, and in some cases, they can be a great attack vector. When trying to exploit a vulnerable file upload, the goal is to get the server to run your code. With languages like PHP, if you were to upload a PHP file and have the server process it, it will execute your code. If you can get your code running on a system you’re attacking, you’re well on your way to root/admin access.
With file uploads, you want to figure out what rules the developers might have put in place to prevent you from getting your code onto the system. Are they filtering out certain file extensions? If so, is the filter case sensitive? Are they using a regex that isn’t effective enough? Are they relying on the mime type that’s sent with the POST body? In cloud native applications, it’s likely that the file being uploaded is stored in a blob storage service such as S3, Azure Storage, or Cloud Storage. If that’s the case, you’ll have to start thinking about how the file is used post upload.
Once you can get your code onto a system, you just need to figure out how to run it.

SQL Injection

Injection attacks are a common problem, and SQL injection is no exception. SQL databases are widely used for many different applications. It’s common for developers to build SQL queries dynamically based on user supplied data.
Imagine that you want to add search functionality to your new website. You find some samples online and your end result is code that looks something like the following:

$query = "SELECT name, price, description FROM products WHERE name = '$name';";

In this example, the $name  variable is user supplied. Even if a user isn’t being malicious they can’t enter a product with a single quote or it would break that query. However, a malicious user could view data they’re not supposed to such as usernames and password hashes. They could create new records, potentially read arbitrary system files, drop tables, and lots of other disruptive acts.
If you name you child Robert'); DROP TABLE Students;-- any damage is the fault of the developers
The difference between SQL injection and blind SQL injection is that blind injection may not provide an indication of what the query might look like.
In the example of the product search, if the products are listed and they have a name, price, and description displayed on the screen, this gives you some clues as to how many columns might be returned and potential names (assuming the developers followed best practices for naming, etc.).
Blind injection doesn’t have any visual indicators to help provide clues, which includes error details. The best you might have is a generic 500 error.

Weak Session IDs

Weak session IDs may not sound all that exciting, however, the session ID is what proves that you are who your username and password claim you are. Once you’ve authenticated, the session ID represents you. Session IDs should be generated randomly so that no one can guess the next session ID.
If you knew what the next session ID for a site would be, then you can become the next person who browses to the site. If that person is logged in, since the session ID represents that user, you will have whatever access they have.
Products such as Burp Suite contain tooling that you can use to test the sessions for predictability.


Cross-site scripting is a very common method where attackers can inject their own scripts into a web page. There are many ways an attacker can use this to their advantage. They could use it to steal session IDs that aren’t HTTP only. They could use it to inject their own functionality into the page, maybe presenting a fake password reset request that sends the current password to them. Or many other wonderfully devious things.
There are different types of XSS attacks. However, the end result is that an attacker gets a legitimate user to run malicious scripts.
For reflected XSS, it’s common that things such as search boxes will take whatever the user entered and display it on the page. If that search happens to be something like

<script>alert('Hello World');</script>

Then a vulnerable site will pop up an alert saying “Hello World.”

Happy Hacking!

I hope this brief intro to setting up a web application hacking lab has been interesting for you.
When you’re ready to stop the VM running the web application, you can run the vagrant halt  command from the directory with the Vagrantfile. When you want to start it back up, use vagrant up . And, if you want to free up space from the VM, run the vagrant destroy  command.
The next article in this series will show how to exploit SQL injection vulnerabilities with your new hacking lab. If there are other security topics you’d like me to cover, feel free to let me know. 
To get a general understanding on Databases, have a look at our two Labs: Create your first Amazon RDS Database or Getting started with Amazon Aurora database engine.
Check out also our collections of labs on Web Applications to get started with web apps. 
Happy hacking and thanks for reading!

Written by

Ben is a software engineer with years of experience building web and mobile apps. He learned about DevOps some time ago, and hasn’t stopped talking about it since. In addition to DevOps, he’s passionate about information security, as well as virtual and augmented reality systems. When he’s not working he’s hiking, camping, or creating video games.

Related Posts

Albert Qian
— June 19, 2018

Preparing for the Microsoft Azure 70-535 Exam

The credibility of Microsoft Azure continues to grow in the first quarter of 2018 with an increasing number of enterprises migrating their workloads, resulting in a jump for Azure from 10% to 13% in market share. Most organizations will find that simply “lifting and shifting” applicatio...

Read more
  • Azure
  • Compute
  • Database
  • Security
— December 19, 2017

Database News: 7 Updates from AWS re:Invent 2017

Following AWS re:Invent 2017, we’ve counted more than 40 announcements of new or improved AWS services.  Today, we’ll be talking about our picks for the new database and storage services that should be on your radar for 2018.What’s New in the Database world?If you’re into Magic Q...

Read more
  • AWS
  • Database
  • reInvent17
— August 25, 2016

How to Migrate Your SQL Server Database to Amazon RDS

Amazon RDS is a web service that provides cloud database functionality for developers looking for a cost-effective and simple way to manage databases. If you're looking to migrate your existing SQL database to RDS, this is the guide for you.RDS offers six database engines: Amaz...

Read more
  • Database
— July 24, 2015

AWS Database Options

There's an AWS database solution for just about any project you can imagine: the trick is properly understanding the job each of them does best.Got data? There's an AWS database with your name on it.Importing an existing MySQL, Oracle, Microsoft SQL, or PostgreSQL database into Amaz...

Read more
  • AWS
  • Database
— March 19, 2015

Two new Cloud Academy courses: AWS database and AWS networking fundamentals

AWS Database Fundamentals and  AWS Networking FundamentalsCloud Academy has just released two new courses from our Amazon Web Services Learning Tracks series. Now, in addition to the general introductory course, AWS Technical Fundamentals (AWS 110), you can also take AWS Networking Fu...

Read more
  • AWS
  • Database
  • Networking & CDN
— October 29, 2014

Part 2 of our course "Databases on AWS" now available

As I announced a few days ago, the second part of our great course "Database on AWS" is now available. The first part that we launched just a couple days ago and focusing on AWS RDS and DynamoDB got an overwhelming success, and I'm sure you'll like this new episode as well.In the secon...

Read more
  • AWS
  • Database
— October 27, 2014

Databases on AWS: a new course now available!

After the great success of our course Storage on AWS, I am really happy that we are just publishing a brand new course focused on Databases on AWS, an extremely interesting topic for many of you out there. This course is quite a long one and we split it into two parts: part 1 has just b...

Read more
  • AWS
  • Database
— October 8, 2014

New CloudAcademy lab: Create your first Amazon RDS database

Thanks to the commendable work of our Senior Devops Engineer Antonio Angelino, we are launching the third laboratory of our platform, and this time it is about AWS RDS, to get you started with your first RDS database.Labs are one of the most interesting features of our platform. They ...

Read more
  • AWS
  • Database