Jenkins CI/CD solution provides a way for developers to create an automated, scalable, and highly configurable pipeline to ensure that code bases stay up-to-date and can be pushed out with very little effort. When a developer pushes new commits to any code, Jenkins can pick up on those changes and run a series of tests and builds, then ship it to production in one seamless pipeline.
Jenkins has over 300,000 installations worldwide, and is growing steadily. Any company with a software development team likely has one or more instances of Jenkins that they interface with.
With this level of ubiquity, Jenkins is often a target for threat actors, especially with the implication that these pipelines contain secrets and the source of a company’s most closely-held software.
GroovyWaiter is a simple Python script that will take a file of URLs, and for each of those URLs, it will attempt to enumerate unauthenticated access to a Jenkins Script Console (explained further below). If it is able to reach the Console, it will execute the command id
if the Jenkins server is running Linux, or whoami.exe
if the server is running Windows.
The script will display found hosts as it is scanning (Figure 1). Once scanning is complete, it will display the output of the commands run in a table (Figure 2).
You could modify this script to make it run more commands than those mentioned above. You could even dump all the secrets stored on a server to get a table of passwords, keys, and other goodies.
Jenkins history and threat landscape
Jenkins allows for the ability to inject “secrets” into automated CI/CD builds. This means that developers can securely insert passwords, SSH keys, and more into builds, as opposed to hardcoding them. However, these secrets are stored on the Jenkins server itself.
For many years, threat actors have targeted Jenkins servers for a multitude of reasons. These are prime candidates for ransomware, as well as supply chain injection (for more advanced actors). More commonly, these servers are targeted because of the data that they could potentially hold.
Exploitation of Jenkins servers
As with any product, there are often many Jenkins common vulnerabilities and exposures (CVEs) reported every year. These contain everything from Reflected Cross Site Scripting vulnerabilities to full-on Remote Code Execution bugs. This post focuses on how Red Teams abuse Jenkins servers by using intended functionalities within Jenkins itself.
Groovy scripts and Jenkins
Jenkins features the ability to execute arbitrary Groovy scripts within a console that is accessible through the Jenkins server. The Script Console is always available within Jenkins at the /script
endpoint.
For the majority of cases, this is secured behind Jenkins authentication (either basic server-side authentication, LDAP, or any other authentication solution). It is secured to only users that are equipped with the Overall/Read permission on the Jenkins server.
Jenkins Script Console access (unauthenticated)
In some cases, Jenkins will be deployed with access control that is too lax. This results in the ability to access anything on the Jenkins server without authenticating, including the Script Console (Figure 3).
Figure 3 shows that the /script
endpoint was accessed and presented the Script Console engine without asking for credentials. At this point, an attacker can execute several actions, including:
- dump all secrets using Groovy
- execute system commands to degrade, compromise, or destroy data on the underlying server that is running Jenkins
- use Groovy functions to decrypt previously-found secrets on the fly
Obviously, accessing a Jenkins Script Console without authentication has major implications. Attackers can laterally move throughout the network and/or escalate privileges, disrupt or inject into builds that are run on the server, and more.
The example provided above is just one Jenkins server, which may not hold the secrets an attacker seeks. The section below explores how an attacker might scale this type of exploitation.
Scaling exploitation of Jenkins servers
Depending on the network or environment, there might be hundreds of Jenkins servers deployed for different teams and offices. An attacker could attempt this type of exploitation manually, but that would take a lot of time that could be cut short by eagle-eyed defenders.
Seeing a chance for this type of scaling, I started digging into how I could take a list of hosts, enumerate access to the /script
endpoint, and exploit at scale. Thus, the GroovyWaiter script was born.
Mitigations
It is highly recommended to follow proper security practices with basic access control. You should also properly secure Jenkins servers. Simply adding authentication, along with proper access control, can be the difference between a full-network compromise, and stopping an attacker in their tracks.