A Gentle Introduction to Credential Stuffing on HTTP Basic Authentication

Credential stuffing is an attack often linked to widely-known data breaches, where credentials are leaked for applications available over the internet such as social networks and e-mail clients. However while performing a security assessment of a specific application or network, one may come across credentials stored in plain-text files or wikis that are available from within the private network. Unprotected credentials in plain-text are a problem within itself, however as a penetration tester, one will be looking to use such credentials to gain access for another applications and services.

Throughout this article it will be presented a scenario where credentials were found in an internal wiki with information about a particular application. Using a simple Python script we will able to automate the credential stuffing process and gain access to the application. An important disclaimer is that the described scenario is fictional, only used to illustrate how credential stuffing can be exploited in the wild.

Using Python 3’s requests module one can easily create GET requests to a given application, and combining with the lack of control for authentication attempts that many web applications present, one can execute the credential stuffing process until it finds a valid credential or it finishes its execution. Credential stuffing is a tricky process if the application being tested implements brute-force mitigations, however even in those scenarios one can find a bypass, similar to CVE-2019-17240.

Alright, let’s get to the fun part: the code. As you can see it’s quite simple to create a script to automate the process. In this particular scenario I had to try all passwords found for all users, therefore the for loop iterating over the password list file is inside the for loop iterating over the user list file. The tryAuthentication function is responsible for performing the GET request to the application and verifying if the HTTP return code is different than 401, if that is the case the script stops and returns which user and password combination can be used to access the application.

 

 

There are many improvements that can be made in this script, especially when it comes to making it more interactive and flexible such as a command-line tool. If you are interested in improving the script feel free to create a pull-request in the repository.