{"id":48672722,"url":"https://github.com/Tw1sm/spraycharles","last_synced_at":"2026-04-26T07:00:46.264Z","repository":{"id":38203602,"uuid":"149113743","full_name":"Tw1sm/spraycharles","owner":"Tw1sm","description":"Low and slow password spraying tool, designed to spray on an interval over a long period of time","archived":false,"fork":false,"pushed_at":"2026-01-30T17:34:18.000Z","size":578,"stargazers_count":218,"open_issues_count":4,"forks_count":37,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-01-31T10:34:26.807Z","etag":null,"topics":["password-guessing","password-spraying","spraying"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tw1sm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-09-17T11:17:47.000Z","updated_at":"2026-01-30T17:34:22.000Z","dependencies_parsed_at":"2024-03-19T14:06:43.091Z","dependency_job_id":null,"html_url":"https://github.com/Tw1sm/spraycharles","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Tw1sm/spraycharles","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tw1sm%2Fspraycharles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tw1sm%2Fspraycharles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tw1sm%2Fspraycharles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tw1sm%2Fspraycharles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tw1sm","download_url":"https://codeload.github.com/Tw1sm/spraycharles/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tw1sm%2Fspraycharles/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32288653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T06:26:00.361Z","status":"ssl_error","status_checked_at":"2026-04-26T06:25:58.791Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["password-guessing","password-spraying","spraying"],"created_at":"2026-04-10T13:00:21.814Z","updated_at":"2026-04-26T07:00:46.259Z","avatar_url":"https://github.com/Tw1sm.png","language":"Python","funding_links":[],"categories":["Password Generation"],"sub_categories":["Spraying Tools"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cp align=\"center\"\u003e\n    \u003cimg height=250 src=.resources/spraycharles.jpeg\u003e\n  \u003c/p\u003e\n\n  \u003ch1 align=\"center\"\u003eSpraycharles\u003c/h1\u003e\n  \n  \u003cp align=\"center\"\u003e\n    \u003ci\u003e\n      hey, yo I'm feeling like spraycharles - Chiddy Bang\n    \u003c/i\u003e\n  \u003c/p\u003e\n  \u003cspan align=\"center\"\u003e\n\n    \n![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge\u0026logo=python\u0026logoColor=ffdd54)\n![PyPi](https://img.shields.io/pypi/v/spraycharles?style=for-the-badge)\n    \n  \u003c/span\u003e\n\u003c/p\u003e\n\nLow and slow password spraying tool, designed to spray on an interval over a long period of time. \n\nIncludes spraying plugins for `Office365`, `OWA`, `EWS`, `Okta`, `ADFS`, `Cisco SSL VPN`, `Citrix Netscaler`, `Sonciwall`, `NTLM over HTTP`, and `SMB`.\n\nAssociated [blog post](https://www.sprocketsecurity.com/blog/how-to-bypass-mfa-all-day) by [@sprocket_ed](https://twitter.com/sprocket_ed) covering NTLM over HTTP, Exchange Web Services and Spraycharles.\n\n### What is this tool?\nSpraycharles is a relatively simple password sprayer, designed at a time when there weren't many publicly available tools enabling password spraying to be a non-manual process over the course of a penetration test. Maybe the best feature of Spraycharles is the ability to setup a long running spray using `-a/--attempts` and `-i/--interval`, and let it run over the couse of several days, while periodically checking on it. If you have a one-off service or something unique to spray, it's also very easy to template a new module and start spraying.\n\n### What is this tool not?\nSpraycharles was not initially designed with modern authentication/cloud providers in mind. If you're looking for more advanced features, you may want to check out tools such as [CredMaster](https://github.com/knavesec/CredMaster) or [TeamFiltration](https://github.com/Flangvik/TeamFiltration) Spraycharles was not designed to be _fast_ - it is single threaded and geared towards more of a volume/time approach.\n\n## Install\nSpraycharles can be installed with `pip3 install spraycharles` or by cloning this repository and running `pip3 install .`\n\n\u003e [!TIP]\n\u003e This will register the `spraycharles`, and `sc` for short, aliases in your path. Log and output files are stored in `~/.spraycharles`. An alternative output location can be specified with a CLI flag.\n\n### Using Docker\nExecute the following commands to build the Spraycharles Docker container:\n\n```bash\ngit clone https://github.com/Tw1sm/spraycharles\ncd spraycharles/extras\ndocker build . -t spraycharles\n```\n\nExecute the following command to use the Spraycharles Docker container:\n\n```bash\ndocker run -it -v ~/.spraycharles:/root/.spraycharles spraycharles -h\n```\n\nYou may need to specify additional volumes based on where username a password lists are being stored.\n\n### NixOS\n\nFor Nix or NixOS users is a package available. Keep in mind that the latest releases might only\nbe present in the `unstable` channel.\n\n```bash\nnix-env -iA nixos.spraycharles\n```\n\n## Usage\nThe `spray` subcommand:\n```\n Usage: spraycharles spray [OPTIONS] COMMAND [ARGS]...\n\n Low and slow password spraying\n\n╭─ Options ─────────────────────────────────────────────────────────────────────────────╮\n│ --debug                 Enable debug logging (overrides --quiet)                      │\n│ --config          TEXT  Configuration file.                                           │\n│ --help    -h            Show this message and exit.                                   │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n╭─ User/Pass Config ────────────────────────────────────────────────────────────────────╮\n│ *  --usernames  -u      TEXT  Filepath of the usernames list [default: None]          │\n│                               [required]                                              │\n│ *  --passwords  -p      TEXT  Single password to spray or filepath of the passwords   │\n│                               list                                                    │\n│                               [default: None]                                         │\n│                               [required]                                              │\n│    --equal      -e            Does 1 spray for each user where password = username    │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n╭─ Spray Target ────────────────────────────────────────────────────────────────────────╮\n│    --host      -H      TEXT                           Host to password spray (ip or   │\n│                                                       hostname). Can by anything when │\n│                                                       using Office365 module - only   │\n│                                                       used for logfile name           │\n│                                                       [default: None]                 │\n│ *  --module    -m      [ADFS|CiscoSSLVPN|Citrix|NTLM  Module corresponding to target  │\n│                        |Office365|Okta|OWA|SMB|Sonic  host                            │\n│                        wall]                          [default: None]                 │\n│                                                       [required]                      │\n│    --path              TEXT                           NTLM authentication endpoint    │\n│                                                       (i.e., rpc or ews)              │\n│                                                       [default: None]                 │\n│    --port      -P      INTEGER                        Port to connect to on the       │\n│                                                       specified host                  │\n│                                                       [default: 443]                  │\n│    --fireprox  -f      TEXT                           URL of desired fireprox         │\n│                                                       interface                       │\n│                                                       [default: None]                 │\n│    --domain    -d      TEXT                           HTTP - Prepend DOMAIN\\ to       │\n│                                                       usernames; SMB - Supply domain  │\n│                                                       for smb connection              │\n│                                                       [default: None]                 │\n│    --no-ssl                                           Use HTTP instead of HTTPS       │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n╭─ Output ──────────────────────────────────────────────────────────────────────────────╮\n│ --output   -o      TEXT  Name and path of result output file [default: None]          │\n│ --quiet                  Will not log each login attempt to the console               │\n│ --analyze                Run the results analyzer after each spray interval (Early    │\n│                          false positives are more likely)                             │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n╭─ Spray Behavior ──────────────────────────────────────────────────────────────────────╮\n│ --attempts    -a      INTEGER  Number of logins submissions per interval (for each    │\n│                                user)                                                  │\n│                                [default: None]                                        │\n│ --interval    -i      INTEGER  Minutes inbetween login intervals [default: None]      │\n│ --timeout     -t      INTEGER  Web request timeout threshold [default: 5]             │\n│ --jitter              INTEGER  Jitter time between requests in seconds                │\n│                                [default: None]                                        │\n│ --jitter-min          INTEGER  Minimum time between requests in seconds               │\n│                                [default: None]                                        │\n│ --pause                        Pause the spray between intervals if a new potentially │\n│                                successful login was found                             │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n╭─ Notifications ───────────────────────────────────────────────────────────────────────╮\n│ --notify   -n      [Slack|Teams|Discord]  Enable notifications for Slack, Teams or    │\n│                                           Discord                                     │\n│                                           [default: None]                             │\n│ --webhook  -w      TEXT                   Webhook used for specified notification     │\n│                                           module                                      │\n│                                           [default: None]                             │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n```\n\n### Config File\nDue to the amount of CLI flags often used, an alternative is to populate command line parameters from a yaml file using the `--config` flag. Additionally, each time you use Spraycharles, your CLI options will be written to a yaml file (`last-config.yaml`) in the current directory for easy modification and reuse.\n\n### Notifications\nSpraycharles has the ability to issue notifications to Discord, Slack and Microsoft Teams following a potentially successful login attempt. This list of notification providers can augmented using the utils/notify.py script. For any of the potential notification agents, you must specify its name and a webhook URL.\n\nYou can specify these using the configuration file to keep your command shorter:\n\n```yaml\nnotify: Slack\nwebhook: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX\n```\n\nNotifications sent to any of the providers will include the targeted hostname associated with the spraying job. This is expecially useful when spraying multiple targets at once.\n\n### Updating Username/Password Files\nYou have the ability to make changes to the provided username and password files while the spray is in progress. Additions or removals to the lists will take effect on the next password rotation\n\n\u003e [!NOTE]\n\u003e If you insert a new password into the list, it must be _after_ the password being currently sprayed, in order to be sprayed (Spraycharles keeps an internal loop counter used as an index to pull the next password at the corresponding place in the updated list)\n\n\n## Utilities\nSpraycharles is packaged with some additional utilities to assist with spraying efforts. Full list of Spraycharles modules:\n```\n Usage: spraycharles [OPTIONS] COMMAND [ARGS]...\n\n╭─ Options ─────────────────────────────────────────────────────────────────────────────╮\n│ --help  -h        Show this message and exit.                                         │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n╭─ Commands ────────────────────────────────────────────────────────────────────────────╮\n│ analyze   Analyze Spraycharles output files for potential spray hits                  │\n│ gen       Generate custom password lists from JSON file                               │\n│ modules   List spraying modules                                                       │\n│ parse     Parse NTLM over HTTP and SMB endpoints to collect domain information        │\n│ spray     Low and slow password spraying                                              │\n╰───────────────────────────────────────────────────────────────────────────────────────╯\n```\n\n### Generating Custom Spray Lists\nThe Spraycharles \"gen\" subcommand will generate a password list based off the specifications provided in extras/list_elements.json\n\n```bash\nspraycharles gen extras/list_elements.json custom_passwords.txt\n```\n\n### Extracting Domain from NTLM over HTTP and SMB\nThe Spraycharles parse subcommand will extract the internal domain from both NTLM over HTTP and SMB services using a command similar to the one listed below.\n\n```bash\nspraycharles parse https://example.com/ews\nspraycharles parse smb://host.domain.local\n```\n\n### Analyzing Result Files\nThe `analyze` submodule can read your output JSON objects and determine response lengths that are statistically relevant. With enough data, it should be able to pull successful logins out of your results file. This is not the only way to determine successful logins, depending on your target site, and I would still recommend checking the data yourself to be sure nothing is missed. For SMB, it will simply find entries with NTSTATUS codes that indicate success.\n\n```bash\nspraycharles analyze myresults.json\n```\n\n## Disclaimer\nThis tool is designed for use during penetration testing; usage of this tool for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse of this program.\n\n## Development\nSpraycharles uses Poetry to manage dependencies. Install from source and setup for development with:\n\n```bash\npip3 install poetry\ngit clone https://github.com/Tw1sm/spraycharles\ncd spraycharles\npoetry install\n```\n\n## Credits\n- [@sprocket_ed](https://twitter.com/sprocket_ed) for contributing: several spray modules, many of features that make spraycharles great, and the associated blog post\n- [@b17zr](https://twitter.com/b17zr) for the `ntlm_challenger.py` script, which is included in the `utils` folder\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTw1sm%2Fspraycharles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTw1sm%2Fspraycharles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTw1sm%2Fspraycharles/lists"}