1
1
Fork 0
mirror of https://github.com/OJ/gobuster.git synced 2024-06-02 06:36:03 +02:00
gobuster/cli/cmd/dir.go
Christian Mehlmauer b05bb53734
remove false text
it's not seconds, it's a duration which can be anything, for example 10m
or 1h
see https://golang.org/pkg/time/#ParseDuration
2018-10-02 08:13:22 +02:00

231 lines
7.1 KiB
Go

package cmd
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"regexp"
"strconv"
"strings"
"syscall"
"time"
"github.com/OJ/gobuster/cli"
"github.com/OJ/gobuster/gobusterdir"
"github.com/OJ/gobuster/libgobuster"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
)
var cmdDir *cobra.Command
func runDir(cmd *cobra.Command, args []string) error {
globalopts, pluginopts, err := parseDirOptions()
if err != nil {
return fmt.Errorf("error on parsing arguments: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
plugin, err := gobusterdir.NewGobusterDir(ctx, globalopts, pluginopts)
if err != nil {
return fmt.Errorf("error on creating gobusterdir: %v", err)
}
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
go func() {
for range signalChan {
// caught CTRL+C
if !globalopts.Quiet {
fmt.Println("\n[!] Keyboard interrupt detected, terminating.")
}
cancel()
}
}()
if err := cli.Gobuster(ctx, globalopts, plugin); err != nil {
return fmt.Errorf("error on running goubster: %v", err)
}
return nil
}
func parseDirOptions() (*libgobuster.Options, *gobusterdir.OptionsDir, error) {
globalopts, err := parseGlobalOptions()
if err != nil {
return nil, nil, err
}
plugin := gobusterdir.NewOptionsDir()
url, err := cmdDir.Flags().GetString("url")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for url: %v", err)
}
plugin.URL = url
if !strings.HasPrefix(plugin.URL, "http") {
// check to see if a port was specified
re := regexp.MustCompile(`^[^/]+:(\d+)`)
match := re.FindStringSubmatch(plugin.URL)
if len(match) < 2 {
// no port, default to http on 80
plugin.URL = fmt.Sprintf("http://%s", plugin.URL)
} else {
port, err2 := strconv.Atoi(match[1])
if err2 != nil || (port != 80 && port != 443) {
return nil, nil, fmt.Errorf("url scheme not specified")
} else if port == 80 {
plugin.URL = fmt.Sprintf("http://%s", plugin.URL)
} else {
plugin.URL = fmt.Sprintf("https://%s", plugin.URL)
}
}
}
statuscodes, err := cmdDir.Flags().GetString("statuscodes")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for statuscodes: %v", err)
}
plugin.StatusCodes = statuscodes
if err3 := plugin.ParseStatusCodes(); err3 != nil {
return nil, nil, fmt.Errorf("invalid value for statuscodes: %v", err3)
}
cookies, err := cmdDir.Flags().GetString("cookies")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for cookies: %v", err)
}
plugin.Cookies = cookies
username, err := cmdDir.Flags().GetString("username")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for username: %v", err)
}
plugin.Username = username
password, err := cmdDir.Flags().GetString("password")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for password: %v", err)
}
plugin.Password = password
extensions, err := cmdDir.Flags().GetString("extensions")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for extensions: %v", err)
}
plugin.Extensions = extensions
if extensions != "" {
if err2 := plugin.ParseExtensions(); err2 != nil {
return nil, nil, fmt.Errorf("invalid value for extensions: %v", err2)
}
}
useragent, err := cmdDir.Flags().GetString("useragent")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for useragent: %v", err)
}
plugin.UserAgent = useragent
proxy, err := cmdDir.Flags().GetString("proxy")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for proxy: %v", err)
}
plugin.Proxy = proxy
timeout, err := cmdDir.Flags().GetDuration("timeout")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for timeout: %v", err)
}
plugin.Timeout = timeout
followredirect, err := cmdDir.Flags().GetBool("followredirect")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for followredirect: %v", err)
}
plugin.FollowRedirect = followredirect
expanded, err := cmdDir.Flags().GetBool("expanded")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for expanded: %v", err)
}
plugin.Expanded = expanded
nostatus, err := cmdDir.Flags().GetBool("nostatus")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for nostatus: %v", err)
}
plugin.NoStatus = nostatus
includelength, err := cmdDir.Flags().GetBool("includelength")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for includelength: %v", err)
}
plugin.IncludeLength = includelength
insecuressl, err := cmdDir.Flags().GetBool("insecuressl")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for insecuressl: %v", err)
}
plugin.InsecureSSL = insecuressl
wildcard, err := cmdDir.Flags().GetBool("wildcard")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for wildcard: %v", err)
}
plugin.WildcardForced = wildcard
addslash, err := cmdDir.Flags().GetBool("addslash")
if err != nil {
return nil, nil, fmt.Errorf("invalid value for addslash: %v", err)
}
plugin.UseSlash = addslash
// Prompt for PW if not provided
if plugin.Username != "" && plugin.Password == "" {
fmt.Printf("[?] Auth Password: ")
passBytes, err := terminal.ReadPassword(int(syscall.Stdin))
// print a newline to simulate the newline that was entered
// this means that formatting/printing after doesn't look bad.
fmt.Println("")
if err != nil {
return nil, nil, fmt.Errorf("username given but reading of password failed")
}
plugin.Password = string(passBytes)
}
// if it's still empty bail out
if plugin.Username != "" && plugin.Password == "" {
return nil, nil, fmt.Errorf("username was provided but password is missing")
}
return globalopts, plugin, nil
}
func init() {
cmdDir = &cobra.Command{
Use: "dir",
Short: "uses dir mode",
RunE: runDir,
}
cmdDir.Flags().StringP("url", "u", "", "The target URL")
cmdDir.Flags().StringP("statuscodes", "s", "200,204,301,302,307,403", "Positive status codes")
cmdDir.Flags().StringP("cookies", "c", "", "Cookies to use for the requests")
cmdDir.Flags().StringP("username", "U", "", "Username for Basic Auth")
cmdDir.Flags().StringP("password", "P", "", "Password for Basic Auth")
cmdDir.Flags().StringP("extensions", "x", "", "File extension(s) to search for")
cmdDir.Flags().StringP("useragent", "a", libgobuster.DefaultUserAgent(), "Set the User-Agent string")
cmdDir.Flags().StringP("proxy", "p", "", "Proxy to use for requests [http(s)://host:port]")
cmdDir.Flags().DurationP("timeout", "", 10*time.Second, "HTTP Timeout")
cmdDir.Flags().BoolP("followredirect", "r", false, "Follow redirects")
cmdDir.Flags().BoolP("expanded", "e", false, "Expanded mode, print full URLs")
cmdDir.Flags().BoolP("nostatus", "n", false, "Don't print status codes")
cmdDir.Flags().BoolP("includelength", "l", false, "Include the length of the body in the output")
cmdDir.Flags().BoolP("insecuressl", "k", false, "Skip SSL certificate verification")
cmdDir.Flags().BoolP("addslash", "f", false, "Apped / to each request")
cmdDir.Flags().BoolP("wildcard", "", false, "Force continued operation when wildcard found")
if err := cmdDir.MarkFlagRequired("url"); err != nil {
log.Fatalf("error on marking flag as required: %v", err)
}
rootCmd.AddCommand(cmdDir)
}