github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/http/build_request_test.go (about)

     1  package http
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/projectdiscovery/nuclei/v2/pkg/model"
    11  	"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
    12  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
    13  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
    14  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
    15  	"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
    16  )
    17  
    18  func TestMakeRequestFromModal(t *testing.T) {
    19  	options := testutils.DefaultOptions
    20  
    21  	testutils.Init(options)
    22  	templateID := "testing-http"
    23  	request := &Request{
    24  		ID:     templateID,
    25  		Name:   "testing",
    26  		Path:   []string{"{{BaseURL}}/login.php"},
    27  		Method: HTTPMethodTypeHolder{MethodType: HTTPPost},
    28  		Body:   "username=test&password=pass",
    29  		Headers: map[string]string{
    30  			"Content-Type":   "application/x-www-form-urlencoded",
    31  			"Content-Length": "1",
    32  		},
    33  	}
    34  	executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
    35  		ID:   templateID,
    36  		Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
    37  	})
    38  	err := request.Compile(executerOpts)
    39  	require.Nil(t, err, "could not compile http request")
    40  
    41  	generator := request.newGenerator(false)
    42  	inputData, payloads, _ := generator.nextValue()
    43  	req, err := generator.Make(context.Background(), contextargs.NewWithInput("https://example.com"), inputData, payloads, map[string]interface{}{})
    44  	require.Nil(t, err, "could not make http request")
    45  	if req.request.URL == nil {
    46  		t.Fatalf("url is nil in generator make")
    47  	}
    48  	bodyBytes, _ := req.request.BodyBytes()
    49  	require.Equal(t, "/login.php", req.request.URL.Path, "could not get correct request path")
    50  	require.Equal(t, "username=test&password=pass", string(bodyBytes), "could not get correct request body")
    51  }
    52  
    53  func TestMakeRequestFromModalTrimSuffixSlash(t *testing.T) {
    54  	options := testutils.DefaultOptions
    55  
    56  	testutils.Init(options)
    57  	templateID := "testing-http"
    58  	request := &Request{
    59  		ID:     templateID,
    60  		Name:   "testing",
    61  		Path:   []string{"{{BaseURL}}?query=example"},
    62  		Method: HTTPMethodTypeHolder{MethodType: HTTPGet},
    63  	}
    64  	executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
    65  		ID:   templateID,
    66  		Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
    67  	})
    68  	err := request.Compile(executerOpts)
    69  	require.Nil(t, err, "could not compile http request")
    70  
    71  	generator := request.newGenerator(false)
    72  	inputData, payloads, _ := generator.nextValue()
    73  	req, err := generator.Make(context.Background(), contextargs.NewWithInput("https://example.com/test.php"), inputData, payloads, map[string]interface{}{})
    74  	require.Nil(t, err, "could not make http request")
    75  	require.Equal(t, "https://example.com/test.php?query=example", req.request.URL.String(), "could not get correct request path")
    76  
    77  	generator = request.newGenerator(false)
    78  	inputData, payloads, _ = generator.nextValue()
    79  	req, err = generator.Make(context.Background(), contextargs.NewWithInput("https://example.com/test/"), inputData, payloads, map[string]interface{}{})
    80  	require.Nil(t, err, "could not make http request")
    81  	require.Equal(t, "https://example.com/test/?query=example", req.request.URL.String(), "could not get correct request path")
    82  }
    83  
    84  func TestMakeRequestFromRawWithPayloads(t *testing.T) {
    85  	options := testutils.DefaultOptions
    86  
    87  	testutils.Init(options)
    88  	templateID := "testing-http"
    89  	request := &Request{
    90  		ID:   templateID,
    91  		Name: "testing",
    92  		Payloads: map[string]interface{}{
    93  			"username": []string{"admin"},
    94  			"password": []string{"admin", "guest", "password", "test", "12345", "123456"},
    95  		},
    96  		AttackType: generators.AttackTypeHolder{Value: generators.ClusterBombAttack},
    97  		Raw: []string{`GET /manager/html HTTP/1.1
    98  Host: {{Hostname}}
    99  User-Agent: Nuclei - Open-source project (github.com/projectdiscovery/nuclei)
   100  Connection: close
   101  Authorization: Basic {{username + ':' + password}}
   102  Accept-Encoding: gzip`},
   103  	}
   104  	executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
   105  		ID:   templateID,
   106  		Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
   107  	})
   108  	err := request.Compile(executerOpts)
   109  	require.Nil(t, err, "could not compile http request")
   110  
   111  	generator := request.newGenerator(false)
   112  	inputData, payloads, _ := generator.nextValue()
   113  	req, err := generator.Make(context.Background(), contextargs.NewWithInput("https://example.com"), inputData, payloads, map[string]interface{}{})
   114  	require.Nil(t, err, "could not make http request")
   115  	authorization := req.request.Header.Get("Authorization")
   116  	require.Equal(t, "Basic admin:admin", authorization, "could not get correct authorization headers from raw")
   117  
   118  	inputData, payloads, _ = generator.nextValue()
   119  	req, err = generator.Make(context.Background(), contextargs.NewWithInput("https://example.com"), inputData, payloads, map[string]interface{}{})
   120  	require.Nil(t, err, "could not make http request")
   121  	authorization = req.request.Header.Get("Authorization")
   122  	require.Equal(t, "Basic admin:guest", authorization, "could not get correct authorization headers from raw")
   123  }
   124  
   125  func TestMakeRequestFromRawPayloadExpressions(t *testing.T) {
   126  	options := testutils.DefaultOptions
   127  
   128  	testutils.Init(options)
   129  	templateID := "testing-http"
   130  	request := &Request{
   131  		ID:   templateID,
   132  		Name: "testing",
   133  		Payloads: map[string]interface{}{
   134  			"username": []string{"admin"},
   135  			"password": []string{"admin", "guest", "password", "test", "12345", "123456"},
   136  		},
   137  		AttackType: generators.AttackTypeHolder{Value: generators.ClusterBombAttack},
   138  		Raw: []string{`GET /manager/html HTTP/1.1
   139  Host: {{Hostname}}
   140  User-Agent: Nuclei - Open-source project (github.com/projectdiscovery/nuclei)
   141  Connection: close
   142  Authorization: Basic {{base64(username + ':' + password)}}
   143  Accept-Encoding: gzip`},
   144  	}
   145  	executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
   146  		ID:   templateID,
   147  		Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
   148  	})
   149  	err := request.Compile(executerOpts)
   150  	require.Nil(t, err, "could not compile http request")
   151  
   152  	generator := request.newGenerator(false)
   153  	inputData, payloads, _ := generator.nextValue()
   154  	req, err := generator.Make(context.Background(), contextargs.NewWithInput("https://example.com"), inputData, payloads, map[string]interface{}{})
   155  	require.Nil(t, err, "could not make http request")
   156  	authorization := req.request.Header.Get("Authorization")
   157  	require.Equal(t, "Basic YWRtaW46YWRtaW4=", authorization, "could not get correct authorization headers from raw")
   158  
   159  	inputData, payloads, _ = generator.nextValue()
   160  	req, err = generator.Make(context.Background(), contextargs.NewWithInput("https://example.com"), inputData, payloads, map[string]interface{}{})
   161  	require.Nil(t, err, "could not make http request")
   162  	authorization = req.request.Header.Get("Authorization")
   163  	require.Equal(t, "Basic YWRtaW46Z3Vlc3Q=", authorization, "could not get correct authorization headers from raw")
   164  }
   165  
   166  func TestMakeRequestFromModelUniqueInteractsh(t *testing.T) {
   167  
   168  	options := testutils.DefaultOptions
   169  
   170  	testutils.Init(options)
   171  	templateID := "testing-unique-interactsh"
   172  	request := &Request{
   173  		ID:     templateID,
   174  		Name:   "testing",
   175  		Path:   []string{"{{BaseURL}}/?u=http://{{interactsh-url}}/&href=http://{{interactsh-url}}/&action=http://{{interactsh-url}}/&host={{interactsh-url}}"},
   176  		Method: HTTPMethodTypeHolder{MethodType: HTTPGet},
   177  	}
   178  	executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
   179  		ID:   templateID,
   180  		Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
   181  	})
   182  	err := request.Compile(executerOpts)
   183  	require.Nil(t, err, "could not compile http request")
   184  
   185  	generator := request.newGenerator(false)
   186  
   187  	generator.options.Interactsh, err = interactsh.New(&interactsh.Options{
   188  		ServerURL:           options.InteractshURL,
   189  		CacheSize:           options.InteractionsCacheSize,
   190  		Eviction:            time.Duration(options.InteractionsEviction) * time.Second,
   191  		CooldownPeriod:      time.Duration(options.InteractionsCoolDownPeriod) * time.Second,
   192  		PollDuration:        time.Duration(options.InteractionsPollDuration) * time.Second,
   193  		DisableHttpFallback: true,
   194  	})
   195  	require.Nil(t, err, "could not create interactsh client")
   196  
   197  	inputData, payloads, _ := generator.nextValue()
   198  	got, err := generator.Make(context.Background(), contextargs.NewWithInput("https://example.com"), inputData, payloads, map[string]interface{}{})
   199  	require.Nil(t, err, "could not make http request")
   200  
   201  	// check if all the interactsh markers are replaced with unique urls
   202  	require.NotContains(t, got.request.URL.String(), "{{interactsh-url}}", "could not get correct interactsh url")
   203  	// check the length of returned urls
   204  	require.Equal(t, len(got.interactshURLs), 4, "could not get correct interactsh url")
   205  	// check if the interactsh urls are unique
   206  	require.True(t, areUnique(got.interactshURLs), "interactsh urls are not unique")
   207  }
   208  
   209  // areUnique checks if the elements of string slice are unique
   210  func areUnique(elements []string) bool {
   211  	encountered := map[string]bool{}
   212  	for v := range elements {
   213  		if encountered[elements[v]] {
   214  			return false
   215  		}
   216  		encountered[elements[v]] = true
   217  	}
   218  	return true
   219  }