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 }