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!