1
1
Fork 0
mirror of https://github.com/OJ/gobuster.git synced 2024-05-13 00:46:05 +02:00

Add support for network interface selection #45

This commit is contained in:
Christian Mehlmauer 2024-04-23 09:00:47 +02:00
parent 660e20f526
commit d46567c609
10 changed files with 105 additions and 7 deletions

View File

@ -43,6 +43,7 @@ All funds that are donated to this project will be donated to charity. A full lo
- automatically disable progress output when output is redirected
- fix extra special characters when run with `--no-progress`
- warn when using vhost mode with a proxy and http based urls as this might not work as expected
- add `interface` and `local-ip` parameters to specify the interface for http requests
## 3.6

View File

@ -4,6 +4,7 @@ import (
"bufio"
"crypto/tls"
"fmt"
"net"
"os"
"regexp"
"strconv"
@ -31,6 +32,8 @@ func BasicHTTPOptions() []cli.Flag {
&cli.StringFlag{Name: "client-cert-pem-key", Aliases: []string{"ccpk"}, Usage: "private key in PEM format for optional TLS client certificates (this key needs to have no password)"},
&cli.StringFlag{Name: "client-cert-p12", Aliases: []string{"ccp12"}, Usage: "a p12 file to use for options TLS client certificates"},
&cli.StringFlag{Name: "client-cert-p12-password", Aliases: []string{"ccp12p"}, Usage: "the password to the p12 file"},
&cli.StringFlag{Name: "interface", Aliases: []string{"iface"}, Usage: "specify network interface to use. Can't be used with local-ip"},
&cli.StringFlag{Name: "local-ip", Usage: "specify local ip of network interface to use. Can't be used with interface"},
}
}
@ -81,6 +84,27 @@ func ParseBasicHTTPOptions(c *cli.Context) (libgobuster.BasicHTTPOptions, error)
}
}
iface := c.String("interface")
localIP := c.String("local-ip")
if iface != "" && localIP != "" {
return opts, fmt.Errorf("can not set both interface and local-ip")
}
switch {
case iface != "":
a, err := getLocalAddrFromInterface(iface)
if err != nil {
return opts, err
}
opts.LocalAddr = a
case localIP != "":
a, err := net.ResolveIPAddr("ip", localIP)
if err != nil {
return opts, err
}
opts.LocalAddr = a
}
return opts, nil
}
@ -238,3 +262,28 @@ func ParseGlobalOptions(c *cli.Context) (libgobuster.Options, error) {
opts.Debug = c.Bool("debug")
return opts, nil
}
func getLocalAddrFromInterface(iface string) (net.Addr, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, fmt.Errorf("could not get interfaces: %w", err)
}
for _, i := range ifaces {
if i.Name == iface {
addrs, err := i.Addrs()
if err != nil {
return nil, fmt.Errorf("could not get local addrs for iface %s: %w", i.Name, err)
}
for _, a := range addrs {
switch v := a.(type) {
case *net.IPAddr:
return v, nil
case *net.IPNet:
return v, nil
}
}
}
}
return nil, fmt.Errorf("could not find ip for interface %s", iface)
}

View File

@ -368,6 +368,12 @@ func (d *GobusterDir) GetConfigString() (string, error) {
}
}
if o.BasicHTTPOptions.LocalAddr != nil {
if _, err := fmt.Fprintf(tw, "[+] Local IP:\t%s\n", o.BasicHTTPOptions.LocalAddr); err != nil {
return "", err
}
}
if o.HideLength {
if _, err := fmt.Fprintf(tw, "[+] Show length:\tfalse\n"); err != nil {
return "", err

View File

@ -266,6 +266,12 @@ func (d *GobusterFuzz) GetConfigString() (string, error) {
}
}
if o.BasicHTTPOptions.LocalAddr != nil {
if _, err := fmt.Fprintf(tw, "[+] Local IP:\t%s\n", o.BasicHTTPOptions.LocalAddr); err != nil {
return "", err
}
}
if o.Username != "" {
if _, err := fmt.Fprintf(tw, "[+] Auth User:\t%s\n", o.Username); err != nil {
return "", err

View File

@ -245,6 +245,12 @@ func (s *GobusterGCS) GetConfigString() (string, error) {
}
}
if o.BasicHTTPOptions.LocalAddr != nil {
if _, err := fmt.Fprintf(tw, "[+] Local IP:\t%s\n", o.BasicHTTPOptions.LocalAddr); err != nil {
return "", err
}
}
if _, err := fmt.Fprintf(tw, "[+] Timeout:\t%s\n", o.Timeout.String()); err != nil {
return "", err
}

View File

@ -236,6 +236,12 @@ func (s *GobusterS3) GetConfigString() (string, error) {
}
}
if o.BasicHTTPOptions.LocalAddr != nil {
if _, err := fmt.Fprintf(tw, "[+] Local IP:\t%s\n", o.BasicHTTPOptions.LocalAddr); err != nil {
return "", err
}
}
if _, err := fmt.Fprintf(tw, "[+] Timeout:\t%s\n", o.Timeout.String()); err != nil {
return "", err
}

View File

@ -266,6 +266,12 @@ func (v *GobusterVhost) GetConfigString() (string, error) {
}
}
if o.BasicHTTPOptions.LocalAddr != nil {
if _, err := fmt.Fprintf(tw, "[+] Local IP:\t%s\n", o.BasicHTTPOptions.LocalAddr); err != nil {
return "", err
}
}
if o.Username != "" {
if _, err := fmt.Fprintf(tw, "[+] Auth User:\t%s\n", o.Username); err != nil {
return "", err

View File

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
@ -79,15 +80,28 @@ func NewHTTPClient(opt *HTTPOptions, logger *Logger) (*HTTPClient, error) {
tlsConfig.Certificates = []tls.Certificate{*opt.TLSCertificate}
}
transport := &http.Transport{
Proxy: proxyURLFunc,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
TLSClientConfig: &tlsConfig,
}
// set specific network interface
if opt.LocalAddr != nil {
dialer := &net.Dialer{
Timeout: opt.Timeout,
LocalAddr: opt.LocalAddr,
}
transport.DialContext = dialer.DialContext
}
client.client = &http.Client{
Timeout: opt.Timeout,
CheckRedirect: redirectFunc,
Transport: &http.Transport{
Proxy: proxyURLFunc,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
TLSClientConfig: &tlsConfig,
}}
Transport: transport,
}
client.username = opt.Username
client.password = opt.Password
client.userAgent = opt.UserAgent

View File

@ -1,6 +1,8 @@
package libgobuster
import "time"
import (
"time"
)
// Options holds all options that can be passed to libgobuster
type Options struct {

View File

@ -2,6 +2,7 @@ package libgobuster
import (
"crypto/tls"
"net"
"time"
)
@ -14,6 +15,7 @@ type BasicHTTPOptions struct {
RetryOnTimeout bool
RetryAttempts int
TLSCertificate *tls.Certificate
LocalAddr net.Addr
}
// HTTPOptions is the struct to pass in all http options to Gobuster