-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCheetah.go
121 lines (100 loc) · 3.01 KB
/
Cheetah.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"bufio"
"flag"
"fmt"
"log"
"net/http"
"os"
"strings"
"sync"
"time"
)
// List of HTTP methods to test
var methods = []string{
"GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD",
}
func checkURL(target, path string, method string, wg *sync.WaitGroup, ch chan<- string) {
defer wg.Done()
// Prepare the full URL by concatenating the target URL and the path
url := fmt.Sprintf("%s/%s", target, path)
// Create an HTTP client to make requests with custom methods
client := &http.Client{
Timeout: 10 * time.Second, // Set a timeout for each request
}
// Prepare the HTTP request
req, err := http.NewRequest(method, url, nil)
if err != nil {
ch <- fmt.Sprintf("Error: %v | Method: %s | URL: %s", err, method, url)
return
}
// Send the HTTP request
resp, err := client.Do(req)
if err != nil {
ch <- fmt.Sprintf("Error: %v | Method: %s | URL: %s", err, method, url)
return
}
defer resp.Body.Close()
// Send the status code, headers, and method to the channel
ch <- fmt.Sprintf("Method: %s | URL: %s\nStatus Code: %d\nHeaders: %v\n", method, url, resp.StatusCode, resp.Header)
}
func processFile(filePath string) []string {
var paths []string
file, err := os.Open(filePath)
if err != nil {
log.Fatalf("Error opening file: %v\n", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
// Add each line (path) from the file to the paths slice
paths = append(paths, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatalf("Error reading file: %v\n", err)
}
return paths
}
func main() {
// Command-line flags for target URL and input file
target := flag.String("u", "", "Target URL (e.g., https://example.com)")
inputFile := flag.String("i", "", "File containing the list of directories to test")
// Parse the command-line flags
flag.Parse()
// Check if the URL and input file are provided
if *target == "" || *inputFile == "" {
log.Fatal("Both target URL (-u) and input file (-i) are required.")
}
// Read the list of paths from the input file
paths := processFile(*inputFile)
// Create a wait group and a channel to handle concurrency
var wg sync.WaitGroup
ch := make(chan string, len(paths))
// Set the maximum number of concurrent requests (for throttling if needed)
maxConcurrency := 50
sem := make(chan struct{}, maxConcurrency)
// Start the directory discovery for each path with method tampering
startTime := time.Now()
for _, path := range paths {
wg.Add(1)
sem <- struct{}{} // acquire a slot in the semaphore
for _, method := range methods {
go func(p, m string) {
defer func() { <-sem }() // release the slot in the semaphore
checkURL(*target, p, m, &wg, ch)
}(path, method)
}
}
// Close the channel when all work is done
go func() {
wg.Wait()
close(ch)
}()
// Collect and display the results
for result := range ch {
fmt.Println(result)
}
// Display the total time taken for the operation
duration := time.Since(startTime)
fmt.Printf("\nDirectory discovery completed in %v\n", duration)
}