Path: blob/dev/pkg/protocols/http/request_test.go
2070 views
package http12import (3"context"4"fmt"5"net/http"6"net/http/httptest"7"testing"89"github.com/stretchr/testify/require"1011"github.com/projectdiscovery/nuclei/v3/pkg/model"12"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"13"github.com/projectdiscovery/nuclei/v3/pkg/operators"14"github.com/projectdiscovery/nuclei/v3/pkg/operators/extractors"15"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"16"github.com/projectdiscovery/nuclei/v3/pkg/output"17"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"18"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"19"github.com/projectdiscovery/nuclei/v3/pkg/testutils"20)2122func TestHTTPExtractMultipleReuse(t *testing.T) {23options := testutils.DefaultOptions2425testutils.Init(options)26templateID := "testing-http"27request := &Request{28ID: templateID,29Raw: []string{30`GET /robots.txt HTTP/1.131Host: {{Hostname}}32User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.033Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.834Accept-Language: en-US,en;q=0.535`,3637`GET {{endpoint}} HTTP/1.138Host: {{Hostname}}39User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.040Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.841Accept-Language: en-US,en;q=0.542`,43},44Operators: operators.Operators{45Matchers: []*matchers.Matcher{{46Part: "body",47Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},48Words: []string{"match /a", "match /b", "match /c"},49}},50Extractors: []*extractors.Extractor{{51Part: "body",52Name: "endpoint",53Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor},54Regex: []string{"(?m)/([a-zA-Z0-9-_/\\\\]+)"},55Internal: true,56}},57},58IterateAll: true,59}60ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {61switch r.URL.Path {62case "/robots.txt":63_, _ = fmt.Fprintf(w, `User-agent: Googlebot64Disallow: /a65Disallow: /b66Disallow: /c`)67default:68_, _ = fmt.Fprintf(w, `match %v`, r.URL.Path)69}70}))71defer ts.Close()7273executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{74ID: templateID,75Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},76})7778err := request.Compile(executerOpts)79require.Nil(t, err, "could not compile network request")8081var finalEvent *output.InternalWrappedEvent82var matchCount int83t.Run("test", func(t *testing.T) {84metadata := make(output.InternalEvent)85previous := make(output.InternalEvent)86ctxArgs := contextargs.NewWithInput(context.Background(), ts.URL)87err := request.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {88if event.OperatorsResult != nil && event.OperatorsResult.Matched {89matchCount++90}91finalEvent = event92})93require.Nil(t, err, "could not execute network request")94})95require.NotNil(t, finalEvent, "could not get event output from request")96require.Equal(t, 3, matchCount, "could not get correct match count")97}9899func TestDisableTE(t *testing.T) {100options := testutils.DefaultOptions101102testutils.Init(options)103templateID := "http-disable-transfer-encoding"104105// in raw request format106request := &Request{107ID: templateID,108Raw: []string{109`POST / HTTP/1.1110Host: {{Hostname}}111User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0112Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8113Accept-Language: en-US,en;q=0.5114115login=1&username=admin&password=admin116`,117},118Operators: operators.Operators{119Matchers: []*matchers.Matcher{{120Type: matchers.MatcherTypeHolder{MatcherType: matchers.StatusMatcher},121Status: []int{200},122}},123},124}125126// in base request format127request2 := &Request{128ID: templateID,129Method: HTTPMethodTypeHolder{MethodType: HTTPPost},130Path: []string{"{{BaseURL}}"},131Body: "login=1&username=admin&password=admin",132Operators: operators.Operators{133Matchers: []*matchers.Matcher{{134Type: matchers.MatcherTypeHolder{MatcherType: matchers.StatusMatcher},135Status: []int{200},136}},137},138}139ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {140if len(r.TransferEncoding) > 0 || r.ContentLength <= 0 {141t.Error("Transfer-Encoding header should not be set")142}143}))144defer ts.Close()145146executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{147ID: templateID,148Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},149})150151err := request.Compile(executerOpts)152require.Nil(t, err, "could not compile http raw request")153154err = request2.Compile(executerOpts)155require.Nil(t, err, "could not compile http base request")156157var finalEvent *output.InternalWrappedEvent158var matchCount int159t.Run("test", func(t *testing.T) {160metadata := make(output.InternalEvent)161previous := make(output.InternalEvent)162ctxArgs := contextargs.NewWithInput(context.Background(), ts.URL)163err := request.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {164if event.OperatorsResult != nil && event.OperatorsResult.Matched {165matchCount++166}167finalEvent = event168})169require.Nil(t, err, "could not execute network request")170})171172t.Run("test2", func(t *testing.T) {173metadata := make(output.InternalEvent)174previous := make(output.InternalEvent)175ctxArgs := contextargs.NewWithInput(context.Background(), ts.URL)176err := request2.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {177if event.OperatorsResult != nil && event.OperatorsResult.Matched {178matchCount++179}180finalEvent = event181})182require.Nil(t, err, "could not execute network request")183})184185require.NotNil(t, finalEvent, "could not get event output from request")186require.Equal(t, 2, matchCount, "could not get correct match count")187}188189// consult @Ice3man543 before making any breaking changes to this test (context: vuln_hash)190func TestReqURLPattern(t *testing.T) {191options := testutils.DefaultOptions192193// assume this was a preprocessor194// {{randstr}} => 2eNU2kbrOcUDzhnUL1RGvSo1it7195testutils.Init(options)196templateID := "testing-http"197request := &Request{198ID: templateID,199Raw: []string{200`GET /{{rand_char("abc")}}/{{interactsh-url}}/123?query={{rand_int(1, 10)}}&data=2eNU2kbrOcUDzhnUL1RGvSo1it7 HTTP/1.1201Host: {{Hostname}}202User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0203Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8204Accept-Language: en-US,en;q=0.5205`,206},207Operators: operators.Operators{208Matchers: []*matchers.Matcher{{209Type: matchers.MatcherTypeHolder{MatcherType: matchers.DSLMatcher},210DSL: []string{"true"},211}},212},213IterateAll: true,214}215ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {216// always return 200217w.WriteHeader(200)218_, _ = w.Write([]byte(`match`))219}))220defer ts.Close()221222executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{223ID: templateID,224Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},225})226client, _ := interactsh.New(interactsh.DefaultOptions(executerOpts.Output, nil, executerOpts.Progress))227executerOpts.Interactsh = client228defer client.Close()229executerOpts.ExportReqURLPattern = true230231// this is how generated constants are added to template232// generated constants are preprocessors that are executed while loading once233executerOpts.Constants = map[string]interface{}{234"{{randstr}}": "2eNU2kbrOcUDzhnUL1RGvSo1it7",235}236237err := request.Compile(executerOpts)238require.Nil(t, err, "could not compile network request")239240var finalEvent *output.InternalWrappedEvent241var matchCount int242t.Run("test", func(t *testing.T) {243metadata := make(output.InternalEvent)244previous := make(output.InternalEvent)245ctxArgs := contextargs.NewWithInput(context.Background(), ts.URL)246err := request.ExecuteWithResults(ctxArgs, metadata, previous, func(event *output.InternalWrappedEvent) {247if event.OperatorsResult != nil && event.OperatorsResult.Matched {248matchCount++249}250finalEvent = event251})252require.Nil(t, err, "could not execute network request")253})254require.NotNil(t, finalEvent, "could not get event output from request")255require.Equal(t, 1, matchCount, "could not get correct match count")256require.NotEmpty(t, finalEvent.Results[0].ReqURLPattern, "could not get req url pattern")257require.Equal(t, `/{{rand_char("abc")}}/{{interactsh-url}}/123?query={{rand_int(1, 10)}}&data={{randstr}}`, finalEvent.Results[0].ReqURLPattern)258}259260261