github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/network/request_test.go (about)

     1  package network
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"net/url"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/projectdiscovery/nuclei/v2/pkg/model"
    14  	"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
    15  	"github.com/projectdiscovery/nuclei/v2/pkg/operators"
    16  	"github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors"
    17  	"github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers"
    18  	"github.com/projectdiscovery/nuclei/v2/pkg/output"
    19  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
    20  	"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
    21  )
    22  
    23  func TestNetworkExecuteWithResults(t *testing.T) {
    24  	options := testutils.DefaultOptions
    25  
    26  	testutils.Init(options)
    27  	templateID := "testing-network"
    28  	request := &Request{
    29  		ID:       templateID,
    30  		Address:  []string{"{{Hostname}}:"},
    31  		ReadSize: 2048,
    32  		Inputs:   []*Input{},
    33  		Operators: operators.Operators{
    34  			Matchers: []*matchers.Matcher{{
    35  				Name:  "test",
    36  				Part:  "data",
    37  				Type:  matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},
    38  				Words: []string{"200 OK"},
    39  			}},
    40  			Extractors: []*extractors.Extractor{{
    41  				Part:  "data",
    42  				Type:  extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor},
    43  				Regex: []string{"<h1>.*</h1>"},
    44  			}},
    45  		},
    46  	}
    47  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    48  		_, _ = w.Write([]byte(exampleBody))
    49  	}))
    50  	defer ts.Close()
    51  
    52  	parsed, err := url.Parse(ts.URL)
    53  	require.Nil(t, err, "could not parse url")
    54  	request.Address[0] = "{{Hostname}}"
    55  
    56  	request.Inputs = append(request.Inputs, &Input{Data: fmt.Sprintf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", parsed.Host)})
    57  	executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
    58  		ID:   templateID,
    59  		Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
    60  	})
    61  	err = request.Compile(executerOpts)
    62  	require.Nil(t, err, "could not compile network request")
    63  
    64  	var finalEvent *output.InternalWrappedEvent
    65  	t.Run("domain-valid", func(t *testing.T) {
    66  		metadata := make(output.InternalEvent)
    67  		previous := make(output.InternalEvent)
    68  		ctxArgs := contextargs.NewWithInput(parsed.Host)
    69  		err := request.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {
    70  			finalEvent = event
    71  		})
    72  		require.Nil(t, err, "could not execute network request")
    73  	})
    74  	require.NotNil(t, finalEvent, "could not get event output from request")
    75  	require.Equal(t, 1, len(finalEvent.Results), "could not get correct number of results")
    76  	require.Equal(t, "test", finalEvent.Results[0].MatcherName, "could not get correct matcher name of results")
    77  	require.Equal(t, 1, len(finalEvent.Results[0].ExtractedResults), "could not get correct number of extracted results")
    78  	require.Equal(t, "<h1>Example Domain</h1>", finalEvent.Results[0].ExtractedResults[0], "could not get correct extracted results")
    79  	finalEvent = nil
    80  
    81  	t.Run("invalid-port-override", func(t *testing.T) {
    82  		metadata := make(output.InternalEvent)
    83  		previous := make(output.InternalEvent)
    84  		ctxArgs := contextargs.NewWithInput("127.0.0.1:11211")
    85  		err := request.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {
    86  			finalEvent = event
    87  		})
    88  		require.Nil(t, err, "could not execute network request")
    89  	})
    90  	require.Nil(t, finalEvent.Results, "could not get event output from request")
    91  
    92  	request.Inputs[0].Type = NetworkInputTypeHolder{NetworkInputType: hexType}
    93  	request.Inputs[0].Data = hex.EncodeToString([]byte(fmt.Sprintf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", parsed.Host)))
    94  
    95  	t.Run("hex-to-string", func(t *testing.T) {
    96  		metadata := make(output.InternalEvent)
    97  		previous := make(output.InternalEvent)
    98  		ctxArgs := contextargs.NewWithInput(parsed.Host)
    99  		err := request.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {
   100  			finalEvent = event
   101  		})
   102  		require.Nil(t, err, "could not execute network request")
   103  	})
   104  	require.NotNil(t, finalEvent, "could not get event output from request")
   105  	require.Equal(t, 1, len(finalEvent.Results), "could not get correct number of results")
   106  	require.Equal(t, "test", finalEvent.Results[0].MatcherName, "could not get correct matcher name of results")
   107  	require.Equal(t, 1, len(finalEvent.Results[0].ExtractedResults), "could not get correct number of extracted results")
   108  	require.Equal(t, "<h1>Example Domain</h1>", finalEvent.Results[0].ExtractedResults[0], "could not get correct extracted results")
   109  }
   110  
   111  var exampleBody = `<!doctype html>
   112  <html>
   113  <head>
   114      <title>Example Domain</title>
   115  
   116      <meta charset="utf-8" />
   117      <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
   118      <meta name="viewport" content="width=device-width, initial-scale=1" />
   119      <style type="text/css">
   120      body {
   121          background-color: #f0f0f2;
   122          margin: 0;
   123          padding: 0;
   124          font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
   125          
   126      }
   127      div {
   128          width: 600px;
   129          margin: 5em auto;
   130          padding: 2em;
   131          background-color: #fdfdff;
   132          border-radius: 0.5em;
   133          box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
   134      }
   135      a:link, a:visited {
   136          color: #38488f;
   137          text-decoration: none;
   138      }
   139      @media (max-width: 700px) {
   140          div {
   141              margin: 0 auto;
   142              width: auto;
   143          }
   144      }
   145      </style>    
   146  </head>
   147  
   148  <body>
   149  <div>
   150      <h1>Example Domain</h1>
   151      <p>This domain is for use in illustrative examples in documents. You may use this
   152      domain in literature without prior coordination or asking for permission.</p>
   153      <p><a href="https://www.iana.org/domains/example">More information...</a></p>
   154  </div>
   155  </body>
   156  </html>
   157  `