1
1
Fork 0
mirror of https://github.com/OJ/gobuster.git synced 2024-05-06 11:16:05 +02:00
gobuster/libgobuster/http.go
Christian Mehlmauer 3bb230056c
Dev (#379)
* update to go 1.17

* more go 1.17 updates

* update sponsors

* update makefile

* gitignore

* remove todo

* Fixed errors mixing with progress in stderr by removing progress string with \r

* Added --retry option for dir, fuzz, s3 and vhost modes

* first dev version

* wording

* fix retries

* update help text

* first work for #298

allow for a totalrequests change from within a plugin

* use defer

* ignore invalid control character urls

* add goreleaser

* gitignore

* output color, better status printing

* more color output

* fix nil panics

* Added support for Google Cloud Storage (GCS) bucket scanning. The scanning finds all public buckets listable by anonymous users

* fix gcs module

* update readme

* go 1.18

* go mod tidy

* makefile

* readme

* readme

* better error message

* use generics for set

* use the new netip type

* update version

* colors

* cspell

* improve readability of GobusterVhost (#334)

* improve readability of GobusterVhost

* fix for the merge side effect

* lint

* update

* update

* more work

* remove unused method

* retries

* colored output

* Closes issue #349 (#356)

* fix version

* Closes issue #349

Co-authored-by: firefart <firefart@gmail.com>

* Closes issue #315 (#359)

* Closes issue #315

* Syntax fix

* support mtls

* readme

* check for fuzz keyword

* allow for http header fuzzing

* better description

* new option to not canonicalize header names

* basic auth fuzzing

* fix typo in vhost command (#361)

* update

* check error

* error handling

* dev

* enable tls1.0 and 1.1 support

* Bump golang.org/x/term from 0.1.0 to 0.2.0 (#369)

Bumps [golang.org/x/term](https://github.com/golang/term) from 0.1.0 to 0.2.0.
- [Release notes](https://github.com/golang/term/releases)
- [Commits](https://github.com/golang/term/compare/v0.1.0...v0.2.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump golang.org/x/crypto from 0.1.0 to 0.2.0 (#368)

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.1.0 to 0.2.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.1.0...v0.2.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Adds LF after the work end (#373)

* typo

* Reformat: Add `\n` after the end

Co-authored-by: firefart <105281+firefart@users.noreply.github.com>

* Bump golang.org/x/crypto from 0.2.0 to 0.3.0 (#374)

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.2.0 to 0.3.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump golang.org/x/crypto from 0.3.0 to 0.4.0 (#376)

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump actions/checkout from 3.1.0 to 3.2.0 (#377)

Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.1.0...v3.2.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add tftp mode

* better output on tftp mode

* Bump goreleaser/goreleaser-action from 3 to 4 (#378)

Bumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 3 to 4.
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](https://github.com/goreleaser/goreleaser-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: goreleaser/goreleaser-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* readme

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: alexmozzhakov <5459149+alexmozzhakov@users.noreply.github.com>
Co-authored-by: Nicolas Lykke Iversen <nlykkei@gmail.com>
Co-authored-by: Neal Caffery <neal1991@sina.com>
Co-authored-by: n30nx <22144985+n30nx@users.noreply.github.com>
Co-authored-by: IPv4v6 <mail.ipv4v6@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: _Magenta_ <0_magenta_0@mail.ru>
2022-12-19 11:47:58 +01:00

211 lines
5.5 KiB
Go

package libgobuster
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
// HTTPHeader holds a single key value pair of a HTTP header
type HTTPHeader struct {
Name string
Value string
}
// HTTPClient represents a http object
type HTTPClient struct {
client *http.Client
userAgent string
defaultUserAgent string
username string
password string
headers []HTTPHeader
noCanonicalizeHeaders bool
cookies string
method string
host string
}
// RequestOptions is used to pass options to a single individual request
type RequestOptions struct {
Host string
Body io.Reader
ReturnBody bool
ModifiedHeaders []HTTPHeader
UpdatedBasicAuthUsername string
UpdatedBasicAuthPassword string
}
// NewHTTPClient returns a new HTTPClient
func NewHTTPClient(opt *HTTPOptions) (*HTTPClient, error) {
var proxyURLFunc func(*http.Request) (*url.URL, error)
var client HTTPClient
proxyURLFunc = http.ProxyFromEnvironment
if opt == nil {
return nil, fmt.Errorf("options is nil")
}
if opt.Proxy != "" {
proxyURL, err := url.Parse(opt.Proxy)
if err != nil {
return nil, fmt.Errorf("proxy URL is invalid (%w)", err)
}
proxyURLFunc = http.ProxyURL(proxyURL)
}
var redirectFunc func(req *http.Request, via []*http.Request) error
if !opt.FollowRedirect {
redirectFunc = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
} else {
redirectFunc = nil
}
tlsConfig := tls.Config{
InsecureSkipVerify: opt.NoTLSValidation,
// enable TLS1.0 and TLS1.1 support
MinVersion: tls.VersionTLS10,
}
if opt.TLSCertificate != nil {
tlsConfig.Certificates = []tls.Certificate{*opt.TLSCertificate}
}
client.client = &http.Client{
Timeout: opt.Timeout,
CheckRedirect: redirectFunc,
Transport: &http.Transport{
Proxy: proxyURLFunc,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
TLSClientConfig: &tlsConfig,
}}
client.username = opt.Username
client.password = opt.Password
client.userAgent = opt.UserAgent
client.defaultUserAgent = DefaultUserAgent()
client.headers = opt.Headers
client.noCanonicalizeHeaders = opt.NoCanonicalizeHeaders
client.cookies = opt.Cookies
client.method = opt.Method
if client.method == "" {
client.method = http.MethodGet
}
// Host header needs to be set separately
for _, h := range opt.Headers {
if h.Name == "Host" {
client.host = h.Value
break
}
}
return &client, nil
}
// Request makes an http request and returns the status, the content length, the headers, the body and an error
// if you want the body returned set the corresponding property inside RequestOptions
func (client *HTTPClient) Request(ctx context.Context, fullURL string, opts RequestOptions) (int, int64, http.Header, []byte, error) {
resp, err := client.makeRequest(ctx, fullURL, opts)
if err != nil {
// ignore context canceled errors
if errors.Is(ctx.Err(), context.Canceled) {
return 0, 0, nil, nil, nil
}
return 0, 0, nil, nil, err
}
defer resp.Body.Close()
var body []byte
var length int64
if opts.ReturnBody {
body, err = io.ReadAll(resp.Body)
if err != nil {
return 0, 0, nil, nil, fmt.Errorf("could not read body %w", err)
}
length = int64(len(body))
} else {
// DO NOT REMOVE!
// absolutely needed so golang will reuse connections!
length, err = io.Copy(io.Discard, resp.Body)
if err != nil {
return 0, 0, nil, nil, err
}
}
return resp.StatusCode, length, resp.Header, body, nil
}
func (client *HTTPClient) makeRequest(ctx context.Context, fullURL string, opts RequestOptions) (*http.Response, error) {
req, err := http.NewRequest(client.method, fullURL, opts.Body)
if err != nil {
return nil, err
}
// add the context so we can easily cancel out
req = req.WithContext(ctx)
if client.cookies != "" {
req.Header.Set("Cookie", client.cookies)
}
// Use host for VHOST mode on a per request basis, otherwise the one provided from headers
if opts.Host != "" {
req.Host = opts.Host
} else if client.host != "" {
req.Host = client.host
}
if client.userAgent != "" {
req.Header.Set("User-Agent", client.userAgent)
} else {
req.Header.Set("User-Agent", client.defaultUserAgent)
}
// add custom headers
// if ModifiedHeaders are supplied use those, otherwise use the original ones
// currently only relevant on fuzzing
if len(opts.ModifiedHeaders) > 0 {
for _, h := range opts.ModifiedHeaders {
if client.noCanonicalizeHeaders {
// https://stackoverflow.com/questions/26351716/how-to-keep-key-case-sensitive-in-request-header-using-golang
req.Header[h.Name] = []string{h.Value}
} else {
req.Header.Set(h.Name, h.Value)
}
}
} else {
for _, h := range client.headers {
if client.noCanonicalizeHeaders {
// https://stackoverflow.com/questions/26351716/how-to-keep-key-case-sensitive-in-request-header-using-golang
req.Header[h.Name] = []string{h.Value}
} else {
req.Header.Set(h.Name, h.Value)
}
}
}
if opts.UpdatedBasicAuthUsername != "" {
req.SetBasicAuth(opts.UpdatedBasicAuthUsername, opts.UpdatedBasicAuthPassword)
} else if client.username != "" {
req.SetBasicAuth(client.username, client.password)
}
resp, err := client.client.Do(req)
if err != nil {
var ue *url.Error
if errors.As(err, &ue) {
if strings.HasPrefix(ue.Err.Error(), "x509") {
return nil, fmt.Errorf("invalid certificate: %w", ue.Err)
}
}
return nil, err
}
return resp, nil
}