Today we are releasing the Jenkins Attack Framework (JAF) to the public. JAF is an Accenture, internally developed, red team-oriented tool for interacting with Jenkins build servers. Jenkins[1] is an opensource build CI/CD pipeline tool that is commonly used in industry to manage building and testing code. It is of interest to red teamers because it often stores powerful credentials, company proprietary code, may have backdoor access into production environments, and often provides attackers with lateral movement and pivoting capabilities. This blogpost does not introduce any new vulnerabilities discovered in Jenkins, but rather demonstrates ways in which it can be abused by red team operators.

Source code for the project can be found on the Accenture Github[2], and getting started is easy:

<<< Start >>>

Figure 1: Installing JAF is a breeze! Just run the install script.

<<< End >>>

The Jenkins Attack Framework automates and simplifies many common Jenkins attack and introduces some new techniques which are likely not well known in the offensive security community before now. While this article will highlight the features of JAF at a high-level, interested parties are highly encouraged to checkout the README for a detailed list of features and options. JAF is built upon a simple plugin framework, and while the tool is eminently usable as is, it is our hope that the community submits additional plugins to help make JAF the go-to tool in the industry for auditing and attacking Jenkins servers.

The first set of features that JAF provides are centered around reconnaissance and situational awareness. These include the “AccessCheck” command which provides a quick way to gauge the access level of multiple sets of credentials which can be provided as a username and password pair, API token, or session cookie. The “ListJobs” command allows the operator to recursively list the names of all jobs on the Jenkins server to quickly locate specific targets or find interestingly named jobs.  “ConsoleOutput” prints out the console output for the last build of every job on the server in a multithreaded fashion. This can be very useful for finding unmasked credentials, even when running as a low-privileged user. One common source of such credentials are Basic Authentication headers in HTTP requests. “WhoAmI” returns permission-related information on the currently provided credentials. For a Jenkins server that performs authentication against a domain controller, this command also provides a list of domain groups associated with the user account, and thus it can be a stealthy way to perform account domain lookups.

<<< Start >>>

Figure 2: All features come with helpful command descriptions and syntax

<<< End >>>

<<< Start >>>

Figure 3: Checking access with AccessCheck. Provides context around the privileges of any compromised credentials.

<<< End >>>

<<< Start >>>

Figure 4: Get user roles and groups. Helpful with domain credentials.

<<< End >>>

The next set of features in JAF are focused around simplifying access to common Jenkins functionality which is useful for red team operatives. The “ListAPITokens”, “CreateAPIToken”, and “DeleteAPIToken” commands allow the operator to list, create, or delete API tokens for the user whose credentials are provided. If the provided credentials are for a Jenkins administrator, these commands can also be used to perform these actions on any other user account which can be a great way to establish persistence. As mentioned, JAF can create API tokens for other users, and this feature is not even a feature that is currently available through the Jenkins web application. “RunScript” allows a Jenkin’s administrator to upload and run a Groovy script via the Jenkins script console, and optionally wait for and return the output. “RunCommand” is a simple utility function that wraps the provided command in Groovy, runs it via the Jenkins script console, and optionally returns the command output. “UploadFile” uploads a file in chunks and reassembles it on the Jenkins master server via the Jenkins script console to get around script console size limitations.

<<< Start >>>

Figure 5: Help for using CreateAPIToken feature.

<<< End >>>

<<< Start >>>

Figure 6: Creating an API token

<<< End >>>

<<< Start >>>

Figure 7: Using the API token for authentication. Notice that the same authorizations apply to the user authenticating use a password as an API key.

<<< End >>>

<<< Start >>>

Figure 8: Enumerating API keys of a user (using an API key for authentication)

<<< End >>>

<<< Start >>>

Figure 9: Using the RunCommand feature to identify networking information of Jenkins host

<<< End >>>

The last set of features is specifically focused on red team advanced attack actions. “DeleteJob” allows the operator to clean-up a malicious job. First it will attempt to delete the job. If that fails, it will attempt to remove all job history, replace the job with a blank job, and disable the job. Success or failure for each of these steps is always returned to the operator. “RunJob” allows the operator to create a job that will upload and execute a script and optionally wait for and return the output of the job before deleting it in a similar failover sequence to the “DeleteJob” command. The script execution parameters and which Jenkins slaves are used are entirely controllable by the operator. In addition, JAF has some tricks up its sleeve for both POSIX and Windows Jenkins slaves, and can launch what we have termed “Ghost Jobs”. A ghost job is a job that uses various techniques that we have pioneered to prevent Jenkins from terminating the job. Once the job has launched, JAF terminated and deletes the job within Jenkins web application. However, the job continues to execute on the slave indefinitely in the background. This feature works for both privileged and unprivileged Jenkins slaves. Ghost Jobs allow an operator with the relatively limited privileges of “create job” and “run job” to potentially setup long running socks proxies or shells on a Jenkins slave that are not visible within Jenkins (after initial launch and cleanup).

The “DumpCreds” command allows an operator with Jenkins Administrator credentials to dump all stored credentials on the Jenkins server, including LDAP or Domain joining credentials via a script that is uploaded and executed in the Jenkins script console. The last command is the “DumpCredsViaJob” command. This command allows an operator with only “create job” and “run job” permissions to dump all stored credentials that are shared with that user. By default, stored credentials are available to be used in jobs by any user. This command steals these credentials by creating a job that binds all the available stored credentials to environment variables, then prints those variables to a file that is obfuscated so that Jenkins cannot redact them. Finally, the console output is captured, and decoded, before the job is deleted to leave no trace. This feature works on both POSIX and Windows slaves and is one of the most powerful and unique features of this framework.

<<< Start >>>

Figure 10: Stealing credentials stored in Jenkins

<<< End >>>

If this tool sounds useful to you, please check out the README and consider contributing to the project. The code and be found at https://github.com/Accenture/jenkins-attack-framework.

We would like to acknowledge Shelby Spencer for the significant work he put into this blog post and project.

 

Accenture Security 

Accenture Security helps organizations build resilience from the inside out, so they can confidently focus on innovation and growth. Leveraging its global network of cybersecurity labs, deep industry understanding across client value chains and services that span the security lifecycle, Accenture helps organizations protect their valuable assets, end-to-end. With services that include strategy and risk management, cyber defence, digital identity, application security and managed security, Accenture enables businesses around the world to defend against known sophisticated threats, and the unknown. Follow us @AccentureSecure on Twitter or visit us at www.accenture.com/security

Accenture, the Accenture logo, and other trademarks, service marks, and designs are registered or unregistered trademarks of Accenture and its subsidiaries in the United States and in foreign countries. All trademarks are properties of their respective owners. All materials are intended for the original recipient only. The reproduction and distribution of this material is forbidden without express written permission from Accenture. The opinions, statements, and assessments in this report are solely those of the individual author(s) and do not constitute legal advice, nor do they necessarily reflect the views of Accenture, its subsidiaries, or affiliates. Given the inherent nature of threat intelligence, the content contained in this report is based on information gathered and understood at the time of its creation. It is subject to change. Accenture provides the information on an “as-is” basis without representation or warranty and accepts no liability for any action or failure to act taken in response to the information contained or referenced in this report. 

Copyright © 2021 Accenture. All rights reserved. 

 

[1] https://www.jenkins.io/
[2] http://github.com/Accenture/

Bryan Alexander

Research & Development Lead

Subscribe to Accenture's Cyber Defense Blog Subscribe to Accenture's Cyber Defense Blog