manual merging dev

This commit is contained in:
mzack 2021-08-07 13:46:20 +02:00
commit 13fa589288
6 changed files with 176 additions and 113 deletions

View File

@ -3,6 +3,7 @@ package httpx
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
@ -156,7 +157,7 @@ get_response:
// websockets don't have a readable body // websockets don't have a readable body
if httpresp.StatusCode != http.StatusSwitchingProtocols { if httpresp.StatusCode != http.StatusSwitchingProtocols {
var err error var err error
respbody, err = ioutil.ReadAll(httpresp.Body) respbody, err = ioutil.ReadAll(io.LimitReader(httpresp.Body, h.Options.MaxResponseBodySizeToRead))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -26,13 +26,15 @@ type Options struct {
Unsafe bool Unsafe bool
TLSGrab bool TLSGrab bool
// VHOSTs options // VHOSTs options
VHostIgnoreStatusCode bool VHostIgnoreStatusCode bool
VHostIgnoreContentLength bool VHostIgnoreContentLength bool
VHostIgnoreNumberOfWords bool VHostIgnoreNumberOfWords bool
VHostIgnoreNumberOfLines bool VHostIgnoreNumberOfLines bool
VHostStripHTML bool VHostStripHTML bool
Allow []string Allow []string
Deny []string Deny []string
MaxResponseBodySizeToSave int64
MaxResponseBodySizeToRead int64
} }
// DefaultOptions contains the default options // DefaultOptions contains the default options

4
go.mod
View File

@ -25,8 +25,8 @@ require (
github.com/projectdiscovery/rawhttp v0.0.7 github.com/projectdiscovery/rawhttp v0.0.7
github.com/projectdiscovery/retryabledns v1.0.12 // indirect github.com/projectdiscovery/retryabledns v1.0.12 // indirect
github.com/projectdiscovery/retryablehttp-go v1.0.2-0.20210526144436-e15804ddc7dc github.com/projectdiscovery/retryablehttp-go v1.0.2-0.20210526144436-e15804ddc7dc
github.com/projectdiscovery/stringsutil v0.0.0-20210617141317-00728870f68d // indirect github.com/projectdiscovery/stringsutil v0.0.0-20210617141317-00728870f68d
github.com/projectdiscovery/urlutil v0.0.0-20210525140139-b874f06ad921 github.com/projectdiscovery/urlutil v0.0.0-20210805190935-3d83726391c1
github.com/projectdiscovery/wappalyzergo v0.0.7 github.com/projectdiscovery/wappalyzergo v0.0.7
github.com/remeh/sizedwaitgroup v1.0.0 github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.3.0 github.com/rs/xid v1.3.0

4
go.sum
View File

@ -167,8 +167,8 @@ github.com/projectdiscovery/retryablehttp-go v1.0.2-0.20210526144436-e15804ddc7d
github.com/projectdiscovery/stringsutil v0.0.0-20210524051937-51dabe3b72c0/go.mod h1:TVSdZC0rRQeMIbsNSiGPhbmhyRtxqqtAGA9JiiNp2r4= github.com/projectdiscovery/stringsutil v0.0.0-20210524051937-51dabe3b72c0/go.mod h1:TVSdZC0rRQeMIbsNSiGPhbmhyRtxqqtAGA9JiiNp2r4=
github.com/projectdiscovery/stringsutil v0.0.0-20210617141317-00728870f68d h1:nlOAex7twmrEqD5i6WLnugF9uO3DQ6jDEKN9gevrTAk= github.com/projectdiscovery/stringsutil v0.0.0-20210617141317-00728870f68d h1:nlOAex7twmrEqD5i6WLnugF9uO3DQ6jDEKN9gevrTAk=
github.com/projectdiscovery/stringsutil v0.0.0-20210617141317-00728870f68d/go.mod h1:TVSdZC0rRQeMIbsNSiGPhbmhyRtxqqtAGA9JiiNp2r4= github.com/projectdiscovery/stringsutil v0.0.0-20210617141317-00728870f68d/go.mod h1:TVSdZC0rRQeMIbsNSiGPhbmhyRtxqqtAGA9JiiNp2r4=
github.com/projectdiscovery/urlutil v0.0.0-20210525140139-b874f06ad921 h1:EgaxpJm7+lKppfAHkFHs+S+II0lodp4Gu3leZCCkWlc= github.com/projectdiscovery/urlutil v0.0.0-20210805190935-3d83726391c1 h1:9dYmONRtwy+xP8UAGHxEQ0cxO3umc9qiFmnYsoDUps4=
github.com/projectdiscovery/urlutil v0.0.0-20210525140139-b874f06ad921/go.mod h1:oXLErqOpqEAp/ueQlknysFxHO3CUNoSiDNnkiHG+Jpo= github.com/projectdiscovery/urlutil v0.0.0-20210805190935-3d83726391c1/go.mod h1:oXLErqOpqEAp/ueQlknysFxHO3CUNoSiDNnkiHG+Jpo=
github.com/projectdiscovery/wappalyzergo v0.0.7 h1:MvlienkiFUbO3nDvlc5mNy1C5XiHzD2EklLDgnG9Zv4= github.com/projectdiscovery/wappalyzergo v0.0.7 h1:MvlienkiFUbO3nDvlc5mNy1C5XiHzD2EklLDgnG9Zv4=
github.com/projectdiscovery/wappalyzergo v0.0.7/go.mod h1:vS+npIOANv7eKsEtODsyRQt2n1v8VofCwj2gjmq72EM= github.com/projectdiscovery/wappalyzergo v0.0.7/go.mod h1:vS+npIOANv7eKsEtODsyRQt2n1v8VofCwj2gjmq72EM=
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=

View File

@ -22,78 +22,81 @@ const (
) )
type scanOptions struct { type scanOptions struct {
Methods []string Methods []string
StoreResponseDirectory string StoreResponseDirectory string
RequestURI string RequestURI string
RequestBody string RequestBody string
VHost bool VHost bool
OutputTitle bool OutputTitle bool
OutputStatusCode bool OutputStatusCode bool
OutputLocation bool OutputLocation bool
OutputContentLength bool OutputContentLength bool
StoreResponse bool StoreResponse bool
OutputServerHeader bool OutputServerHeader bool
OutputWebSocket bool OutputWebSocket bool
OutputWithNoColor bool OutputWithNoColor bool
OutputMethod bool OutputMethod bool
ResponseInStdout bool ResponseInStdout bool
ChainInStdout bool ChainInStdout bool
TLSProbe bool TLSProbe bool
CSPProbe bool CSPProbe bool
VHostInput bool VHostInput bool
OutputContentType bool OutputContentType bool
Unsafe bool Unsafe bool
Pipeline bool Pipeline bool
HTTP2Probe bool HTTP2Probe bool
OutputIP bool OutputIP bool
OutputCName bool OutputCName bool
OutputCDN bool OutputCDN bool
OutputResponseTime bool OutputResponseTime bool
PreferHTTPS bool PreferHTTPS bool
NoFallback bool NoFallback bool
NoFallbackScheme bool NoFallbackScheme bool
TechDetect bool TechDetect bool
StoreChain bool StoreChain bool
MaxResponseBodySize int MaxResponseBodySizeToSave int
OutputExtractRegex string MaxResponseBodySizeToRead int
extractRegex *regexp.Regexp OutputExtractRegex string
ExcludeCDN bool extractRegex *regexp.Regexp
ExcludeCDN bool
} }
func (s *scanOptions) Clone() *scanOptions { func (s *scanOptions) Clone() *scanOptions {
return &scanOptions{ return &scanOptions{
Methods: s.Methods, Methods: s.Methods,
StoreResponseDirectory: s.StoreResponseDirectory, StoreResponseDirectory: s.StoreResponseDirectory,
RequestURI: s.RequestURI, RequestURI: s.RequestURI,
RequestBody: s.RequestBody, RequestBody: s.RequestBody,
VHost: s.VHost, VHost: s.VHost,
OutputTitle: s.OutputTitle, OutputTitle: s.OutputTitle,
OutputStatusCode: s.OutputStatusCode, OutputStatusCode: s.OutputStatusCode,
OutputLocation: s.OutputLocation, OutputLocation: s.OutputLocation,
OutputContentLength: s.OutputContentLength, OutputContentLength: s.OutputContentLength,
StoreResponse: s.StoreResponse, StoreResponse: s.StoreResponse,
OutputServerHeader: s.OutputServerHeader, OutputServerHeader: s.OutputServerHeader,
OutputWebSocket: s.OutputWebSocket, OutputWebSocket: s.OutputWebSocket,
OutputWithNoColor: s.OutputWithNoColor, OutputWithNoColor: s.OutputWithNoColor,
OutputMethod: s.OutputMethod, OutputMethod: s.OutputMethod,
ResponseInStdout: s.ResponseInStdout, ResponseInStdout: s.ResponseInStdout,
ChainInStdout: s.ChainInStdout, ChainInStdout: s.ChainInStdout,
TLSProbe: s.TLSProbe, TLSProbe: s.TLSProbe,
CSPProbe: s.CSPProbe, CSPProbe: s.CSPProbe,
OutputContentType: s.OutputContentType, OutputContentType: s.OutputContentType,
Unsafe: s.Unsafe, Unsafe: s.Unsafe,
Pipeline: s.Pipeline, Pipeline: s.Pipeline,
HTTP2Probe: s.HTTP2Probe, HTTP2Probe: s.HTTP2Probe,
OutputIP: s.OutputIP, OutputIP: s.OutputIP,
OutputCName: s.OutputCName, OutputCName: s.OutputCName,
OutputCDN: s.OutputCDN, OutputCDN: s.OutputCDN,
OutputResponseTime: s.OutputResponseTime, OutputResponseTime: s.OutputResponseTime,
PreferHTTPS: s.PreferHTTPS, PreferHTTPS: s.PreferHTTPS,
NoFallback: s.NoFallback, NoFallback: s.NoFallback,
NoFallbackScheme: s.NoFallbackScheme, NoFallbackScheme: s.NoFallbackScheme,
TechDetect: s.TechDetect, TechDetect: s.TechDetect,
StoreChain: s.StoreChain, StoreChain: s.StoreChain,
OutputExtractRegex: s.OutputExtractRegex, OutputExtractRegex: s.OutputExtractRegex,
MaxResponseBodySizeToSave: s.MaxResponseBodySizeToSave,
MaxResponseBodySizeToRead: s.MaxResponseBodySizeToRead,
} }
} }
@ -171,7 +174,8 @@ type Options struct {
StoreChain bool StoreChain bool
Deny customlist.CustomList Deny customlist.CustomList
Allow customlist.CustomList Allow customlist.CustomList
MaxResponseBodySize int MaxResponseBodySizeToSave int
MaxResponseBodySizeToRead int
OutputExtractRegex string OutputExtractRegex string
RateLimit int RateLimit int
Probe bool Probe bool
@ -182,6 +186,7 @@ type Options struct {
func ParseOptions() *Options { func ParseOptions() *Options {
options := &Options{} options := &Options{}
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
flag.BoolVar(&options.TLSGrab, "tls-grab", false, "Perform TLS data grabbing") flag.BoolVar(&options.TLSGrab, "tls-grab", false, "Perform TLS data grabbing")
flag.BoolVar(&options.TechDetect, "tech-detect", false, "Perform wappalyzer based technology detection") flag.BoolVar(&options.TechDetect, "tech-detect", false, "Perform wappalyzer based technology detection")
flag.IntVar(&options.Threads, "threads", 50, "Number of threads") flag.IntVar(&options.Threads, "threads", 50, "Number of threads")
@ -244,7 +249,8 @@ func ParseOptions() *Options {
flag.BoolVar(&options.StoreChain, "store-chain", false, "Save chain to file (default 'output')") flag.BoolVar(&options.StoreChain, "store-chain", false, "Save chain to file (default 'output')")
flag.Var(&options.Allow, "allow", "Allowlist ip/cidr") flag.Var(&options.Allow, "allow", "Allowlist ip/cidr")
flag.Var(&options.Deny, "deny", "Denylist ip/cidr") flag.Var(&options.Deny, "deny", "Denylist ip/cidr")
flag.IntVar(&options.MaxResponseBodySize, "max-response-body-size", math.MaxInt32, "Maximum response body size") flag.IntVar(&options.MaxResponseBodySizeToSave, "response-size-to-save", math.MaxInt32, "Max response size to save in bytes (default - unlimited)")
flag.IntVar(&options.MaxResponseBodySizeToRead, "response-size-to-read", math.MaxInt32, "Max response size to read in bytes (default - unlimited)")
flag.StringVar(&options.OutputExtractRegex, "extract-regex", "", "Extract Regex") flag.StringVar(&options.OutputExtractRegex, "extract-regex", "", "Extract Regex")
flag.IntVar(&options.RateLimit, "rate-limit", 150, "Maximum requests to send per second") flag.IntVar(&options.RateLimit, "rate-limit", 150, "Maximum requests to send per second")
flag.BoolVar(&options.Probe, "probe", false, "Display probe status") flag.BoolVar(&options.Probe, "probe", false, "Display probe status")

View File

@ -14,14 +14,15 @@ import (
"os" "os"
"path" "path"
"regexp" "regexp"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/projectdiscovery/clistats" "github.com/projectdiscovery/clistats"
"github.com/projectdiscovery/stringsutil"
"github.com/projectdiscovery/urlutil" "github.com/projectdiscovery/urlutil"
// automatic fd max increase if running as root // automatic fd max increase if running as root
@ -40,6 +41,7 @@ import (
"github.com/projectdiscovery/rawhttp" "github.com/projectdiscovery/rawhttp"
wappalyzer "github.com/projectdiscovery/wappalyzergo" wappalyzer "github.com/projectdiscovery/wappalyzergo"
"github.com/remeh/sizedwaitgroup" "github.com/remeh/sizedwaitgroup"
"go.uber.org/ratelimit"
) )
const ( const (
@ -48,12 +50,13 @@ const (
// Runner is a client for running the enumeration process. // Runner is a client for running the enumeration process.
type Runner struct { type Runner struct {
options *Options options *Options
hp *httpx.HTTPX hp *httpx.HTTPX
wappalyzer *wappalyzer.Wappalyze wappalyzer *wappalyzer.Wappalyze
scanopts scanOptions scanopts scanOptions
hm *hybrid.HybridMap hm *hybrid.HybridMap
stats clistats.StatisticsClient stats clistats.StatisticsClient
ratelimiter ratelimit.Limiter
} }
// New creates a new client for running enumeration process. // New creates a new client for running enumeration process.
@ -84,6 +87,12 @@ func New(options *Options) (*Runner, error) {
httpxOptions.RandomAgent = options.RandomAgent httpxOptions.RandomAgent = options.RandomAgent
httpxOptions.Deny = options.Deny httpxOptions.Deny = options.Deny
httpxOptions.Allow = options.Allow httpxOptions.Allow = options.Allow
httpxOptions.MaxResponseBodySizeToSave = int64(options.MaxResponseBodySizeToSave)
httpxOptions.MaxResponseBodySizeToRead = int64(options.MaxResponseBodySizeToRead)
// adjust response size saved according to the max one read by the server
if httpxOptions.MaxResponseBodySizeToSave > httpxOptions.MaxResponseBodySizeToRead {
httpxOptions.MaxResponseBodySizeToSave = httpxOptions.MaxResponseBodySizeToRead
}
var key, value string var key, value string
httpxOptions.CustomHeaders = make(map[string]string) httpxOptions.CustomHeaders = make(map[string]string)
@ -182,7 +191,8 @@ func New(options *Options) (*Runner, error) {
scanopts.NoFallbackScheme = options.NoFallbackScheme scanopts.NoFallbackScheme = options.NoFallbackScheme
scanopts.TechDetect = options.TechDetect scanopts.TechDetect = options.TechDetect
scanopts.StoreChain = options.StoreChain scanopts.StoreChain = options.StoreChain
scanopts.MaxResponseBodySize = options.MaxResponseBodySize scanopts.MaxResponseBodySizeToSave = options.MaxResponseBodySizeToSave
scanopts.MaxResponseBodySizeToRead = options.MaxResponseBodySizeToRead
if options.OutputExtractRegex != "" { if options.OutputExtractRegex != "" {
if scanopts.extractRegex, err = regexp.Compile(options.OutputExtractRegex); err != nil { if scanopts.extractRegex, err = regexp.Compile(options.OutputExtractRegex); err != nil {
return nil, err return nil, err
@ -210,6 +220,12 @@ func New(options *Options) (*Runner, error) {
} }
runner.hm = hm runner.hm = hm
if options.RateLimit > 0 {
runner.ratelimiter = ratelimit.New(options.RateLimit)
} else {
runner.ratelimiter = ratelimit.NewUnlimited()
}
return runner, nil return runner, nil
} }
@ -256,7 +272,7 @@ func (r *Runner) prepareInput() {
} }
numTargets += numTargetsStdin numTargets += numTargetsStdin
} }
// reqLength = numTargets
if r.options.ShowStatistics { if r.options.ShowStatistics {
numPorts := len(customport.Ports) numPorts := len(customport.Ports)
if numPorts == 0 { if numPorts == 0 {
@ -280,6 +296,9 @@ func (r *Runner) loadAndCloseFile(finput *os.File) (numTargets int, err error) {
for scanner.Scan() { for scanner.Scan() {
target := strings.TrimSpace(scanner.Text()) target := strings.TrimSpace(scanner.Text())
// Used just to get the exact number of targets // Used just to get the exact number of targets
if target == "" {
continue
}
if _, ok := r.hm.Get(target); ok { if _, ok := r.hm.Get(target); ok {
continue continue
} }
@ -340,7 +359,6 @@ func (r *Runner) Close() {
// RunEnumeration on targets for httpx client // RunEnumeration on targets for httpx client
func (r *Runner) RunEnumeration() { func (r *Runner) RunEnumeration() {
//fmt.Println("result : == >> 45646 ")
// Try to create output folder if it doesnt exist // Try to create output folder if it doesnt exist
if r.options.StoreResponse && !fileutil.FolderExists(r.options.StoreResponseDir) { if r.options.StoreResponse && !fileutil.FolderExists(r.options.StoreResponseDir) {
if err := os.MkdirAll(r.options.StoreResponseDir, os.ModePerm); err != nil { if err := os.MkdirAll(r.options.StoreResponseDir, os.ModePerm); err != nil {
@ -368,7 +386,7 @@ func (r *Runner) RunEnumeration() {
} }
for resp := range output { for resp := range output {
if resp.err != nil { if resp.err != nil {
gologger.Debug().Msgf("Failure '%s': %s\n", resp.URL, resp.err) gologger.Debug().Msgf("Failed '%s': %s\n", resp.URL, resp.err)
} }
if resp.str == "" { if resp.str == "" {
continue continue
@ -404,7 +422,6 @@ func (r *Runner) RunEnumeration() {
if r.options.JSONOutput { if r.options.JSONOutput {
row = resp.JSON(&r.scanopts) row = resp.JSON(&r.scanopts)
} }
gologger.Silent().Msgf("%s\n", row) gologger.Silent().Msgf("%s\n", row)
if f != nil { if f != nil {
//nolint:errcheck // this method needs a small refactor to reduce complexity //nolint:errcheck // this method needs a small refactor to reduce complexity
@ -456,7 +473,6 @@ func (r *Runner) process(t string, wg *sizedwaitgroup.SizedWaitGroup, hp *httpx.
if scanopts.NoFallback { if scanopts.NoFallback {
protocols = []string{httpx.HTTPS, httpx.HTTP} protocols = []string{httpx.HTTPS, httpx.HTTP}
} }
for target := range targets(stringz.TrimProtocol(t, scanopts.NoFallback || scanopts.NoFallbackScheme)) { for target := range targets(stringz.TrimProtocol(t, scanopts.NoFallback || scanopts.NoFallbackScheme)) {
// if no custom ports specified then test the default ones // if no custom ports specified then test the default ones
if len(customport.Ports) == 0 { if len(customport.Ports) == 0 {
@ -615,9 +631,46 @@ retry:
req.Body = nil req.Body = nil
} }
} }
r.ratelimiter.Take()
resp, err := hp.Do(req) resp, err := hp.Do(req)
fullURL := req.URL.String()
builder := &strings.Builder{}
// if the full url doesn't end with the custom path we pick the original input value
if !stringsutil.HasSuffixAny(fullURL, scanopts.RequestURI) {
parsedURL, _ := urlutil.Parse(fullURL)
parsedURL.RequestURI = scanopts.RequestURI
fullURL = parsedURL.String()
}
builder.WriteString(stringz.RemoveURLDefaultPort(fullURL))
if r.options.Probe {
builder.WriteString(" [")
outputStatus := "SUCCESS"
if err != nil {
outputStatus = "FAILED"
}
if !scanopts.OutputWithNoColor && err != nil {
builder.WriteString(aurora.Red(outputStatus).String())
} else if !scanopts.OutputWithNoColor && err == nil {
builder.WriteString(aurora.Green(outputStatus).String())
} else {
builder.WriteString(outputStatus)
}
builder.WriteRune(']')
}
if err != nil { if err != nil {
errString := ""
errString = err.Error()
splitErr := strings.Split(errString, ":")
errString = strings.TrimSpace(splitErr[len(splitErr)-1])
if !retried && origProtocol == httpx.HTTPorHTTPS { if !retried && origProtocol == httpx.HTTPorHTTPS {
if protocol == httpx.HTTPS { if protocol == httpx.HTTPS {
protocol = httpx.HTTP protocol = httpx.HTTP
@ -627,19 +680,13 @@ retry:
retried = true retried = true
goto retry goto retry
} }
return Result{URL: URL.String(), err: err} if r.options.Probe {
return Result{URL: URL.String(), Input: domain, Timestamp: time.Now(), err: err, Failed: err != nil, Error: errString, str: builder.String()}
} else {
return Result{URL: URL.String(), Input: domain, Timestamp: time.Now(), err: err}
}
} }
var fullURL string
if resp.StatusCode >= 0 {
fullURL = req.URL.String()
}
builder := &strings.Builder{}
builder.WriteString(stringz.RemoveURLDefaultPort(fullURL))
// portLst = append(portLst, fullURL)
if scanopts.OutputStatusCode { if scanopts.OutputStatusCode {
builder.WriteString(" [") builder.WriteString(" [")
for i, chainItem := range resp.Chain { for i, chainItem := range resp.Chain {
@ -733,6 +780,7 @@ retry:
// check for virtual host // check for virtual host
isvhost := false isvhost := false
if scanopts.VHost { if scanopts.VHost {
r.ratelimiter.Take()
isvhost, _ = hp.IsVirtualHost(req) isvhost, _ = hp.IsVirtualHost(req)
if isvhost { if isvhost {
builder.WriteString(" [vhost]") builder.WriteString(" [vhost]")
@ -748,6 +796,7 @@ retry:
pipeline := false pipeline := false
if scanopts.Pipeline { if scanopts.Pipeline {
port, _ := strconv.Atoi(URL.Port) port, _ := strconv.Atoi(URL.Port)
r.ratelimiter.Take()
pipeline = hp.SupportPipeline(protocol, method, URL.Host, port) pipeline = hp.SupportPipeline(protocol, method, URL.Host, port)
if pipeline { if pipeline {
builder.WriteString(" [pipeline]") builder.WriteString(" [pipeline]")
@ -757,6 +806,7 @@ retry:
var http2 bool var http2 bool
// if requested probes for http2 // if requested probes for http2
if scanopts.HTTP2Probe { if scanopts.HTTP2Probe {
r.ratelimiter.Take()
http2 = hp.SupportHTTP2(protocol, method, URL.String()) http2 = hp.SupportHTTP2(protocol, method, URL.String())
if http2 { if http2 {
builder.WriteString(" [http2]") builder.WriteString(" [http2]")
@ -802,6 +852,7 @@ retry:
} }
if len(technologies) > 0 { if len(technologies) > 0 {
sort.Strings(technologies)
technologies := strings.Join(technologies, ",") technologies := strings.Join(technologies, ",")
builder.WriteString(" [") builder.WriteString(" [")
@ -852,8 +903,8 @@ retry:
// store response // store response
responsePath := path.Join(scanopts.StoreResponseDirectory, domainFile) responsePath := path.Join(scanopts.StoreResponseDirectory, domainFile)
respRaw := resp.Raw respRaw := resp.Raw
if len(respRaw) > scanopts.MaxResponseBodySize { if len(respRaw) > scanopts.MaxResponseBodySizeToSave {
respRaw = respRaw[:scanopts.MaxResponseBodySize] respRaw = respRaw[:scanopts.MaxResponseBodySizeToSave]
} }
writeErr := ioutil.WriteFile(responsePath, []byte(respRaw), 0644) writeErr := ioutil.WriteFile(responsePath, []byte(respRaw), 0644)
if writeErr != nil { if writeErr != nil {
@ -903,6 +954,7 @@ retry:
if scanopts.ChainInStdout && resp.HasChain() { if scanopts.ChainInStdout && resp.HasChain() {
chainItems = append(chainItems, resp.GetChainAsSlice()...) chainItems = append(chainItems, resp.GetChainAsSlice()...)
} }
return Result{ return Result{
Timestamp: time.Now(), Timestamp: time.Now(),
Request: request, Request: request,
@ -914,6 +966,7 @@ retry:
HeaderSHA256: headersSha, HeaderSHA256: headersSha,
raw: resp.Raw, raw: resp.Raw,
URL: fullURL, URL: fullURL,
Input: domain,
ContentLength: resp.ContentLength, ContentLength: resp.ContentLength,
ChainStatusCodes: chainStatusCodes, ChainStatusCodes: chainStatusCodes,
Chain: chainItems, Chain: chainItems,
@ -938,8 +991,6 @@ retry:
ResponseTime: resp.Duration.String(), ResponseTime: resp.Duration.String(),
Technologies: technologies, Technologies: technologies,
FinalURL: finalURL, FinalURL: finalURL,
// UniqueUrl: uniqueUrlStrngs,
// PortLst: portLst,
} }
} }
@ -957,10 +1008,12 @@ type Result struct {
CNAMEs []string `json:"cnames,omitempty"` CNAMEs []string `json:"cnames,omitempty"`
raw string raw string
URL string `json:"url,omitempty"` URL string `json:"url,omitempty"`
Input string `json:"input,omitempty"`
Location string `json:"location,omitempty"` Location string `json:"location,omitempty"`
Title string `json:"title,omitempty"` Title string `json:"title,omitempty"`
str string str string
err error err error
Error string `json:"error,omitempty"`
WebServer string `json:"webserver,omitempty"` WebServer string `json:"webserver,omitempty"`
ResponseBody string `json:"response-body,omitempty"` ResponseBody string `json:"response-body,omitempty"`
ContentType string `json:"content-type,omitempty"` ContentType string `json:"content-type,omitempty"`
@ -980,12 +1033,13 @@ type Result struct {
Technologies []string `json:"technologies,omitempty"` Technologies []string `json:"technologies,omitempty"`
Chain []httpx.ChainItem `json:"chain,omitempty"` Chain []httpx.ChainItem `json:"chain,omitempty"`
FinalURL string `json:"final-url,omitempty"` FinalURL string `json:"final-url,omitempty"`
Failed bool `json:"failed"`
} }
// JSON the result // JSON the result
func (r Result) JSON(scanopts *scanOptions) string { //nolint func (r Result) JSON(scanopts *scanOptions) string { //nolint
if scanopts != nil && len(r.ResponseBody) > scanopts.MaxResponseBodySize { if scanopts != nil && len(r.ResponseBody) > scanopts.MaxResponseBodySizeToSave {
r.ResponseBody = r.ResponseBody[:scanopts.MaxResponseBodySize] r.ResponseBody = r.ResponseBody[:scanopts.MaxResponseBodySizeToSave]
} }
if js, err := json.Marshal(r); err == nil { if js, err := json.Marshal(r); err == nil {