1 | | - | package main |
2 | | - | |
3 | | - | import ( |
4 | | - | "fmt" |
5 | | - | "net/http" |
6 | | - | "sync" |
7 | | - | "io/ioutil" |
8 | | - | "time" |
9 | | - | "net" |
10 | | - | "crypto/tls" |
11 | | - | "github.com/fatih/color" |
12 | | - | "flag" |
13 | | - | "bufio" |
14 | | - | "os" |
15 | | - | "log" |
16 | | - | "strings" |
17 | | - | |
18 | | - | ) |
19 | | - | |
20 | | - | var Threads int |
21 | | - | var recheck_url string |
22 | | - | var method string |
23 | | - | var body string |
24 | | - | var payload string |
25 | | - | var base_size int |
26 | | - | var matcher string |
27 | | - | var payloads []string |
28 | | - | var confirm []string |
29 | | - | var verify bool |
30 | | - | var signatures = []string{"Program Files", "Windows", "[boot loader]", "[drivers]", "HTTP /1.1", "HTTP /1.0", "About php.ini", "root:x:", "root:*"} |
31 | | - | |
32 | | - | func getClient() *http.Client { |
33 | | - | tr := &http.Transport{ |
34 | | - | MaxIdleConns: 30, |
35 | | - | IdleConnTimeout: time.Second, |
36 | | - | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, |
37 | | - | DialContext: (&net.Dialer{ |
38 | | - | Timeout: time.Second * 10, |
39 | | - | KeepAlive: time.Second, |
40 | | - | }).DialContext, |
41 | | - | } |
42 | | - | |
43 | | - | re := func(req *http.Request, via []*http.Request) error { |
44 | | - | return http.ErrUseLastResponse |
45 | | - | } |
46 | | - | |
47 | | - | return &http.Client{ |
48 | | - | Transport: tr, |
49 | | - | CheckRedirect: re, |
50 | | - | Timeout: time.Second * 10, |
51 | | - | } |
52 | | - | } |
53 | | - | |
54 | | - | func base_request(c *http.Client, u string, method string, matcher string) (int, string) { |
55 | | - | req, _ := http.NewRequest(method, u, nil) |
56 | | - | if req != nil { |
57 | | - | resp, _ := c.Do(req) |
58 | | - | if resp != nil { |
59 | | - | contents, _ := ioutil.ReadAll(resp.Body) |
60 | | - | if matcher == "check" { |
61 | | - | body = string(contents) |
62 | | - | } |
63 | | - | base_size = len(contents) |
64 | | - | resp.Body.Close() |
65 | | - | } |
66 | | - | } |
67 | | - | |
68 | | - | return base_size, body |
69 | | - | } |
70 | | - | |
71 | | - | |
72 | | - | func requester(c *http.Client, u string, method string, list []string , verify bool, matcher string) { |
73 | | - | req_base, _ := base_request(c, u, method, matcher) |
74 | | - | for _, test := range list { |
75 | | - | url := strings.Replace(u, "FUZZ", test, -1) |
76 | | - | req_test, _ := base_request(c, url, method , matcher) |
77 | | - | if req_test != req_base { |
78 | | - | if verify != true { |
79 | | - | fmt.Printf("%v %s\n", color.RedString("[!] Potential vulnerability found at:..🛠") , url) |
80 | | - | fmt.Printf("%v\n", color.CyanString("[~] Storing for confirmation..✒")) |
81 | | - | } |
82 | | - | confirm = append(confirm, url) |
83 | | - | } |
84 | | - | } |
85 | | - | if verify != true { |
86 | | - | fmt.Printf("%v\n",color.YellowString("[>] Staring confirmation tests..🔍")) |
87 | | - | } |
88 | | - | matcher = "check" |
89 | | - | for _, recheck_url = range confirm { |
90 | | - | _, checkbody := base_request(c, recheck_url, method, matcher) |
91 | | - | for _, query := range signatures { |
92 | | - | if strings.Contains(checkbody, query) { |
93 | | - | fmt.Printf("%v %s\n", color.GreenString("[+] POC:..✨"), recheck_url) |
94 | | - | } |
95 | | - | } |
96 | | - | } |
97 | | - | } |
98 | | - | |
99 | | - | func payloadlist(path string) []string { |
100 | | - | file, err := os.Open(path) |
101 | | - | if err != nil { |
102 | | - | log.Fatal(err) |
103 | | - | } |
104 | | - | defer file.Close() |
105 | | - | |
106 | | - | scanner := bufio.NewScanner(file) |
107 | | - | for scanner.Scan() { |
108 | | - | payloads = append(payloads, scanner.Text()) |
109 | | - | } |
110 | | - | |
111 | | - | if err := scanner.Err(); err != nil { |
112 | | - | log.Fatal(err) |
113 | | - | } |
114 | | - | return payloads |
115 | | - | } |
116 | | - | |
117 | | - | func Banner() { |
118 | | - | color.HiGreen(` |
119 | | - | .____ _____.__ _____ |
120 | | - | | | _/ ____\__| / \ ____ |
121 | | - | | | \ __\| |/ \ / \_/ __ \ |
122 | | - | | |___| | | / Y \ ___/ |
123 | | - | |_______ \__| |__\____|__ /\___ > |
124 | | - | \/ \/ \/ v1.0 |
125 | | - | `) |
126 | | - | color.HiRed(" " + "Made with <3 by @shivangx01b") |
127 | | - | |
128 | | - | } |
129 | | - | |
130 | | - | func ParseArguments() { |
131 | | - | flag.IntVar(&Threads, "t", 40, "Number of workers to use..default 40. Ex: -t 50") |
132 | | - | flag.StringVar(&payload, "p", "", "Feed the list of payloads to fuzz. Ex: -p ~/wordlists/lfi.txt") |
133 | | - | flag.StringVar(&method, "method", "GET", "Add method name if required. Ex: -method PUT. Default \"GET\"") |
134 | | - | flag.BoolVar(&verify, "verify", false, "Only prints confirmed results. Ex -verify ") |
135 | | - | flag.Parse() |
136 | | - | } |
137 | | - | |
138 | | - | |
139 | | - | func main() { |
140 | | - | ParseArguments() |
141 | | - | Banner() |
142 | | - | checkin, _ := os.Stdin.Stat() |
143 | | - | if checkin.Mode() & os.ModeNamedPipe > 0 { |
144 | | - | if payload != "" { |
145 | | - | list := payloadlist(payload) |
146 | | - | matcher = "nocheck" |
147 | | - | urls := make(chan string, Threads) |
148 | | - | processGroup := new(sync.WaitGroup) |
149 | | - | processGroup.Add(Threads) |
150 | | - | |
151 | | - | for i := 0; i < Threads; i++ { |
152 | | - | c := getClient() |
153 | | - | go func() { |
154 | | - | defer processGroup.Done() |
155 | | - | for u := range urls { |
156 | | - | requester(c, u, method, list, verify, matcher) |
157 | | - | } |
158 | | - | }() |
159 | | - | } |
160 | | - | |
161 | | - | sc := bufio.NewScanner(os.Stdin) |
162 | | - | |
163 | | - | for sc.Scan() { |
164 | | - | urls <- sc.Text() |
165 | | - | } |
166 | | - | close(urls) |
167 | | - | processGroup.Wait() |
168 | | - | } else { |
169 | | - | color.HiRed("\n[!] Must give payload list") |
170 | | - | } |
171 | | - | } else { |
172 | | - | color.HiRed("\n[!] Check: LfiMe -h for arguments") |
173 | | - | } |
174 | | - | } |
175 | | - | |