Add support for cookies, status codes, and more

* Cookies can now be added in case you want to brute force something
  when authenticated. Use the -c flag.
* If you want to add a trailing slash to the DIR busting, you can now
  set -f=true.
* -v=true now says "output verbose" which shows the result for every
  request that is made (except the first).
* You can specify your own positive status codes on the command line
  now through the -s=... parameter.
This commit is contained in:
OJ
2015-02-01 21:36:08 +10:00
parent 645201dfad
commit f0004634a7
+104 -29
View File
@@ -18,18 +18,27 @@ import (
"fmt"
"net/http"
"os"
"strconv"
"strings"
"sync"
)
// Shim type for "set"
type IntSet struct {
set map[int]bool
}
// Contains settings that are read in from the command
// line when the program is invoked.
type Settings struct {
Threads int
Wordlist string
Url string
Extensions []string
ShowAll bool
Threads int
Wordlist string
Url string
Cookies string
Extensions []string
StatusCodes IntSet
ShowAll bool
UseSlash bool
}
// A single result which comes from an individual web
@@ -39,9 +48,41 @@ type Result struct {
Status int
}
// Add an element to a set
func (set *IntSet) Add(i int) bool {
_, found := set.set[i]
set.set[i] = true
return !found
}
// Test if an element is in a set
func (set *IntSet) Contains(i int) bool {
_, found := set.set[i]
return found
}
// Stringify the set
func (set *IntSet) Stringify() string {
values := []string{}
for s, _ := range set.set {
values = append(values, strconv.Itoa(s))
}
return strings.Join(values, ",")
}
// Make a request to the given URL.
func MakeRequest(url string) *int {
resp, err := http.Get(url)
func MakeRequest(client *http.Client, url, cookie string) *int {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil
}
if cookie != "" {
req.Header.Set("Cookie", cookie)
}
resp, err := client.Do(req)
if err != nil {
return nil
@@ -54,22 +95,27 @@ func MakeRequest(url string) *int {
// Small helper to combine URL with URI then make a
// request to the generated location.
func GoGet(url, uri string) *int {
return MakeRequest(url + uri)
func GoGet(client *http.Client, url, uri, cookie string) *int {
return MakeRequest(client, url+uri, cookie)
}
// Parse all the command line options into a settings
// instance for future use.
func ParseCmdLine() *Settings {
var extensions string
s := Settings{}
var codes string
s := Settings{StatusCodes: IntSet{set: map[int]bool{}}}
// Set up the variables we're interested in parsing.
flag.IntVar(&s.Threads, "t", 10, "Number of concurrent threads")
flag.StringVar(&s.Wordlist, "w", "", "Path to the wordlist")
flag.StringVar(&codes, "s", "200,204,301,302,307", "Positive status codes")
flag.StringVar(&s.Url, "u", "", "The target URL")
flag.StringVar(&s.Cookies, "c", "", "Cookies to use for the requests")
flag.StringVar(&extensions, "x", "", "File extension(s) to search for")
flag.BoolVar(&s.ShowAll, "s", false, "Show all results (not just positives)")
flag.BoolVar(&s.ShowAll, "v", false, "Show all results (not just positives)")
flag.BoolVar(&s.UseSlash, "f", false, "Append a forward-slash to each directory request")
flag.Parse()
@@ -102,7 +148,19 @@ func ParseCmdLine() *Settings {
s.Extensions = strings.Split(extensions, ",")
}
if GoGet(s.Url, "") == nil {
// status codes are comma seaprated
if codes != "" {
for _, c := range strings.Split(codes, ",") {
i, err := strconv.Atoi(c)
if err != nil {
panic("Invalid status code given")
}
s.StatusCodes.Add(i)
}
}
client := &http.Client{}
if GoGet(client, s.Url, "", s.Cookies) == nil {
fmt.Println("Url (-u): Unable to connect", s.Url)
}
@@ -126,6 +184,13 @@ func Process(s *Settings) {
wg := new(sync.WaitGroup)
wg.Add(s.Threads)
client := &http.Client{}
suffix := ""
if s.UseSlash {
suffix = "/"
}
// Create goroutines for each of the number of threads
// specified.
for i := 0; i < s.Threads; i++ {
@@ -138,11 +203,11 @@ func Process(s *Settings) {
break
}
// Try the DIR first.
dirResp := GoGet(s.Url, word)
// Try the DIR first
dirResp := GoGet(client, s.Url, word+suffix, s.Cookies)
if dirResp != nil {
resultChan <- Result{
Uri: word,
Uri: word + suffix,
Status: *dirResp,
}
}
@@ -150,7 +215,7 @@ func Process(s *Settings) {
// Follow up with files using each ext.
for ext := range s.Extensions {
file := word + s.Extensions[ext]
fileResp := GoGet(s.Url, file)
fileResp := GoGet(client, s.Url, file, s.Cookies)
if fileResp != nil {
resultChan <- Result{
Uri: file,
@@ -170,17 +235,14 @@ func Process(s *Settings) {
// appear from the worker threads.
go func() {
for r := range resultChan {
switch r.Status {
// Only print results out if we find something
// meaningful.
case 200, 204, 301, 302, 307:
if s.StatusCodes.Contains(r.Status) {
// Only print results out if we find something
// meaningful.
fmt.Printf("Found: /%s (%d)\n", r.Uri, r.Status)
default:
} else if s.ShowAll {
// Print out other results if the user wants to
// see them.
if s.ShowAll {
fmt.Printf("Result: /%s (%d)\n", r.Uri, r.Status)
}
fmt.Printf("Result: /%s (%d)\n", r.Uri, r.Status)
}
}
}()
@@ -204,7 +266,7 @@ func Process(s *Settings) {
}
func main() {
fmt.Println("Gobuster v0.1 (OJ Reeves @TheColonial)")
fmt.Println("Gobuster v0.2 (OJ Reeves @TheColonial)")
fmt.Println("======================================")
settings := ParseCmdLine()
@@ -213,12 +275,25 @@ func main() {
return
}
fmt.Printf("[+] Url : %s\n", settings.Url)
fmt.Printf("[+] Threads : %d\n", settings.Threads)
fmt.Printf("[+] Wordlist : %s\n", settings.Wordlist)
fmt.Printf("[+] Url : %s\n", settings.Url)
fmt.Printf("[+] Threads : %d\n", settings.Threads)
fmt.Printf("[+] Wordlist : %s\n", settings.Wordlist)
fmt.Printf("[+] Status codes : %s\n", settings.StatusCodes.Stringify())
if settings.Cookies != "" {
fmt.Printf("[+] Cookies : %s\n", settings.Cookies)
}
if len(settings.Extensions) > 0 {
fmt.Printf("[+] Extensions : %s\n", strings.Join(settings.Extensions, ","))
fmt.Printf("[+] Extensions : %s\n", strings.Join(settings.Extensions, ","))
}
if settings.UseSlash {
fmt.Printf("[+] Add Slash : true\n")
}
if settings.ShowAll {
fmt.Printf("[+] Dislpay all : true\n")
}
fmt.Println("======================================")