mirror of
https://github.com/OJ/gobuster.git
synced 2024-05-19 02:36:02 +02:00
implement VHOST bruteforcing
This commit is contained in:
parent
ef6e9b00c1
commit
59029be1e8
48
README.md
48
README.md
|
@ -43,6 +43,7 @@ All funds that are donated to this project will be donated to charity. A full lo
|
|||
```text
|
||||
dir uses dir mode
|
||||
dns uses dns mode
|
||||
vhost uses vhost mode
|
||||
```
|
||||
|
||||
## Common Command line options
|
||||
|
@ -91,6 +92,21 @@ dns uses dns mode
|
|||
--wildcard Force continued operation when wildcard found
|
||||
```
|
||||
|
||||
## Command line options for `vhost` mode
|
||||
|
||||
```text
|
||||
-c, --cookies string Cookies to use for the requests
|
||||
-h, --help help for vhost
|
||||
-k, --insecuressl Skip SSL certificate verification
|
||||
-P, --password string Password for Basic Auth
|
||||
-p, --proxy string Proxy to use for requests [http(s)://host:port]
|
||||
--timeout duration HTTP Timeout (default 10s)
|
||||
-u, --url string The target URL
|
||||
-a, --useragent string Set the User-Agent string (default "gobuster 2.0.1")
|
||||
-U, --username string Username for Basic Auth
|
||||
--wildcard Force continued operation when wildcard found
|
||||
```
|
||||
|
||||
## Easy Installation
|
||||
|
||||
### Binary Releases
|
||||
|
@ -435,6 +451,38 @@ Found: test.127.0.0.1.xip.io
|
|||
=====================================================
|
||||
```
|
||||
|
||||
### `vhost` mode
|
||||
|
||||
Command line might look like this:
|
||||
|
||||
```bash
|
||||
gobuster vhost -u https://mysite.com -w common-vhosts.txt
|
||||
```
|
||||
|
||||
Normal sample run goes like this:
|
||||
|
||||
```bash
|
||||
gobuster vhost -u https://mysite.com -w common-vhosts.txt
|
||||
|
||||
=====================================================
|
||||
Gobuster v2.0.1 OJ Reeves (@TheColonial)
|
||||
=====================================================
|
||||
[+] Url: https://mysite.com
|
||||
[+] Threads: 10
|
||||
[+] Wordlist: common-vhosts.txt
|
||||
[+] User Agent: gobuster 2.0.1
|
||||
[+] Timeout: 10s
|
||||
=====================================================
|
||||
2018/10/09 08:36:00 Starting gobuster
|
||||
=====================================================
|
||||
Found: www.mysite.com
|
||||
Found: piwik.mysite.com
|
||||
Found: mail.mysite.com
|
||||
=====================================================
|
||||
2018/10/09 08:36:05 Finished
|
||||
=====================================================
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
See the LICENSE file.
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/OJ/gobuster/cli"
|
||||
"github.com/OJ/gobuster/gobustervhost"
|
||||
"github.com/OJ/gobuster/libgobuster"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var cmdVhost *cobra.Command
|
||||
|
||||
func runVhost(cmd *cobra.Command, args []string) error {
|
||||
globalopts, pluginopts, err := parseVhostOptions()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on parsing arguments: %v", err)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
plugin, err := gobustervhost.NewGobusterVhost(ctx, globalopts, pluginopts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error on creating gobustervhost: %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 parseVhostOptions() (*libgobuster.Options, *gobustervhost.OptionsVhost, error) {
|
||||
globalopts, err := parseGlobalOptions()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var plugin gobustervhost.OptionsVhost
|
||||
|
||||
url, err := cmdVhost.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cookies, err := cmdVhost.Flags().GetString("cookies")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid value for cookies: %v", err)
|
||||
}
|
||||
plugin.Cookies = cookies
|
||||
|
||||
username, err := cmdVhost.Flags().GetString("username")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid value for username: %v", err)
|
||||
}
|
||||
plugin.Username = username
|
||||
|
||||
password, err := cmdVhost.Flags().GetString("password")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid value for password: %v", err)
|
||||
}
|
||||
plugin.Password = password
|
||||
|
||||
useragent, err := cmdVhost.Flags().GetString("useragent")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid value for useragent: %v", err)
|
||||
}
|
||||
plugin.UserAgent = useragent
|
||||
|
||||
proxy, err := cmdVhost.Flags().GetString("proxy")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid value for proxy: %v", err)
|
||||
}
|
||||
plugin.Proxy = proxy
|
||||
|
||||
timeout, err := cmdVhost.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
|
||||
|
||||
insecuressl, err := cmdVhost.Flags().GetBool("insecuressl")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid value for insecuressl: %v", err)
|
||||
}
|
||||
plugin.InsecureSSL = insecuressl
|
||||
|
||||
// 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() {
|
||||
cmdVhost = &cobra.Command{
|
||||
Use: "vhost",
|
||||
Short: "Uses VHOST bruteforcing mode",
|
||||
RunE: runVhost,
|
||||
}
|
||||
cmdVhost.Flags().StringP("url", "u", "", "The target URL")
|
||||
cmdVhost.Flags().StringP("cookies", "c", "", "Cookies to use for the requests")
|
||||
cmdVhost.Flags().StringP("username", "U", "", "Username for Basic Auth")
|
||||
cmdVhost.Flags().StringP("password", "P", "", "Password for Basic Auth")
|
||||
cmdVhost.Flags().StringP("useragent", "a", libgobuster.DefaultUserAgent(), "Set the User-Agent string")
|
||||
cmdVhost.Flags().StringP("proxy", "p", "", "Proxy to use for requests [http(s)://host:port]")
|
||||
cmdVhost.Flags().DurationP("timeout", "", 10*time.Second, "HTTP Timeout")
|
||||
cmdVhost.Flags().BoolP("followredirect", "r", true, "Follow redirects")
|
||||
cmdVhost.Flags().BoolP("insecuressl", "k", false, "Skip SSL certificate verification")
|
||||
if err := cmdVhost.MarkFlagRequired("url"); err != nil {
|
||||
log.Fatalf("error on marking flag as required: %v", err)
|
||||
}
|
||||
|
||||
cmdVhost.PersistentPreRun = func(cmd *cobra.Command, args []string) {
|
||||
configureGlobalOptions()
|
||||
}
|
||||
|
||||
rootCmd.AddCommand(cmdVhost)
|
||||
}
|
|
@ -17,13 +17,13 @@ import (
|
|||
type GobusterDir struct {
|
||||
options *OptionsDir
|
||||
globalopts *libgobuster.Options
|
||||
http *httpClient
|
||||
http *libgobuster.HTTPClient
|
||||
}
|
||||
|
||||
// GetRequest issues a GET request to the target and returns
|
||||
// the status code, length and an error
|
||||
func (d *GobusterDir) get(url string) (*int, *int64, error) {
|
||||
return d.http.makeRequest(url, d.options.Cookies)
|
||||
return d.http.Get(url, "", d.options.Cookies)
|
||||
}
|
||||
|
||||
// NewGobusterDir creates a new initialized GobusterDir
|
||||
|
@ -40,7 +40,18 @@ func NewGobusterDir(cont context.Context, globalopts *libgobuster.Options, opts
|
|||
options: opts,
|
||||
globalopts: globalopts,
|
||||
}
|
||||
h, err := newHTTPClient(cont, opts)
|
||||
|
||||
httpOpts := libgobuster.HTTPOptions{
|
||||
Proxy: opts.Proxy,
|
||||
FollowRedirect: opts.FollowRedirect,
|
||||
InsecureSSL: opts.InsecureSSL,
|
||||
Timeout: opts.Timeout,
|
||||
Username: opts.Username,
|
||||
Password: opts.Password,
|
||||
UserAgent: opts.UserAgent,
|
||||
}
|
||||
|
||||
h, err := libgobuster.NewHTTPClient(cont, &httpOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -68,7 +79,6 @@ func (d *GobusterDir) PreRun() error {
|
|||
}
|
||||
|
||||
if d.options.StatusCodesParsed.Contains(*wildcardResp) {
|
||||
d.options.IsWildcard = true
|
||||
log.Printf("[-] Wildcard response found: %s => %d", url, *wildcardResp)
|
||||
if !d.options.WildcardForced {
|
||||
return fmt.Errorf("To force processing of Wildcard responses, specify the '--wildcard' switch.")
|
||||
|
|
|
@ -25,7 +25,6 @@ type OptionsDir struct {
|
|||
NoStatus bool
|
||||
InsecureSSL bool
|
||||
UseSlash bool
|
||||
IsWildcard bool
|
||||
WildcardForced bool
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
package gobustervhost
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/OJ/gobuster/libgobuster"
|
||||
)
|
||||
|
||||
// GobusterVhost is the main type to implement the interface
|
||||
type GobusterVhost struct {
|
||||
options *OptionsVhost
|
||||
globalopts *libgobuster.Options
|
||||
http *libgobuster.HTTPClient
|
||||
domain string
|
||||
baseResponse string
|
||||
}
|
||||
|
||||
// NewGobusterVhost creates a new initialized GobusterDir
|
||||
func NewGobusterVhost(cont context.Context, globalopts *libgobuster.Options, opts *OptionsVhost) (*GobusterVhost, error) {
|
||||
if globalopts == nil {
|
||||
return nil, fmt.Errorf("please provide valid global options")
|
||||
}
|
||||
|
||||
if opts == nil {
|
||||
return nil, fmt.Errorf("please provide valid plugin options")
|
||||
}
|
||||
|
||||
g := GobusterVhost{
|
||||
options: opts,
|
||||
globalopts: globalopts,
|
||||
}
|
||||
|
||||
httpOpts := libgobuster.HTTPOptions{
|
||||
Proxy: opts.Proxy,
|
||||
FollowRedirect: opts.FollowRedirect,
|
||||
InsecureSSL: opts.InsecureSSL,
|
||||
Timeout: opts.Timeout,
|
||||
Username: opts.Username,
|
||||
Password: opts.Password,
|
||||
UserAgent: opts.UserAgent,
|
||||
}
|
||||
|
||||
h, err := libgobuster.NewHTTPClient(cont, &httpOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.http = h
|
||||
return &g, nil
|
||||
}
|
||||
|
||||
// PreRun is the pre run implementation of gobusterdir
|
||||
func (v *GobusterVhost) PreRun() error {
|
||||
|
||||
// add trailing slash
|
||||
if !strings.HasSuffix(v.options.URL, "/") {
|
||||
v.options.URL = fmt.Sprintf("%s/", v.options.URL)
|
||||
}
|
||||
|
||||
url, err := url.Parse(v.options.URL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid url %s: %v", v.options.URL, err)
|
||||
}
|
||||
v.domain = url.Host
|
||||
|
||||
_, bodyBase, err := v.http.GetBody(v.options.URL, "", v.options.Cookies)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to connect to %s: %v", v.options.URL, err)
|
||||
}
|
||||
v.baseResponse = *bodyBase
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run is the process implementation of gobusterdir
|
||||
func (v *GobusterVhost) Run(word string) ([]libgobuster.Result, error) {
|
||||
subdomain := fmt.Sprintf("%s.%s", word, v.domain)
|
||||
_, body, err := v.http.GetBody(v.options.URL, subdomain, v.options.Cookies)
|
||||
var ret []libgobuster.Result
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
if *body != v.baseResponse {
|
||||
result := libgobuster.Result{
|
||||
Entity: subdomain,
|
||||
}
|
||||
ret = append(ret, result)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ResultToString is the to string implementation of gobusterdir
|
||||
func (v *GobusterVhost) ResultToString(r *libgobuster.Result) (*string, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
if _, err := fmt.Fprintf(buf, "Found: %s\n", r.Entity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := buf.String()
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
// GetConfigString returns the string representation of the current config
|
||||
func (v *GobusterVhost) GetConfigString() (string, error) {
|
||||
var buffer bytes.Buffer
|
||||
bw := bufio.NewWriter(&buffer)
|
||||
tw := tabwriter.NewWriter(bw, 0, 5, 3, ' ', 0)
|
||||
o := v.options
|
||||
if _, err := fmt.Fprintf(tw, "[+] Url:\t%s\n", o.URL); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := fmt.Fprintf(tw, "[+] Threads:\t%d\n", v.globalopts.Threads); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
wordlist := "stdin (pipe)"
|
||||
if v.globalopts.Wordlist != "-" {
|
||||
wordlist = v.globalopts.Wordlist
|
||||
}
|
||||
if _, err := fmt.Fprintf(tw, "[+] Wordlist:\t%s\n", wordlist); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if o.Proxy != "" {
|
||||
if _, err := fmt.Fprintf(tw, "[+] Proxy:\t%s\n", o.Proxy); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if o.Cookies != "" {
|
||||
if _, err := fmt.Fprintf(tw, "[+] Cookies:\t%s\n", o.Cookies); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if o.UserAgent != "" {
|
||||
if _, err := fmt.Fprintf(tw, "[+] User Agent:\t%s\n", o.UserAgent); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if o.Username != "" {
|
||||
if _, err := fmt.Fprintf(tw, "[+] Auth User:\t%s\n", o.Username); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if v.globalopts.Verbose {
|
||||
if _, err := fmt.Fprintf(tw, "[+] Verbose:\ttrue\n"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(tw, "[+] Timeout:\t%s\n", o.Timeout.String()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := tw.Flush(); err != nil {
|
||||
return "", fmt.Errorf("error on tostring: %v", err)
|
||||
}
|
||||
|
||||
if err := bw.Flush(); err != nil {
|
||||
return "", fmt.Errorf("error on tostring: %v", err)
|
||||
}
|
||||
|
||||
return strings.TrimSpace(buffer.String()), nil
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package gobustervhost
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// OptionsVhost is the struct to hold all options for this plugin
|
||||
type OptionsVhost struct {
|
||||
Password string
|
||||
URL string
|
||||
UserAgent string
|
||||
Username string
|
||||
Proxy string
|
||||
Cookies string
|
||||
Timeout time.Duration
|
||||
InsecureSSL bool
|
||||
FollowRedirect bool
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package gobusterdir
|
||||
package libgobuster
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -9,12 +9,12 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/OJ/gobuster/v3/libgobuster"
|
||||
)
|
||||
|
||||
type httpClient struct {
|
||||
// HTTPClient represents a http object
|
||||
type HTTPClient struct {
|
||||
client *http.Client
|
||||
context context.Context
|
||||
userAgent string
|
||||
|
@ -23,10 +23,22 @@ type httpClient struct {
|
|||
includeLength bool
|
||||
}
|
||||
|
||||
// HTTPOptions provides options to the http client
|
||||
type HTTPOptions struct {
|
||||
Proxy string
|
||||
Username string
|
||||
Password string
|
||||
UserAgent string
|
||||
Timeout time.Duration
|
||||
FollowRedirect bool
|
||||
InsecureSSL bool
|
||||
IncludeLength bool
|
||||
}
|
||||
|
||||
// NewHTTPClient returns a new HTTPClient
|
||||
func newHTTPClient(c context.Context, opt *OptionsDir) (*httpClient, error) {
|
||||
func NewHTTPClient(c context.Context, opt *HTTPOptions) (*HTTPClient, error) {
|
||||
var proxyURLFunc func(*http.Request) (*url.URL, error)
|
||||
var client httpClient
|
||||
var client HTTPClient
|
||||
proxyURLFunc = http.ProxyFromEnvironment
|
||||
|
||||
if opt == nil {
|
||||
|
@ -67,42 +79,12 @@ func newHTTPClient(c context.Context, opt *OptionsDir) (*httpClient, error) {
|
|||
return &client, nil
|
||||
}
|
||||
|
||||
// MakeRequest makes a request to the specified url
|
||||
func (client *httpClient) makeRequest(fullURL, cookie string) (*int, *int64, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, fullURL, nil)
|
||||
|
||||
// Get makes an http request and returns the status, the length and an error
|
||||
func (client *HTTPClient) Get(fullURL, host, cookie string) (*int, *int64, error) {
|
||||
resp, err := client.makeRequest(fullURL, host, cookie)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// add the context so we can easily cancel out
|
||||
req = req.WithContext(client.context)
|
||||
|
||||
if cookie != "" {
|
||||
req.Header.Set("Cookie", cookie)
|
||||
}
|
||||
|
||||
ua := libgobuster.DefaultUserAgent()
|
||||
if client.userAgent != "" {
|
||||
ua = client.userAgent
|
||||
}
|
||||
req.Header.Set("User-Agent", ua)
|
||||
|
||||
if client.username != "" {
|
||||
req.SetBasicAuth(client.username, client.password)
|
||||
}
|
||||
|
||||
resp, err := client.client.Do(req)
|
||||
if err != nil {
|
||||
if ue, ok := err.(*url.Error); ok {
|
||||
|
||||
if strings.HasPrefix(ue.Err.Error(), "x509") {
|
||||
return nil, nil, fmt.Errorf("Invalid certificate: %v", ue.Err)
|
||||
}
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
var length *int64
|
||||
|
@ -120,7 +102,7 @@ func (client *httpClient) makeRequest(fullURL, cookie string) (*int, *int64, err
|
|||
} else {
|
||||
// DO NOT REMOVE!
|
||||
// absolutely needed so golang will reuse connections!
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
_, err := io.Copy(ioutil.Discard, resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -128,3 +110,60 @@ func (client *httpClient) makeRequest(fullURL, cookie string) (*int, *int64, err
|
|||
|
||||
return &resp.StatusCode, length, nil
|
||||
}
|
||||
|
||||
// GetBody makes an http request and returns the status and the body
|
||||
func (client *HTTPClient) GetBody(fullURL, host, cookie string) (*int, *string, error) {
|
||||
resp, err := client.makeRequest(fullURL, host, cookie)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not read body: %v", err)
|
||||
}
|
||||
bodyString := string(body)
|
||||
|
||||
return &resp.StatusCode, &bodyString, nil
|
||||
}
|
||||
|
||||
func (client *HTTPClient) makeRequest(fullURL, host, cookie string) (*http.Response, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, fullURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// add the context so we can easily cancel out
|
||||
req = req.WithContext(client.context)
|
||||
|
||||
if cookie != "" {
|
||||
req.Header.Set("Cookie", cookie)
|
||||
}
|
||||
|
||||
if host != "" {
|
||||
req.Host = host
|
||||
}
|
||||
|
||||
ua := DefaultUserAgent()
|
||||
if client.userAgent != "" {
|
||||
ua = client.userAgent
|
||||
}
|
||||
req.Header.Set("User-Agent", ua)
|
||||
|
||||
if client.username != "" {
|
||||
req.SetBasicAuth(client.username, client.password)
|
||||
}
|
||||
|
||||
resp, err := client.client.Do(req)
|
||||
if err != nil {
|
||||
if ue, ok := err.(*url.Error); ok {
|
||||
|
||||
if strings.HasPrefix(ue.Err.Error(), "x509") {
|
||||
return nil, fmt.Errorf("Invalid certificate: %v", ue.Err)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package gobusterdir
|
||||
package libgobuster
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -19,12 +19,12 @@ func httpServer(t *testing.T, content string) *httptest.Server {
|
|||
func TestMakeRequest(t *testing.T) {
|
||||
h := httpServer(t, "test")
|
||||
defer h.Close()
|
||||
o := NewOptionsDir()
|
||||
c, err := newHTTPClient(context.Background(), o)
|
||||
var o HTTPOptions
|
||||
c, err := NewHTTPClient(context.Background(), &o)
|
||||
if err != nil {
|
||||
t.Fatalf("Got Error: %v", err)
|
||||
}
|
||||
a, b, err := c.makeRequest(h.URL, "")
|
||||
a, b, err := c.Get(h.URL, "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Got Error: %v", err)
|
||||
}
|
Loading…
Reference in New Issue