example - synacktiv/captaincredz GitHub Wiki
Learning CaptainCredz by example
This part is a small exercise to practice using CaptainCredz, in a local "lab" environment. This will help you to learn the basic concepts of CaptainCredz.
Setting up the "lab"
You can spin up the CaptainCredz test server locally. This server will be the target of our spraying.
$ python3 tests/app.py
The server listens on 0.0.0.0:28514 on your machine.
Configuring CaptainCredz to attack our test server
A test
plugin, tailored for our test web server, is available in CaptainCredz. It asks for a url
parameter.
An appropriate config file for this spray can look like the following:
{
"plugins" : [
{
"name": "test",
"args": {
"url": "http://127.0.0.1:28514"
}
}
],
"userfile" : "tests/wordlists/users.txt",
"passwordfile" : "tests/wordlists/passwords.txt",
"userpassfile" : "tests/wordlists/userpass.txt",
"jitter" : 5,
"delay_req" : 5,
"delay_user" : 30,
"stop_on_success": true,
"verbose" : true
}
This configuration makes use of CaptainCredz test word lists, and applies a random delay of 5 to 10 (= 5+5) seconds between any two authentication requests, with no less than 30 seconds between two authentication requests for the same user.
Getting our first credz
Let's run CaptainCredz with this config:
$ python3 captaincredz.py --config config.json
[01/30/25 13:21:19] DEBUG DEBUG - [test] Testing network connection... logger.py:45
DEBUG DEBUG - [test] Plugin test connection successful! logger.py:45
DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'passFromUserPass'} logger.py:45
INFO INFO - 2025-01-30T13:21:19 - test - failure ([email protected]:passFromUserPass) / [-] FAIL: [email protected]:passFromUserPass logger.py:65
[01/30/25 13:21:25] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'otherPassword'} logger.py:45
INFO INFO - 2025-01-30T13:21:25 - test - success ([email protected]:otherPassword) / [+] SUCCESS: [email protected]:otherPassword logger.py:65
INFO INFO - Stopping on first success according to configuration option stop_on_success logger.py:48
INFO INFO - Stopping gracefully, please wait... logger.py:48
INFO INFO - All cleaned up! Just waiting for workers to finish their current tasks, you may kill them with another CTRL+C if it is taking too long logger.py:48
[01/30/25 13:21:27] DEBUG DEBUG - Workers are all finished, will not return any more credz... logger.py:45
INFO INFO - No more creds to test logger.py:48
DEBUG DEBUG - All workers have successfully stopped logger.py:45
Spraying... ━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3% -:--:--
So, what happened here ?
First, CaptainCredz instantiated a worker for our test plugin. The first two lines in the output are related to this instantiation, where CaptainCredz will try to validate if the plugin configuration is correct by actually attempting an HTTP request to our test target.
After that, the actual spraying begins. The first line popping (Current candidate is [...]
) is displayed just before the authentication attempt is performed, and announces what's coming next. The second one (the INFO
one) is displayed as soon as the result of the authentication attempt is available. In this case, it came out as a failure
(as the password is incorrect). CaptainCredz then waited for approximately 6 seconds before performing a second authentication attempt. This time, it came out as a success
! As we instructed CaptainCredz to stop_on_success
in the configuration, it then shut down gracefully.
Gotta catch 'em all !
Let's remove the "stop_on_success": true
line from our config and re-launch the spray :
$ python3 captaincredz.py --config config.json
[01/30/25 13:35:29] DEBUG DEBUG - [test] Testing network connection... logger.py:45
DEBUG DEBUG - [test] Plugin test connection successful! logger.py:45
DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'passFromPassFile'} logger.py:45
INFO INFO - 2025-01-30T13:35:29 - test - failure ([email protected]:passFromPassFile) / [-] FAIL: [email protected]:passFromPassFile logger.py:65
[01/30/25 13:35:37] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'passFromPassFile'} logger.py:45
INFO INFO - 2025-01-30T13:35:37 - test - failure ([email protected]:passFromPassFile) / [-] FAIL: [email protected]:passFromPassFile logger.py:65
[01/30/25 13:35:43] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'passFromPassFile'} logger.py:45
INFO INFO - 2025-01-30T13:35:43 - test - inexistant ([email protected]:passFromPassFile) / [-] User [email protected] does not exist logger.py:65
DEBUG DEBUG - Trimming [email protected] logger.py:45
[01/30/25 13:35:53] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'passFromPassFile'} logger.py:45
INFO INFO - 2025-01-30T13:35:53 - test - inexistant ([email protected]:passFromPassFile) / [-] User [email protected] does not exist logger.py:65
DEBUG DEBUG - Trimming [email protected] logger.py:45
[01/30/25 13:36:01] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'passFromPassFile'} logger.py:45
INFO INFO - 2025-01-30T13:36:01 - test - inexistant ([email protected]:passFromPassFile) / [-] User [email protected] does not exist logger.py:65
DEBUG DEBUG - Trimming [email protected] logger.py:45
[01/30/25 13:36:08] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'user1!'} logger.py:45
INFO INFO - 2025-01-30T13:36:08 - test - success ([email protected]:user1!) / [+] SUCCESS: [email protected]:user1! logger.py:65
DEBUG DEBUG - Trimming [email protected] logger.py:45
[01/30/25 13:36:16] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'user1!'} logger.py:45
INFO INFO - 2025-01-30T13:36:16 - test - failure ([email protected]:user1!) / [-] FAIL: [email protected]:user1! logger.py:65
[01/30/25 13:36:50] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'blahblah'} logger.py:45
INFO INFO - 2025-01-30T13:36:50 - test - failure ([email protected]:blahblah) / [-] FAIL: [email protected]:blahblah logger.py:65
[01/30/25 13:37:25] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'test'} logger.py:45
INFO INFO - 2025-01-30T13:37:25 - test - failure ([email protected]:test) / [-] FAIL: [email protected]:test logger.py:65
[01/30/25 13:38:00] DEBUG DEBUG - Current candidate is {'username': '[email protected]', 'password': 'Uz3r2@'} logger.py:45
INFO INFO - 2025-01-30T13:38:00 - test - success ([email protected]:Uz3r2@) / [+] SUCCESS: [email protected]:Uz3r2@ logger.py:65
DEBUG DEBUG - Trimming [email protected] logger.py:45
[01/30/25 13:38:02] INFO INFO - No more creds to test logger.py:48
DEBUG DEBUG - All workers have successfully stopped logger.py:45
Spraying... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
The output is longer this time.
A few remarks on this run, unordered:
- CaptainCredz has a built-in cache mechanism (a file
cache.db
should have appeared in your current directory the first time you ran CaptainCredz). With this file, CaptainCredz keeps track of authentication attempts across runs. Now remember that during our first run, we found valid credentials for the user[email protected]
. There is no need to re-spray this user! As such, you can see that no authentication attempt was performed for this user on the second run. Same goes for the pair[email protected]
:passFromUserPass
, which we already know is a failure from the first run. It was instantly skipped on this second run. - The timing requirements are tight. No two authentication attempts were performed with less than a 5 seconds delay, and no two authentication attempts on the same user were performed with less than a 30 seconds delay.
- In case the
test
plugin was able to determine a user was inexistant (for example, with a different error message), it "trimmed" the user. This means that the user is discarded, and no more tests will be performed on it. - In case of a successful attempt (valid credentials found), the user is trimmed as well. Indeed, there is no need to spray a user if we already found their password.
Congratulations, you have found valid credentials for all users of this test server :smile: If you want to continue practicing with CaptainCredz, you will have to either (re)move the cache file, or specify another name for it (with the cache_file
config option) so that CaptainCredz creates a new cache file for your new run.
Note that this workshop only covered basic concepts of CaptainCredz. More advanced concepts like post-actions and the WeekDay Warrior mode are detailed in the documentation. Feel free to try them on this local setup before attempting them on real targets.
Have fun using CaptainCredz!