Summary
- Attackers can leverage the Jenkins Script Console to execute malicious Groovy scripts, leading to cybercriminal activities such as the deployment of cryptocurrency miners.
- Misconfigurations such as improperly setup authentication mechanisms expose the /script endpoint to attackers. This can lead to remote code execution (RCE) and misuse by malicious actors.
- Attackers can exploit Jenkins vulnerabilities to run scripts that can download and execute a miner binary and maintain persistence using cron jobs and systemd-run utilities.
Jenkins is an open-source solution that enables continuous integration and continuous delivery (CI/CD), allowing for the automation of the various stages of software development such as the test, build, and deployment phases. While it offers many benefits to users, it can also be used as an attack vector by malicious actors that can exploit misconfigured servers and unpatched Jenkins versions to deploy cryptocurrency miners and backdoors, as well as to gather sensitive information. In this blog entry, we will discuss how the Jenkins Script Console can be weaponized by attackers for cryptomining activity if not configured properly.
Technical details
The Script Console in Jenkins is a tool that allows administrators and authorized users to execute , Groovy scripts directly on the Jenkins server. This console runs scripts with Jenkins' access privileges, giving it elevated permissions. Jenkins supports scripting via the Groovy language.
By default, Jenkins does not enable the script console for anonymous users. Rather, the console, which allows the execution of Groovy scripts (and thus potentially dangerous commands), is restricted to authenticated users with administrative permissions. However, it is possible for a Jenkins instance to be misconfigured — for example, when certain authentication mechanisms are improperly set up — potentially leading to vulnerable instances. If the "Sign Up" or "Registration" option is enabled, gaining access to Jenkins and the /script endpoint can also result in RCE. Therefore, proper protection of this interface is essential. Unfortunately, some Jenkins deployments that are exposed to the internet are misconfigured, leaving them vulnerable to misuse.
A quick search on Shodan reveals the number of Jenkins servers exposed to the public. Note that while not all exposed Jenkins servers might be susceptible to misuse, they can still serve as pivot points for attackers.
We observed that if a malicious actor can access the Jenkins Script Console, then they can run malicious scripts to harvest cryptocurrencies. Figure 3 shows the encoded malicious payload we found during our analysis.
As seen in the image, the attacker exploits a Jenkins Groovy plug-in misconfiguration to execute the Base64-encoded string, which is actually a malicious script.
The analysis of this script is as follows:
First, this script checks whether it is running BusyBox, which if detected, will exit from the script:
This script has a function named svalid() that checks for locations with writable permissions:
The function takes an argument and creates a temporary shell script named vinars in the specified directory. The script simply prints "ginerd" to the console. It makes this small script executable and captures the exit status with $?, a special variable that contains a number indicating the result of the last executed command. This function is further used to execute a simple script in a dynamically specified location.
The script ensures it has enough system resources to perform the mining effectively (similar to other cryptocurrency miners). To do this, the script checks for processes that consume more than 90% of the CPU’s resources, then proceeds to kills these processes. Furthermore, it will terminate all stopped processes.
Next, the attacker searches for locations where the miner can be downloaded and executed. First, it checks if the current user can write and execute the miner under the /dev/shm directory using the svalid () function; if the function returns a non-zero exit status (indicating the directory is not writable and executable), it then searches for other directories except /proc and /sys.
If a favorable directory is unable to be located, it uses /tmp for operations and creates a sub directory named duet, assigning it maximum permissions (777).
In the next section, it first checks if the cryptominer binary is present in the directory. If not, it downloads the cryptominer binary and makes it persistent. To check the presence of the malicious binary, the script checks the SHA256 hash.
If this command returns a failure status code, the script proceeds to download the malicious binary, an encrypted tar file with the “cex” file name from https[:]//berrystore[.]me. It uses wget to download the binary.
If wget is unable to download the file, the OpenSSL’s s_client option is used to download the binary, which connects to a remote host using SSL/TLS.
This command sends an HTTPS GET request to the server, then retrieves the server's response, extracting the last 2,481,008 bytes from the input stream, indicating evasive behavior. The extracted bytes will then be saved to the “cex” file.
Being an AES-256 encrypted tar file, OpenSSL is further used to decrypt it. The SHA256 hash is used for key derivation from the password, while AES-256 is used for decryption. After decryption, tar is used to decompress the file, after which the original “cex” file is removed and the executable permission is assigned to the file which is the same file validated earlier in this script with the “sha256sum app” command.
To make sure that the miner persistent, cron job, and systemd-run are implemented along with persistence, the flock system utility validates that there is only one instance of the miner running at a time.
Using cron job to achieve persistence
The code in Figure 13 creates a cron job:
- It uses the flock system utility to lock the file, and the /var/tmp/verl.lock file to ensure that only one instance is running at a time
- It uses awk '!a[$0]++' to remove all the duplicate entries from the cron job. This is another step to ensure only one instance of cron job executes at a time.
- Finally, the output from awk is piped into crontab -, which updates the user's crontab with the filtered and unique cron job entries.
The script stores the whole cron job entry in a variable named cronny with all the parameters to run the miner, including the pool and wallet addresses and adds this to the crontab.
Using systemd-run to achieve persistence
The systemd-run command uses DBUS_SESSSION_BUS_ADDRESS=unix:/run/user/$(id -u)/bus to set the DBUS_SESSSION_BUS_ADDRESS environment variable to the address of the D-Bus session bus socket file specific to the current user's session. This allows applications and services running within the user session to communicate via D-Bus.
The attacker then uses systemd-run to schedule the execution of a cryptocurrency mining application at the beginning of every hour. The flock utility ensures that only one instance runs at a time using a lock.
Even if these methods fail to execute the miner in a desired manner, the attacker has another mechanism to use for execution.
The script part performs the following actions:
- Writes the string to a file named strptr that sets the rig ID for the mining operation.
- The “trap '' SIG” command sets a trap to ignore the SIG signal. The purpose of this line could be to prevent the script from being terminated prematurely by certain signals.
- The “( sleep 40; kill -9 $PPID ) &” command starts a subshell in the background (&). The subshell sleeps for 40 seconds and then sends a SIGKILL signal to the parent process ($PPID), which is likely the script itself (possibly a way to ensure that the script terminates after a certain period as a cleanup measure).
- Finally, the exec command executes the miner.
Mitigations
To protect Jenkins servers from the attacks that we discussed here, we recommend the following best practices:
- Use the Script Approval feature provided by Jenkins.
- Apply proper authentication and authorization policies to access the web console. Note that Jenkins offers specific guidelines on Access Control.
- Use the Audit Logging feature provided by Jenkins.
- Ensure that Jenkins servers are not accessible from the internet.
Trend solutions
Vision One Threat Hunting Query
The following text lists potentially useful queries for threat hunting within Vision One:
- eventSubId: 2 AND processCmd:* exec * --rig-id *
- eventSubId: 2 AND processCmd:cron AND objectCmd:* exec * --rig-id *
Conclusion
The robust capabilities of the Jenkins software make it an essential tool for modern software development. However, these capabilities can also bring significant risks when misconfigured or left unpatched (also seen in our previous Jenkins blog entry). In this blog entry, we discuss how the Jenkins Script Console can be weaponized by attackers to deploy malicious scripts for activities such as cryptocurrency mining.
Ensuring proper configuration, robust authentication and authorization, regular audits, and restricting the internet accessibility of Jenkins servers are all vital steps for organizations to significantly reduce the likelihood of their Jenkins instances becoming attack vectors and safeguard their development environments against exploitation.
Indicators of Compromise (IOCs)
The indicators of compromise for this entry can be found here.
MITRE ATT&CK Techniques
Tactic | Technique | Technique ID |
---|---|---|
Initial Access | Exploit Public-Facing Application | T1190 |
Discovery | Process Discovery | T1057 |
File and Directory Discovery | T1083 | |
Defense Evasion | File and Directory Permissions Modification: Linux and Mac File and Directory Permissions Modification | T1222.002 |
Deobfuscate/Decode Files or Information | T1140 | |
Command and Control | Ingress Tool Transfer | T1105 |
Application Layer Protocol: Web Protocols | T1071.001 | |
Persistence | Scheduled Task/Job: Cron | T1053.003 |
Scheduled Task/Job: Systemd Timers | T1053.006 | |
Impact | Resource Hijacking | T1496 |