The Damn Vulnerable Web App (DVWA) is a tool made by DigiNinja to help security professionals and developers alike find and exploit Web Application Vulnerabilities. It’s a great tool and worth checking out if you haven’t already.
Results of StackHawk’s Dynamic Application Security Test (DAST) scan of the Damn Vulnerable Web App.
Below are the details on how you can test StackHawk with the DVWA yourself. Note that this whole process can be done in ~10 minutes and provides a great example of how StackHawk works.
Initial Set Up
StackHawk is built to find security bugs in a running application. To get DVWA up and running, I went the easy route and deployed the web app via a Docker container. This gave me the freedom to use the app and not worry about fiddling with a LAMP stack. The default docker instructions docker run --rm -it -p 8080:80 kaakaww/dvwa-docker
exposes DVWA to the host machine interfaces on port 8080, including http://localhost:8080/. From there, I could easily log in to the web interface and ensure everything was working as expected.
If you’re following along at home, that docker image is ready to go. Log in and start using it or scanning using username: admin
and password: password
Starting a StackHawk Scan
To start, if you don’t have an API key, please make your way over to https://stackhawk.com and signup to get access. Once you have an API key and have defined an application and received the applicationId for your test you are ready to configure the scanner.
StackHawk has a simplified configuration file written in YAML to make implementation easier and scalable. Automating scanning across the wide variety of applications out there introduces significant complexity, but we’ve simplified the configuration so you can get up and running quickly.
Since we know the application lives on http://localhost:8080/, the beginning of our config file (stackhawk.yml) should look something like this:
app:
applicationId: {your applicationID uuid}
env: Development
# The url of the application to scan
host: http://localhost:8080 # (required)
hawk:
# # The web crawler / spider configuration
spider:
# # Enable the base spider for discovering your app's routes
base: true # (default)
Within this section of our config file, we tell the scanner what the StackHawk applicationId is, what environment DVWA is running in, where the application can be found and what web crawling to do. In this instance, DVWA is a PHP application, so the base spider will work nicely to find and parse links and forms in the page (we support single page apps too – check out the docs). If we save this file to a directory on our local computer, say ~/dvwatest/
, we can then begin a scanning run. To start StackHawk with our stackhawk.yml file defined, we simply run the command:
cd ~/dvwatest/
docker run --rm -v $(pwd):/hawk:rw -it stackhawk/hawkscan:latest stackhawk.yml
Since all of the functionality of the web app is behind Form/Session authentication, running HawkScan at this point only discovers the login.php page. While that part is nifty, there’s no real meat there.
DVWA comes with a default admin user that we set the password for in the beginning part of the article. Reviewing the login form, there is Login, the name of the Submit button with the value Login. It’s important for StackHawk to know that, because that’s how it will try to log in. There are also three different fields submitted:
Username
Password
user_token
The first two fields are fairly self explanatory. The third field, user_token, is the CSRF field that helps prevent form stuffing, or automated attempts to bypass the login page. The value for user_token is generated by the server and displayed in the page. The server expects that value back when the user attempts a login to validate the form was read and submitted in a regular fashion. It’s important for StackHawk to know the user_token as well so it can scrape the login page, find the value, pass it back to the server and complete the CSRF challenge. With all these additions, our config file is starting to look a bit more robust.
We also need to set up some of the authentication parameters for the scanner to be able to log into the DVWA. We know it uses Form based authentication.
When we made HawkScan, one the the things we wanted to improve was the Authentication process. The base scanner is sort of agnostic to whether or not your authentication worked and getting feedback to tell if authentication actually worked is at best, difficult. We’ve made that process better in the authentication section. We ask for a URL and a response code that should be accessible after authentication. When those succeed, the scanner continues. If they don’t the scanner stops and give you feedback about what didn’t go correctly in authentication.
app:
applicationId: {your applicationID uuid}
env: Development
# The url of your application to scan
host: http://localhost:8080 # (required)
# # The name of your anti csrf parameter
antiCsrfParam: user_token # here we define the CSRF field name so the scanner can pick it up
# # Form POST based authentication configuration for scanning as a user.
# # Enabling will force the scanner to scan as an
# # authenticated user of your app.
# # Authenticated requests will pass cookies received from the form POST
# # to maintain authentication.
authentication:
# # A regex to match against http responses to determine if the scan user is
# # still logged in to your app
loggedInIndicator: "\\QLogout\\E" # (required)
# # A regex to match against http responses to determine if the scan user is
# # logged out of your app
loggedOutIndicator: "\\QloginInput\\E" # (required)
# # A page that is only accessible being logged in. We will try to access this page
# # to validate authentication worked
testPath:
path: /vulnerabilities/javascript/
type: HEADER
success: ".*200.*"
usernamePassword:
type: FORM # (optional)
# # The route to a form POST to authenticate a user
loginPath: /login.php # (required)
# # The route to logout a user
logoutPath: /logout.php # (required)
# # The username field name in your authentication form
usernameField: username # (required)
# # The password field name in your authentication form.
passwordField: password # (required)
# # Other parameters that may be required by your log in form
otherParams: # (optional)
- name: Login # The login form parameter is needed to make login work
val: "Login"
- name: "security" # I'm not sure what this does in the app, but scans don't work without it
val: "low"
# # The username to authenticate as when scanning
scanUsername: admin # (required)
# # The password of the scanUsername
scanPassword: password # (required)
hawk:
# # Web crawler / spider configuration
spider:
# # Enable the base spider for discovering your app's routes
base: true # (default)
With this config file, StackHawk knows how to log in to the app. However, when I ran some scans, the results and discovered URLs are not quite what I was expecting. There were not enough URLs and WAY less vulnerabilities than I expected. When investigating the DVWA in my browser, I can see a few things that I must tell StackHawk for it to do a more thorough job.
Browsing to the Logout Menu, the application instantly logs me out. What that means, is the scanner is logging me into the application to do the spidering of the app, browsing the links it can find and logging me out before it can test any of the pages. I need to tell the scanner about these things. My config now looks like this.
app:
applicationId: {your applicationID uuid}
env: Development
# The url of your application to scan
host: http://localhost:8080 # (required)
sessionTokens: # the session cookies DVWA uses in some fashion
- "PHPSESSID"
- "dvwaSession"
# # The name of your anti csrf parameter
antiCsrfParam: user_token # here we define the CSRF field name so the scanner can pick it up
# What pages to not scan
excludePaths:
-"logout.php" # the scanner will log itself out if you don't ignore it
# # Form POST based authentication configuration for scanning as a user.
# # Enabling will force the scanner to scan as an
# # authenticated user of your app.
# # Authenticated requests will pass cookies received from the form POST
# # to maintain authentication.
authentication:
# # A regex to match against http responses to determine if the scan user is
# # still logged in to your app
loggedInIndicator: "\\QLogout\\E" # (required)
# # A regex to match against http responses to determine if the scan user is
# # logged out of your app
loggedOutIndicator: "\\QloginInput\\E" # (required)
# # A page that is only accessible being logged in. We will try to access this page
# # to validate authentication worked
testPath:
path: /vulnerabilities/javascript/
type: HEADER
success: ".*200.*"
usernamePassword:
type: FORM # (optional)
# # The route to a form POST to authenticate a user
loginPath: /login.php # (required)
# # The route to logout a user
logoutPath: /logout.php # (required)
# # The username field name in your authentication form
usernameField: username # (required)
# # The password field name in your authentication form.
passwordField: password # (required)
# # Other parameters that may be required by your log in form
otherParams: # (optional)
- name: Login # The login form parameter is needed to make login work
val: "Login"
- name: "security" # I'm not sure what this does in the app, but scans don't work without it
val: "low"
# # The username to authenticate as when scanning
scanUsername: admin # (required)
# # The password of the scanUsername
scanPassword: password # (required)
hawk:
# # Web crawler / spider configuration
spider:
# # Enable the base spider for discovering your app's routes
base: true # (default)
Now we are starting to get better results, but something is still missing causing the scanner to not find all the links and test the pages. While we have described our application well, the scanner is still doing something incorrectly with the session when spidering links in the app. We can tell it to not browse or test some of the pages that are giving us trouble. For instance, the setup.php page has a button that rebuilds the entire database, that’s probably not helping our cause. Also, the security.php page has a button that turns on PHPIDS and make the app more secure and while that’s great, it makes our test not work well. The last one we are concerned about is the /vulnerabilities/csrf/
path that has the ability to change the users password. While that doesn’t affect the current scan, the scanner will change the password of the user and confuse you a lot!
# Complete configuration for DWVA StackHawk Scan
app:
applicationId: {your applicationID uuid}
env: Development
# The url of your application to scan
host: http://localhost:8080 # (required)
sessionTokens: # the session cookies DVWA uses in some fashion
- "PHPSESSID"
- "dvwaSession"
# # The name of your anti csrf parameter
antiCsrfParam: user_token # here we define the CSRF field name so the scanner can pick it up
excludePaths:
- "/setup.php" # The scanner resets the DB :)
- "/security.php" #the scanner turns on PHPIDS here
- "/vulnerabilities/csrf/*" #this page changes the admin password
- "/logout.php" # the scanner will log itself out if you don't ignore here
# # Form POST based authentication configuration for scanning as a user.
# # Enabling will force the scanner to scan as an
# # authenticated user of your app.
# # Authenticated requests will pass cookies received from the form POST
# # to maintain authentication.
authentication:
# # A regex to match against http responses to determine if the scan user is
# # still logged in to your app
loggedInIndicator: "\\QLogout\\E" # (required)
# # A regex to match against http responses to determine if the scan user is
# # logged out of your app
loggedOutIndicator: "\\QloginInput\\E" # (required)
# # A page that is only accessable being logged in. We will try to access this page
# # to validate authentication worked
testPath:
path: /vulnerabilities/javascript/
type: HEADER
success: ".*200.*"
# # What kind of thing will the browser pass to the server to prove it's logged in
cookieAuthorization:
cookieNames:
- "PHPSESSID"
- "dvwaSession"
usernamePassword:
type: FORM # (optional)
# # The route to a form POST to authenticate a user
loginPath: /login.php # (required)
# # The route to logout a user
logoutPath: /logout.php # (required)
# # The username field name in your authentication form
usernameField: username # (required)
# # The password field name in your authentication form.
passwordField: password # (required)
# # Other parameters that may be required by your log in form
otherParams: # (optional)
- name: Login # The login form parameter is needed to make login work
val: "Login"
- name: "security" #I'm not sure what this does in the app, but scans don't work without it
val: "low"
# # The username to authenticate as when scanning
scanUsername: admin # (required)
# # The password of the scanUsername
scanPassword: password # (required)
hawk:
# # Web crawler / spider configuration
spider:
# # Enable the base spider for discovering your app's routes
base: true # (default)
Now we have a working config for DVWA and can effectively scan the app and get results from the scanner. All of the results of these scans should be viewable from the direct link printed at the end of the scan in the terminal. From there you should be able to browse each of the issue and find the request response pairs that made an alert trigger.
While the iteration to make this work was not difficult, you do need to understand how the application behaves and what things could be causing the scanner to not be able to do its job. Now we have a working config for DVWA and can effectively scan the app and get results from the scanner. To test StackHawk scanning the Damn Vulnerable Web App or your own application, sign up for an account at stackhawk.com