Hi there,
I hope you are doing well.
In this article, I’ll discuss how I found a bug in a private program on HackerOne.
Denial of Service, or simply DoS, is a type of attack, in which the attacker sends multiple requests to the server to make the server crash or add a significant delay in the response timings for all the users.
This can lead to business loss as the customers of that website won’t be able to access the website and perform the actions, like buying things if it’s an e-commerce site, chatting with other people if it’s a public forum-like software, etc.
The request, that is sent to the server, is generally to cause DoS is generally specially crafted which adds a significant delay in the response timing.
This makes the server spend more resources on the attacker’s specially crafted request, and the genuine customer’s request will be allotted fewer resources, leading to a complete denial of service or causing a delay
In this section of the article, we will discuss what happens when you click the login button. This includes the processes that happen on the server side.
For any web application to prevent user passwords from being leaked in plaintext (not as hash) even after a data breach, companies store their password in the form of hashes.
These are some special functions, that convert strings of any length to a fixed length string.
You can convert a string into a hash, but you can’t do vice-versa.
Taking the example of MD5, you can convert the string “password” into MD5 hash “5f4dcc3b5aa765d61d8327deb882cf99”, but you can’t convert “5f4dcc3b5aa765d61d8327deb882cf99” directly into “password”
Hashing is a complex process. It involves heavy calculation. Though the example demonstrated here, i.e. of MD5 hash function, takes less time as compared to other functions, it’s considered a bit insecure, but still it gives a good load on the CPU.
Getting back on to the point of what happens after clicking login.
A request is sent to the server, involving the username and the password specified by the user.
The password is either converted into a hash on the front end only (with the help of Javascript functions), or they are sent as plaintext (generally over HTTPS) to the server, which then calculates the hash of the password.
If the hash is being calculated on the front end only, then there are negligible chances that the server would be vulnerable to this attack.
For this attack to happen, the server must calculate the hash for the string provided
The longer the string is, the more time and CPU power it will consume to calculate the hash.
This means we have to send a long string to the application.
Now, once we know what happens on the backend, you should’ve figured out how to cause a DoS
We just need to send a long string in the parameter for the password.
For this example, let’s consider the following request:-
POST /login
Host: www.target.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
--snip--
Content-Length: 123username=*****&password=********
In the request given above, the parameter containing the password is password
.
But before we send a long string, exactly how long is a long string?
Well, it depends upon the server. If the server has implemented some good hashing algorithms, then it will take more time, and vice-versa.
Generally, passwords of more than 10000 characters should be tested, by increasing the length of the string.
The following Python script can get your work done:-
for x in range(50000, 500000, 10000): #start:as it is , stop: as per your system's limit and considering the server load, step: value greater than 10K recommended
print("a"*x)
The above Python script will generate characters of length between 50K to 500K, with a difference of 10K between each string.
You can save the script, run it, and save the output of this to a file:-
python3 generate.py > lst.txt
This means the first line of the output will contain 50K characters, the second line will have 60K, and so on.
The timing can be tested by using web application proxies like Burp, ZAP, or Caido.
In my case, I’ve used caido, as it’s a very lightweight proxy compared to others.
Now, I’ll just fire up my web application proxy, which is Caido (not a promotion).
In the browser, I’ll open up the target, and head over to the login page, i.e. https://www[.]target[.]com/login
After filling in all the details on the login page, I’ll send the request for login, which in our example is POST /login
to automate (intruder in Burp). After marking the payload position (the password
parameter), I’ll set the payload type to “Simple List”, and I’ll load the output file for the above Python code
Now, I’ll simply start the attack, and inspect the response timing for the requests
In the above screenshot, you can see that as the request ID is increasing, the response time is also increasing. This means that the server is vulnerable to this attack
Now, the attacker needs to just keep sending the requests, with a higher number of workers (at a very fast rate) and ultimately, it will cause a DoS on the server.
Note that to demonstrate impact on the server, you don’t need to cause a DoS. This is also out of scope for programs to cause an actual DoS (though they might accept DoS vulnerabilities). Just showing the difference in response time is enough.
If you’ve found a vulnerability at one place, there are chances that you can find the same vulnerability at other places on the web app.
Following are some more places that are worth checking if you’ve found this type of vulnerability:-
## Summary
An attacker can cause DoS on the server by sending multiple login requests with long passwords## Steps to reproduce
If you are using some GUI tool, make sure your system is capable enough of that. If not, please keep the character limit lower in the attack else your system will crash.
- Save the following Python script
```python
for x in range(50000, 500000, 10000): #start:as it is , stop: as per your system's limit and considering the server load, step: value greater than 10K recommended
print("a"*x)
```
- Adjust the limits as per your system
- Now, head over to <login_page_url>
- Capture the login request.
- Now, set the output of the Python script given above as the payload (in burp/ZAP/caido)
- Start replaying the request
- As the length of the payload increases, the response time also increases
If you want, you can also use the CLI, copy the request as cURL (right click > copy as cURL in all proxies), and modify the request as per your choice (remove garbage, etc). To make the length of the password big, use the following
```bash
curl .... -d "username=****&password=$(python3 -c 'print("a"*20000)')"
```
## Screenshot
<add screenshot from the intruder in burp>
## References
- [Possible denial of service when entering a loooong password - Nextcloud](https://hackerone.com/reports/840598)
- [No length on password - Imgur](https://hackerone.com/reports/1411363)
## Impact
An attacker can cause DoS on the system causing business losses
## Remediation
Before calculating the hash for the password on the server, make sure the length is less than what is set when storing the password