{"id":13780622,"url":"https://github.com/Accenture/jenkins-attack-framework","last_synced_at":"2025-05-11T13:32:43.071Z","repository":{"id":37628066,"uuid":"364371887","full_name":"Accenture/jenkins-attack-framework","owner":"Accenture","description":null,"archived":false,"fork":false,"pushed_at":"2021-05-11T13:47:56.000Z","size":100,"stargazers_count":555,"open_issues_count":0,"forks_count":62,"subscribers_count":17,"default_branch":"master","last_synced_at":"2024-11-12T09:29:52.322Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Accenture.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-04T20:01:00.000Z","updated_at":"2024-11-01T06:42:19.000Z","dependencies_parsed_at":"2022-09-06T09:11:10.413Z","dependency_job_id":null,"html_url":"https://github.com/Accenture/jenkins-attack-framework","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fjenkins-attack-framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fjenkins-attack-framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fjenkins-attack-framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Accenture%2Fjenkins-attack-framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Accenture","download_url":"https://codeload.github.com/Accenture/jenkins-attack-framework/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225056844,"owners_count":17414222,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-08-03T18:01:17.968Z","updated_at":"2024-11-17T15:31:22.186Z","avatar_url":"https://github.com/Accenture.png","language":"Python","readme":"Jenkins Attack Framework\n============================\n\n## Description\n\nThis project can currently perform the following tasks:\n\n* **AccessCheck:** Test credentials and provide a rough overview of their access levels\n\n* **ConsoleOutput:** Dump the console output of the last build of every job on the server (Can be Gigabytes of data, but good for finding credentials)\n\n* **CreateAPIToken:** Creates an API Token for the current user (Or another user if you have administrative credentials)\n\n* **DeleteAPIToken:** Deletes an API Token for the current user (Or another user if you have administrative credentials. Lists existing ones if no token supplied)\n\n* **DeleteJob:** Delete a Job, or failing that, attempt a number of follow-up mitigations from most-to-least effective.\n\n* **DumpCreds:** Dump credentials (Uses administrative credentials to dump credentials via Jenkins Console)\n\n* **DumpCredsViaJob:** Dump credentials via job creation and explicit enumeration (User needs at least Add Job permissions)\n\n* **ListAPITokens:** List existing API tokens for the current user (Or another user if you have administrative credentials)\n\n* **ListJobs:** List existing Jenkins Jobs (Good For finding specific jobs)\n\n* **RunCommand:** Run system command and get output/errors back (Uses administrative credentials and Jenkins Console)\n\n* **RunJob:** Upload a script and run it as a job.  Also run \"Ghost Jobs\" that don't terminate or show up in Jenkins (after launch)\n\n* **RunScript:** Run Groovy scripts (Uses administrative credentials to run a Groovy Script via Jenkins Console)\n\n* **UploadFile:** Upload a file (Uses administrative credentials and chunked uploading via Jenkins Console)\n\n* **WhoAmI:** Get the credentialed user's Jenkins groups (Usually contains their domain groups)\n\n* More things are in the works...\n\n## Installing\n\nRun the following commands: \n\n\tgit clone git@github.com:Accenture/jenkins-attack-framework.git \n\tcd jaf\n\tchmod +x jaf\n\tsudo ./jaf --install\n\t./jaf --install\n\nBefore you can use the RunJob \"ghost job\" feature against Windows Jenkins Slaves, you will need to compile the following file `data/cpp/windows_ghost_job_helper.cpp` using Visual Studio's cl tool (see compile arguments in comment at the top of that file), and then drop the compiled file in `data/exe/windows_ghost_job_helper.exe`.\n\n## Command Line Help\n\nThe commandline help should be pretty straight forward, but is provided here with additional notes:\n\n\tusage: jaf.py \u003cCommand\u003e [-h]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\t\u003cCommand\u003e   Subcommand to run (pass sub command for more detailed help):\n\t\t\t\tAccessCheck ConsoleOutput CreateAPIToken DeleteAPIToken\n\t\t\t\tDeleteJob DumpCreds DumpCredsViaJob ListAPITokens ListJobs\n\t\t\t\tRunCommand RunJob RunScript UploadFile WhoAmI\n\n\toptional arguments:\n\t-h, --help  show this help message and exit\n\n### Common Usage Notes\n\nFor every subcommand, you can get more detailed help by calling JAF with the subcommand and no additional options (or the `-h` option).\n\n#### Server URL\t\n\nFor every command (other than requesting help), the `-s` command is required. This should be the full, base URL to the Jenkins instance.\n\n#### User Agent\n\nJAF will use the following user agent with each request: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36`. This was chosen, at least at the time of this release to fit in. If you wish to use a different user-agent, one can be specified with the `-u` option.\n\n#### Output Redirection\n\nFor every command, you may pass the `-o` option with a file path. If passed, JAF will write all output (with the exception of some fatal or critical errors) to the file instead of stdout. This option is particularly useful on Windows where console redirection tends to break on random bytes unless you change the code page.\n\n#### Credentials\n\nIf no credentials are provided, JAF will attempt to connect with anonymous credentials.\nCredentials can be provided via two methods. To provide a single set of credentials use the `-a` option.\nCredentials can take three forms: `user:password`, `user:apitoken`, or a Cookie string. \n\nIn the case of the latter option, the cookie should include the entire cookie (everthing after \"Cookie: \" in the browser header).\nCookie authentication is particularly useful when the Jenkin server uses federation with another Jenkins server for authentication.\nIn this scenario, normal `user:password` auth will not work. API tokens _may_ still work. If not, authenticate in your browser, then pass the cookie.\nCookie authentication can also include a `Jenkins Crumb`, which should be concatenated to the end of the cookie string to look something like: `JSESSIONID.9922756a=node0rhre4wjrdcjz9m4tbqx0qwqn1567.node0|Jenkins-Crumb=f5cb5472851aad76fc45568ef1e4160928d075376fd78c436a58d39b99aae09a`\n\nThough JAF can usually determine your authentication type by parsing the string, you can also hint the correct type by prepending your credential string with one of the following (self-explanatory) tags: `{USERPASS}`, `{APITOKEN}`, `{COOKIE}` \n\nFor the following two commands, you may pass a single set of credentials using the `-a` option or you may pass multiple credentials with the `-c` option: `AccessCheck` and `WhoAmI`.\nThe `-c` option takes either the path to a file which contains one of the aforementioned credential forms per line, or `-`. If `-` is passed, JAF will take credentials via stdin instead of from a file (formatting remains the same).\n\n#### Timeouts, Threads, and Waiting\n\nHTTP Request Timeouts default to 30 seconds. If you would like a shorter or longer timeout, one can be configured with the `-n` option.\n\nFor certain multi-request methods (`ConsoleOutput`, `AccessCheck`, or `WhoAmI`), the number of threads (and thus number of simultaneous requests) can be configured. By default 4 threads are used. To specify a different number of threads pass the `-t` option.\n\nFor the `RunCommand`, `RunJob`, and `RunScript` methods, in addition to setting a total request timeout, you may pass the `-x` option to explicitly not wait for the request to return. This can be valuable when starting a SOCKS Proxy or similar long running task.\n\n\n### AccessCheck\n\nThis method provides a number of heuristic checks for access levels which are useful for an attacker. A negative result should be accurate. A positive result means that the user potentially has the access, but you will need to perform additonal validation. There are simply too many ways to restrict access in Jenkins and no API for determining granular access levels, so results are not always prefectly accurate.  Currently this method checks for the following access: `Basic Read Access (read)`, `Create Job Access (build)`, `Some level of Admin Access (admin)`, `Script Console Access (script)`, `Scriptler Groovy Script Plugin Access (scriptler)`\n\n\tusage: jaf.py AccessCheck [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-t \u003cThreads\u003e]\n\t\t\t\t[-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\t\t\t\t[-c \u003cCredential File\u003e]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tAccessCheck           Get Users Rough Level of Access on Jenkins Server\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-t \u003cThreads\u003e, --threads \u003cThreads\u003e\n\t\t\t\t\t\t\tNumber of max concurrent HTTP requests. Defaults to: 4\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-c \u003cCredential File\u003e, --credentialfile \u003cCredential File\u003e\n\t\t\t\t\t\t\tCredential File (\"-\" for stdin). Creds in form\n\t\t\t\t\t\t\t\"\u003cUser\u003e:\u003cPassword\u003e\" or \"\u003cUser\u003e:\u003cAPI Token\u003e\"\n\n\n### ConsoleOutput\n\nThis method dumps the console output for the last build of every job that the user can see. You need at least job viewing privileges which is not always possible to determine. This can and often does result in gigabytes (or even terabytes) of output.\n\n\tusage: jaf.py ConsoleOutput [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-t \u003cThreads\u003e]\n\t\t\t\t[-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tConsoleOutput         Get Latest Console Output from All Jenkins Jobs\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-t \u003cThreads\u003e, --threads \u003cThreads\u003e\n\t\t\t\t\t\t\tNumber of max concurrent HTTP requests. Defaults to: 4\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\n\n### CreateAPIToken\n\nUsed to create an API Token for the user who's credentials are supplied. If the `--user` option is passed, this command will instead create an API token for the supplied user (but you must have administrative `/script` console access to do this). \n\n`Token Name` is entirely optional and can be anything even a duplicate of an existing token name. Tokens are shown under the user's `configure` page (`/user/\u003cusername\u003e/configure`), so pick a name that will blend in (or no name). If no `Token Name` is specified and you are creating the token for the current user, Jenkins will pick the name `Token Created on \u003cDate\u003e`. If creating a token with no `Token Name` as an admin for another user (or even yourself while using the `--user` option, the name will actually be blank, and the Jenkins API actually makes this kind of difficult to notice). \n\nOn successful token creation, the new API Token will be printed to the screen. You should capture this, as this token can never be viewed again.\n\n\tusage: jaf.py CreateAPIToken [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\t\t\t\t[-U \u003cUser Name\u003e] [\u003cToken Name\u003e]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tCreateAPIToken        Create an API Token for your user\n\t\u003cToken Name\u003e          Token Name which is shown under the user's\n\t\t\t\t\t\t\tconfiguration page (so pick something that is not too\n\t\t\t\t\t\t\tsuspicious). Can be duplicated (There do not appear to\n\t\t\t\t\t\t\tbe any restrictions on token names). If not provided,\n\t\t\t\t\t\t\tonly token creation date will be shown on user's page.\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-U \u003cUser Name\u003e, --user \u003cUser Name\u003e\n\t\t\t\t\t\t\tIf provided, will use Jenkins Script Console to add\n\t\t\t\t\t\t\ttoken for this user. (Requires Admin \"/script\"\n\t\t\t\t\t\t\tpermissions)\n\n\n### DeleteAPIToken\n\nUsed to delete an API Token for the user who's credentials are supplied. If the `--user` option is passed, this command will instead delete the API token for the supplied user (but you must have administrative `/script` console access to do this). \n\nToken Name or UUID is required to actually delete a token. If not supplied, this function effectively acts like `ListAPITokens` and returns a list of existing tokens. If a `Token Name` is supplied this command will try to delete that token and alert you on success or failure. If the name matches multiple tokens, no token will be deleted, and you will receive an error message. In that case, you should instead list tokens (either by calling `DeleteAPIToken` with no additional arguments, or via calling `ListAPITokens`), then try again with a `Token UUID`. Deleted tokens cannot be restored, so make sure you are certain before attempting.\n\n\tusage: jaf.py DeleteAPIToken [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n              [-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n              [-U \u003cUser Name\u003e] [\u003cToken Name or UUID\u003e]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tDeleteAPIToken        Delete an API Token for your user\n\t\u003cToken Name or UUID\u003e  If not specified, command will return list of tokens\n\t\t\t\t\t\t\tfor subsequent calls.\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-U \u003cUser Name\u003e, --user \u003cUser Name\u003e\n\t\t\t\t\t\t\tIf provided, will use Jenkins Script Console to delete\n\t\t\t\t\t\t\ttoken for this user. (Requires Admin \"/script\"\n\t\t\t\t\t\t\tpermissions)\n\n\n### DeleteJob\n\nAttempts to delete a Jenkins job. If the user does not have the rights, this will instead, attempt to delete all build logs, overwrite the job with a blank job, and then disable the job. \n\n\tusage: jaf.py DeleteJob [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\t\t\t\t\u003cTask Name\u003e\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tDeleteJob             Delete Jenkins Jobs\n\t\u003cTask Name\u003e           Task to Delete\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\n\n### DumpCreds\n\nShould be self explanatory, but this does require administrative credentials with `/script` access.\n\n\tusage: jaf.py DumpCreds [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n              [-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n              [-N \u003cNode\u003e]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tDumpCreds             Dump all Stored Credentials on Jenkins\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-N \u003cNode\u003e, --node \u003cNode\u003e\n\t\t\t\t\t\t\tNode (Slave) to execute against. Executes against\n\t\t\t\t\t\t\t\"master\" if not specified.\n\n### DumpCredsViaJob\n\nDump credentials by creating a Job and explicitly enumerating echoing out all the credentials that are\nstored and accessible to the user. These credentials are then Base64 encoded so as to prevent Jenkins from\nredacting them.  The credentials are retrieved and formatted. User must have at least Job creation privileges.\n\n\tusage: jaf.py DumpCredsViaJob [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e]\n\t\t\t\t[-n \u003cTimeout\u003e] [-o Output File]\n\t\t\t\t[-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]] [-N \u003cNode\u003e]\n\t\t\t\t[-T \u003cNode Type\u003e] \u003cTask Name\u003e\n\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tDumpCredsViaJob       Dump credentials via explicit enumeration of shared\n\t\t\t\t\t\t\tcredentials in a job (Only requires job creation\n\t\t\t\t\t\t\tpermissions and some shared credentials)\n\t\u003cTask Name\u003e           Task to Create, must be unique (may not be deleted if\n\t\t\t\t\t\t\tuser doesn't have job deletion permissions, so pick\n\t\t\t\t\t\t\tsomething that blends in)\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-N \u003cNode\u003e, --node \u003cNode\u003e\n\t\t\t\t\t\t\tNode to execute against. If specified, you must also\n\t\t\t\t\t\t\tpass -T\n\t-T \u003cNode Type\u003e, --nodetype \u003cNode Type\u003e\n\t\t\t\t\t\t\tNode Type, either: \"posix\" or \"windows\". If specified,\n\t\t\t\t\t\t\tyou must also pass -N\n\n\n### ListAPITokens\n\nMethod simply lists all existing API Tokens for the user who's creds you supplied. If the `--user` option is passed, this command will instead list the API tokens for the supplied user (but you must have administrative `/script` console access to do this).\n\nThe actual API Tokens cannot be recovered as only a hash is stored, and only Admin users can even access these hashes. So this method is really only useful for getting a list before trying to use `CreateAPIToken` or `DeleteAPIToken`.\n\n\tusage: jaf.py ListAPITokens [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\t\t\t\t[-U \u003cUser Name\u003e]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tListAPITokens         List API Tokens for your user\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-U \u003cUser Name\u003e, --user \u003cUser Name\u003e\n\t\t\t\t\t\t\tIf provided, will use Jenkins Script Console to query\n\t\t\t\t\t\t\ttokens for this user. (Requires Admin \"/script\"\n\t\t\t\t\t\t\tpermissions)\n\n\n### ListJobs\n\nMethod simply lists all jobs on the server, recursively.\n\n\tusage: jaf.py ListJobs [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tListJobs              Get List of All Jenkins Job Names\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\n\n### RunCommand\n\nThis method wraps passed system commands to capture stdout and stderr and return it. Requires administrative credentials with `/script` access.\n\n\tusage: jaf.py RunCommand [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\t\t\t\t[-x] [-N \u003cNode\u003e] \u003cSystem Command\u003e \n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tRunCommand            Run System Command on Jenkins via Jenkins Console\n\t\u003cSystem Command\u003e      System Command To Run\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-x, --no_wait         Do not wait for Output\n\t-N \u003cNode\u003e, --node \u003cNode\u003e\n\t\t\t\t\t\t\tNode (Slave) to execute against. Executes against\n\t\t\t\t\t\t\t\"master\" if not specified.\n\n\n### RunJob\n\nAllows you to run jobs via Jenkins. The command will upload your script or executable and then execute it. The `-e` option allows you to specify what program is called to execute your uploaded script, otherwise the script is executed by the default handler. The `-A` allows you to specify an argument string to pass to your script or executable. For exmple, if both the `-e` and `-A` option were passed, your file would be executed in this fashion: `\u003cexecutor\u003e \u003cpayload name\u003e \u003cargument string\u003e`.\n\nThe `-g` option allows you to run \"Ghost Jobs\". Ghost jobs are jobs which are launched then terminated and deleted so that they do not continue to show up in Jenkins. Due to some clever hackery with this feature, Jenkins does not terminate these jobs (or mark an executor as in-use), and the jobs can run indefinitely on the executing system.  This is an excellent way to upload a SOCKS5 server to a slave and run it on a high port to tunnel traffic with only Create Job permissions.\n\n**GHOSTJOB OPSEC WARNING 1:** In the case of running a GHOST job on a Windows slave, a helper executable is uploaded. If the slave is running as an administrative user, `wmic process call create` is used as part of the job termination bypass. You should not use this technique if the Windows Slaves are running EDR.\n\n**GHOSTJOB OPSEC WARNING 2:** You should ensure that your payloads are designed in such a way as to handle deleting themselves upon completion as in the case of Windows slaves, JAF cannot automatically do this.\n\n\tusage: jaf.py RunJob [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\t\t\t\t[-x] [-g] [-N \u003cNode\u003e] [-T \u003cNode Type\u003e] [-e \u003cExecutor String\u003e]\n\t\t\t\t[-A \u003cAdditional Arguments String\u003e] \u003cTask Name\u003e \u003cExecutable File\u003e\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tRunJob                Run Jenkins Jobs\n\t\u003cTask Name\u003e           Task to Create, must be unique (may not be deleted if\n\t\t\t\t\t\t\tuser doesn't have job deletion permissions, so pick\n\t\t\t\t\t\t\tsomething that blends in)\n\t\u003cExecutable File\u003e     Local path to script to upload and run. Should be\n\t\t\t\t\t\t\tcompatible with OS and with expected extension.\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-x, --no_wait         Do not wait for Job. Cannot be specified if -g is\n\t\t\t\t\t\t\tpassed\n\t-g, --ghost           Launch \"ghost job\", does not show up as a running job\n\t\t\t\t\t\t\tafter initial launch, does not tie up executors, and\n\t\t\t\t\t\t\truns indefinitely. Cannot be specified with the -x\n\t\t\t\t\t\t\toption.\n\t-N \u003cNode\u003e, --node \u003cNode\u003e\n\t\t\t\t\t\t\tNode (Slave) to execute against. Executes against any\n\t\t\t\t\t\t\tavailable node if not specified.\n\t-T \u003cNode Type\u003e, --nodetype \u003cNode Type\u003e\n\t\t\t\t\t\t\tNode Type, either: \"posix\" or \"windows\". If specified,\n\t\t\t\t\t\t\tyou must also pass -N\n\t-e \u003cExecutor String\u003e, --executor \u003cExecutor String\u003e\n\t\t\t\t\t\t\tIf passed, this command string will be prepended to\n\t\t\t\t\t\t\tcommand string ([\u003cExecutor String\u003e] \u003cExecutable File\u003e\n\t\t\t\t\t\t\t[\u003cAdditional Arguments String\u003e]).\n\t-A \u003cAdditional Arguments String\u003e, --args \u003cAdditional Arguments String\u003e\n\t\t\t\t\t\t\tIf passed, this will be concatonated to the end of the\n\t\t\t\t\t\t\tcommand string ([\u003cExecutor String\u003e] \u003cExecutable File\u003e\n\t\t\t\t\t\t\t[\u003cAdditional Arguments String\u003e]).\n\n\n### RunScript\n\nShould be self explanatory, but this does require administrative credentials with `/script` access.\n\n\tusage: jaf.py RunScript [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n              [-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n              [-x] [-N \u003cNode\u003e] \u003cGroovy File Path\u003e \n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tRunScript             Run Specified Groovy Script via Jenkins Console\n\t\u003cGroovy File Path\u003e    Groovy File Path to Run via Script Console\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-x, --no_wait         Do not wait for Output\n\t-N \u003cNode\u003e, --node \u003cNode\u003e\n\t\t\t\t\t\t\tNode (Slave) to execute against. Executes against\n\t\t\t\t\t\t\t\"master\" if not specified.\n\n\n### UploadFile\n\nThis method requires administrative credentials with `/script` access.\nThis method works by chunking files into pieces small enough to post to the Jenkins server as base64 encoded chunks that are decoded via groovy commands in the console and appended to a file.  For this to work, you should ensure that the upload file path is:\n\n1) a full path (no `~` or other expansion will be done, nor folders created).\n\n2) write-able by the jenkin's system user.\n\n3) In the path format for the OS in use.\n\nIn addition, it is critical that the file does not already exist. Due to the mulitiple chunk nature, this process is additive. An existing file will result in the upload file being appended to the existing file.\n\n\n\tusage: jaf.py UploadFile [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n              [-o Output File] [-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n              [-N \u003cNode\u003e] \u003cUpload File\u003e \u003cUpload File Path\u003e \n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tUploadFile            Upload file to Jenkins Server via chunked upload\n\t\t\t\t\t\t\tthrough Jenkins Console (slow for large files)\n\t\u003cUpload File\u003e         Local Path to File to Upload\n\t\u003cUpload File Path\u003e    Remote Full File Path to Upload To. SHOULD NOT ALREADY\n\t\t\t\t\t\t\tEXIST! (Upload is appended to existing file)\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-N \u003cNode\u003e, --node \u003cNode\u003e\n\t\t\t\t\t\t\tNode (Slave) to execute against. Executes against\n\t\t\t\t\t\t\t\"master\" if not specified.\n\n\n### WhoAmI\n\nThis method is basically a useability wrapper around `/api/whoAmI`. This page shows the current logged-in users all the Jenkins groups they are in.\nIn the case of a LDAP/Domain-Connected Jenkins, this also includes all domain groups for the user (recursively or not depends on admin settings).\n\n\tusage: jaf.py WhoAmI [-h] -s \u003cServer\u003e [-u \u003cUser-Agent\u003e] [-n \u003cTimeout\u003e]\n\t\t\t\t[-o Output File] [-t \u003cThreads\u003e]\n\t\t\t\t[-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]]\n\t\t\t\t[-c \u003cCredential File\u003e]\n\n\tJenkins Attack Framework\n\n\tpositional arguments:\n\tWhoAmI                Get Users Roles and Possibly Domain Groups\n\n\toptional arguments:\n\t-h, --help            show this help message and exit\n\t-s \u003cServer\u003e, --server \u003cServer\u003e\n\t\t\t\t\t\t\tJenkins Server\n\t-u \u003cUser-Agent\u003e, --useragent \u003cUser-Agent\u003e\n\t\t\t\t\t\t\tJAF User-Agent. Defaults to: Mozilla/5.0 (Windows NT\n\t\t\t\t\t\t\t10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like\n\t\t\t\t\t\t\tGecko) Chrome/80.0.3987.149 Safari/537.36\n\t-n \u003cTimeout\u003e, --timeout \u003cTimeout\u003e\n\t\t\t\t\t\t\tHTTP Request Timeout (in seconds). Defaults to: 30\n\t-o Output File, --output Output File\n\t\t\t\t\t\t\tWrite Output to File\n\t-t \u003cThreads\u003e, --threads \u003cThreads\u003e\n\t\t\t\t\t\t\tNumber of max concurrent HTTP requests. Defaults to: 4\n\t-a [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e], --authentication [\u003cUser\u003e:[\u003cPassword\u003e|\u003cAPI Token\u003e]|\u003cCookie\u003e]\n\t\t\t\t\t\t\tUser + Password or API Token, or full JSESSIONID\n\t\t\t\t\t\t\tcookie string\n\t-c \u003cCredential File\u003e, --credentialfile \u003cCredential File\u003e\n\t\t\t\t\t\t\tCredential File (\"-\" for stdin). Creds in form\n\t\t\t\t\t\t\t\"\u003cUser\u003e:\u003cPassword\u003e\" or \"\u003cUser\u003e:\u003cAPI Token\u003e\"\n\n\n## Version Info:\n\nThis should be kept up to date with the lastest version info at the top.\n\n###    1.5.2\n\nAdded a bit more postive confirmation when using `RunJob` with the `-g` or `-x` options.\n\n###    1.5.1\n\nAdded the `DeleteJob` feature to complement `RunJob` and `ListJob`.\n\n###    1.5\n\nAdded the `RunJob` feature including the very powerful `GhostJob` feature.\n\nOther minor bug fixes, more unit tests, and templating updates.\n\n###    1.4.1\n\nMore code improvements and clean ups.\n\nAdded `--user` option for these commands: `CreateAPIToken`, `DeleteAPIToken`, `ListAPITokens`\n\n###    1.4\n\nMore code improvements and clean ups.\n\nAdded three new API Token Commands (and corresponding unit tests): `CreateAPIToken`, `DeleteAPIToken`, `ListAPITokens`\n\n###    1.3\n\nFixed a bunch of little bugs.\n\nWrote a Unit Test Framework for this tool.\n\nMany minor code clean-ups.\n\nPulled the `install_dependencies.sh` script into the main `jaf` wrapper script.\n\n###    1.2\n\nMajor Code Refactor with Plugin Framework.\n\nAdded new \"DumpCredsViaJob\" method.\n\nAdded node/slave specification for many of the commands: DumpCreds, DumpCredsViaJob, RunCommand, RunScript, UploadFile\n\nFixed a bug in UploadFile where back slashes were not being properly escaped in paths.\n\nUpdated Credential Dumping Script to dump more types of credentials and domain and ldap binding credentials.\n\n###    1.1\n\nFixed some authentication bugs.\n\n###\t   1.0\n\nDue to the full re-write/rebranding of Jenkins Miner, this is now version 1.0 of the Jenkins Attack Framework.\n\nCredit\n======\n\nThis project was originally developed by Shelby Spencer (@shellster) with the gracious support, funding, and resources of Accenture.  The project is wholly owned by Accenture, but is licensed under the MIT license (see LICENSE file).\n","funding_links":[],"categories":["Repositories","Python","Tools"],"sub_categories":["ArgoCD","Defense Evasion"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAccenture%2Fjenkins-attack-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAccenture%2Fjenkins-attack-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAccenture%2Fjenkins-attack-framework/lists"}