diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go index 2c3aaba01..76699f2dd 100644 --- a/v2/internal/runner/runner.go +++ b/v2/internal/runner/runner.go @@ -248,6 +248,7 @@ func New(options *types.Options) (*Runner, error) { Output: runner.output, IssuesClient: runner.issuesClient, Progress: runner.progress, + Debug: runner.options.Debug, }) if err != nil { gologger.Error().Msgf("Could not create interactsh client: %s", err) diff --git a/v2/pkg/protocols/common/interactsh/interactsh.go b/v2/pkg/protocols/common/interactsh/interactsh.go index 6fa71797b..773a88e0d 100644 --- a/v2/pkg/protocols/common/interactsh/interactsh.go +++ b/v2/pkg/protocols/common/interactsh/interactsh.go @@ -1,7 +1,10 @@ package interactsh import ( + "bytes" + "fmt" "net/url" + "os" "strings" "sync/atomic" "time" @@ -62,6 +65,8 @@ type Options struct { IssuesClient *reporting.Client // Progress is the nuclei progress bar implementation. Progress progress.Progress + // Debug specifies whether debugging output should be shown for interactsh-client + Debug bool } const defaultMaxInteractionsCount = 5000 @@ -100,6 +105,9 @@ func New(options *Options) (*Client, error) { } interactClient.interactsh.StartPolling(interactClient.pollDuration, func(interaction *server.Interaction) { + if options.Debug { + debugPrintInteraction(interaction) + } item := interactClient.requests.Get(interaction.UniqueID) if item == nil { // If we don't have any request for this ID, add it to temporary @@ -252,3 +260,20 @@ func HasMatchers(op *operators.Operators) bool { } return false } + +func debugPrintInteraction(interaction *server.Interaction) { + builder := &bytes.Buffer{} + + switch interaction.Protocol { + case "dns": + builder.WriteString(fmt.Sprintf("[%s] Received DNS interaction (%s) from %s at %s", interaction.FullId, interaction.QType, interaction.RemoteAddress, interaction.Timestamp.Format("2006-01-02 15:04:05"))) + builder.WriteString(fmt.Sprintf("\n-----------\nDNS Request\n-----------\n\n%s\n\n------------\nDNS Response\n------------\n\n%s\n\n", interaction.RawRequest, interaction.RawResponse)) + case "http": + builder.WriteString(fmt.Sprintf("[%s] Received HTTP interaction from %s at %s", interaction.FullId, interaction.RemoteAddress, interaction.Timestamp.Format("2006-01-02 15:04:05"))) + builder.WriteString(fmt.Sprintf("\n------------\nHTTP Request\n------------\n\n%s\n\n-------------\nHTTP Response\n-------------\n\n%s\n\n", interaction.RawRequest, interaction.RawResponse)) + case "smtp": + builder.WriteString(fmt.Sprintf("[%s] Received SMTP interaction from %s at %s", interaction.FullId, interaction.RemoteAddress, interaction.Timestamp.Format("2006-01-02 15:04:05"))) + builder.WriteString(fmt.Sprintf("\n------------\nSMTP Interaction\n------------\n\n%s\n\n", interaction.RawRequest)) + } + fmt.Fprint(os.Stderr, builder.String()) +} diff --git a/v2/pkg/protocols/http/request.go b/v2/pkg/protocols/http/request.go index 70f50c721..e6b5be9ea 100644 --- a/v2/pkg/protocols/http/request.go +++ b/v2/pkg/protocols/http/request.go @@ -67,7 +67,7 @@ func (r *Request) executeRaceRequest(reqURL string, previous output.InternalEven wg.Add(1) go func(httpRequest *generatedRequest) { defer wg.Done() - err := r.executeRequest(reqURL, httpRequest, previous, callback, 0) + err := r.executeRequest(reqURL, httpRequest, previous, false, callback, 0) mutex.Lock() if err != nil { requestErr = multierr.Append(requestErr, err) @@ -107,7 +107,7 @@ func (r *Request) executeParallelHTTP(reqURL string, dynamicValues output.Intern r.options.RateLimiter.Take() previous := make(map[string]interface{}) - err := r.executeRequest(reqURL, httpRequest, previous, callback, 0) + err := r.executeRequest(reqURL, httpRequest, previous, false, callback, 0) mutex.Lock() if err != nil { requestErr = multierr.Append(requestErr, err) @@ -166,7 +166,7 @@ func (r *Request) executeTurboHTTP(reqURL string, dynamicValues, previous output go func(httpRequest *generatedRequest) { defer swg.Done() - err := r.executeRequest(reqURL, httpRequest, previous, callback, 0) + err := r.executeRequest(reqURL, httpRequest, previous, false, callback, 0) mutex.Lock() if err != nil { requestErr = multierr.Append(requestErr, err) @@ -222,7 +222,7 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp } var gotOutput bool r.options.RateLimiter.Take() - err = r.executeRequest(reqURL, request, previous, func(event *output.InternalWrappedEvent) { + err = r.executeRequest(reqURL, request, previous, hasInteractMarkers, func(event *output.InternalWrappedEvent) { // Add the extracts to the dynamic values if any. if event.OperatorsResult != nil { gotOutput = true @@ -260,7 +260,7 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp const drainReqSize = int64(8 * 1024) // executeRequest executes the actual generated request and returns error if occurred -func (r *Request) executeRequest(reqURL string, request *generatedRequest, previous output.InternalEvent, callback protocols.OutputEventCallback, requestCount int) error { +func (r *Request) executeRequest(reqURL string, request *generatedRequest, previous output.InternalEvent, hasInteractMarkers bool, callback protocols.OutputEventCallback, requestCount int) error { r.setCustomHeaders(request) var ( @@ -330,6 +330,22 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, previ } r.options.Output.Request(r.options.TemplateID, formedURL, "http", err) r.options.Progress.IncrementErrorsBy(1) + + // If we have interactsh markers and request times out, still send + // a callback event so in case we recieve an interaction, correlation is possible. + if hasInteractMarkers { + outputEvent := r.responseToDSLMap(&http.Response{}, reqURL, formedURL, tostring.UnsafeToString(dumpedRequest), "", "", "", 0, request.meta) + if i := strings.LastIndex(hostname, ":"); i != -1 { + hostname = hostname[:i] + } + outputEvent["ip"] = httpclientpool.Dialer.GetDialedIP(hostname) + + event := &output.InternalWrappedEvent{InternalEvent: outputEvent} + if r.CompiledOperators != nil { + event.InternalEvent = outputEvent + } + callback(event) + } return err } defer func() { diff --git a/v2/pkg/reporting/exporters/disk/disk.go b/v2/pkg/reporting/exporters/disk/disk.go index d29799a34..603515644 100644 --- a/v2/pkg/reporting/exporters/disk/disk.go +++ b/v2/pkg/reporting/exporters/disk/disk.go @@ -46,7 +46,7 @@ func (i *Exporter) Export(event *output.ResultEvent) error { filenameBuilder.WriteString("-") filenameBuilder.WriteString(strings.ReplaceAll(strings.ReplaceAll(event.Matched, "/", "_"), ":", "_")) filenameBuilder.WriteString(".md") - finalFilename := filenameBuilder.String() + finalFilename := sanitizeFilename(filenameBuilder.String()) dataBuilder := &bytes.Buffer{} dataBuilder.WriteString("### ") @@ -63,3 +63,10 @@ func (i *Exporter) Export(event *output.ResultEvent) error { func (i *Exporter) Close() error { return nil } + +func sanitizeFilename(filename string) string { + if len(filename) > 256 { + filename = filename[0:255] + } + return filename +}