Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/cmd/integration-test/http.go
2070 views
1
package main
2
3
import (
4
"errors"
5
"fmt"
6
"net/http"
7
"net/http/httptest"
8
"net/http/httputil"
9
"os"
10
"reflect"
11
"regexp"
12
"strconv"
13
"strings"
14
"time"
15
16
"github.com/julienschmidt/httprouter"
17
"gopkg.in/yaml.v2"
18
19
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
20
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
21
"github.com/projectdiscovery/retryablehttp-go"
22
"github.com/projectdiscovery/utils/errkit"
23
logutil "github.com/projectdiscovery/utils/log"
24
sliceutil "github.com/projectdiscovery/utils/slice"
25
stringsutil "github.com/projectdiscovery/utils/strings"
26
unitutils "github.com/projectdiscovery/utils/unit"
27
)
28
29
var httpTestcases = []TestCaseInfo{
30
// TODO: excluded due to parsing errors with console
31
// "http/raw-unsafe-request.yaml": &httpRawUnsafeRequest{},
32
{Path: "protocols/http/get-headers.yaml", TestCase: &httpGetHeaders{}},
33
{Path: "protocols/http/get-query-string.yaml", TestCase: &httpGetQueryString{}},
34
{Path: "protocols/http/get-redirects.yaml", TestCase: &httpGetRedirects{}},
35
{Path: "protocols/http/get-host-redirects.yaml", TestCase: &httpGetHostRedirects{}},
36
{Path: "protocols/http/disable-redirects.yaml", TestCase: &httpDisableRedirects{}},
37
{Path: "protocols/http/get.yaml", TestCase: &httpGet{}},
38
{Path: "protocols/http/post-body.yaml", TestCase: &httpPostBody{}},
39
{Path: "protocols/http/post-json-body.yaml", TestCase: &httpPostJSONBody{}},
40
{Path: "protocols/http/post-multipart-body.yaml", TestCase: &httpPostMultipartBody{}},
41
{Path: "protocols/http/raw-cookie-reuse.yaml", TestCase: &httpRawCookieReuse{}},
42
{Path: "protocols/http/raw-dynamic-extractor.yaml", TestCase: &httpRawDynamicExtractor{}},
43
{Path: "protocols/http/raw-get-query.yaml", TestCase: &httpRawGetQuery{}},
44
{Path: "protocols/http/raw-get.yaml", TestCase: &httpRawGet{}},
45
{Path: "protocols/http/raw-with-params.yaml", TestCase: &httpRawWithParams{}},
46
{Path: "protocols/http/raw-unsafe-with-params.yaml", TestCase: &httpRawWithParams{}}, // Not a typo, functionality is same as above
47
{Path: "protocols/http/raw-path-trailing-slash.yaml", TestCase: &httpRawPathTrailingSlash{}},
48
{Path: "protocols/http/raw-payload.yaml", TestCase: &httpRawPayload{}},
49
{Path: "protocols/http/raw-post-body.yaml", TestCase: &httpRawPostBody{}},
50
{Path: "protocols/http/raw-unsafe-path.yaml", TestCase: &httpRawUnsafePath{}},
51
{Path: "protocols/http/http-paths.yaml", TestCase: &httpPaths{}},
52
{Path: "protocols/http/request-condition.yaml", TestCase: &httpRequestCondition{}},
53
{Path: "protocols/http/request-condition-new.yaml", TestCase: &httpRequestCondition{}},
54
{Path: "protocols/http/self-contained.yaml", TestCase: &httpRequestSelfContained{}},
55
{Path: "protocols/http/self-contained-with-path.yaml", TestCase: &httpRequestSelfContained{}}, // Not a typo, functionality is same as above
56
{Path: "protocols/http/self-contained-with-params.yaml", TestCase: &httpRequestSelfContainedWithParams{}},
57
{Path: "protocols/http/self-contained-file-input.yaml", TestCase: &httpRequestSelfContainedFileInput{}},
58
{Path: "protocols/http/get-case-insensitive.yaml", TestCase: &httpGetCaseInsensitive{}},
59
{Path: "protocols/http/get.yaml,protocols/http/get-case-insensitive.yaml", TestCase: &httpGetCaseInsensitiveCluster{}},
60
{Path: "protocols/http/get-redirects-chain-headers.yaml", TestCase: &httpGetRedirectsChainHeaders{}},
61
{Path: "protocols/http/dsl-matcher-variable.yaml", TestCase: &httpDSLVariable{}},
62
{Path: "protocols/http/dsl-functions.yaml", TestCase: &httpDSLFunctions{}},
63
{Path: "protocols/http/race-simple.yaml", TestCase: &httpRaceSimple{}},
64
{Path: "protocols/http/race-multiple.yaml", TestCase: &httpRaceMultiple{}},
65
{Path: "protocols/http/stop-at-first-match.yaml", TestCase: &httpStopAtFirstMatch{}},
66
{Path: "protocols/http/stop-at-first-match-with-extractors.yaml", TestCase: &httpStopAtFirstMatchWithExtractors{}},
67
{Path: "protocols/http/variables.yaml", TestCase: &httpVariables{}},
68
{Path: "protocols/http/variable-dsl-function.yaml", TestCase: &httpVariableDSLFunction{}},
69
{Path: "protocols/http/get-override-sni.yaml", TestCase: &httpSniAnnotation{}},
70
{Path: "protocols/http/get-sni.yaml", TestCase: &customCLISNI{}},
71
{Path: "protocols/http/redirect-match-url.yaml", TestCase: &httpRedirectMatchURL{}},
72
{Path: "protocols/http/get-sni-unsafe.yaml", TestCase: &customCLISNIUnsafe{}},
73
{Path: "protocols/http/annotation-timeout.yaml", TestCase: &annotationTimeout{}},
74
{Path: "protocols/http/custom-attack-type.yaml", TestCase: &customAttackType{}},
75
{Path: "protocols/http/get-all-ips.yaml", TestCase: &scanAllIPS{}},
76
{Path: "protocols/http/get-without-scheme.yaml", TestCase: &httpGetWithoutScheme{}},
77
{Path: "protocols/http/cl-body-without-header.yaml", TestCase: &httpCLBodyWithoutHeader{}},
78
{Path: "protocols/http/cl-body-with-header.yaml", TestCase: &httpCLBodyWithHeader{}},
79
{Path: "protocols/http/cli-with-constants.yaml", TestCase: &ConstantWithCliVar{}},
80
{Path: "protocols/http/matcher-status.yaml", TestCase: &matcherStatusTest{}},
81
{Path: "protocols/http/disable-path-automerge.yaml", TestCase: &httpDisablePathAutomerge{}},
82
{Path: "protocols/http/http-preprocessor.yaml", TestCase: &httpPreprocessor{}},
83
{Path: "protocols/http/multi-request.yaml", TestCase: &httpMultiRequest{}},
84
{Path: "protocols/http/http-matcher-extractor-dy-extractor.yaml", TestCase: &httpMatcherExtractorDynamicExtractor{}},
85
{Path: "protocols/http/multi-http-var-sharing.yaml", TestCase: &httpMultiVarSharing{}},
86
{Path: "protocols/http/raw-path-single-slash.yaml", TestCase: &httpRawPathSingleSlash{}},
87
{Path: "protocols/http/raw-unsafe-path-single-slash.yaml", TestCase: &httpRawUnsafePathSingleSlash{}},
88
}
89
90
type httpMultiVarSharing struct{}
91
92
func (h *httpMultiVarSharing) Execute(filePath string) error {
93
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "https://scanme.sh", debug)
94
if err != nil {
95
return err
96
}
97
return expectResultsCount(results, 1)
98
}
99
100
type httpMatcherExtractorDynamicExtractor struct{}
101
102
func (h *httpMatcherExtractorDynamicExtractor) Execute(filePath string) error {
103
router := httprouter.New()
104
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
105
html := `<!DOCTYPE html>
106
<html lang="en">
107
<body>
108
<a href="/domains">Domains</a>
109
</body>
110
</html>`
111
_, _ = fmt.Fprint(w, html)
112
})
113
router.GET("/domains", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
114
html := `<!DOCTYPE html>
115
<html lang="en">
116
<head>
117
<title>Dynamic Extractor Test</title>
118
</head>
119
<body>
120
<!-- The content of the title tag matches the regex pattern for both the extractor and matcher for 'title' -->
121
</body>
122
</html>
123
`
124
_, _ = fmt.Fprint(w, html)
125
})
126
ts := httptest.NewServer(router)
127
defer ts.Close()
128
129
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
130
if err != nil {
131
return err
132
}
133
134
return expectResultsCount(results, 1)
135
}
136
137
type httpInteractshRequest struct{}
138
139
// Execute executes a test case and returns an error if occurred
140
func (h *httpInteractshRequest) Execute(filePath string) error {
141
router := httprouter.New()
142
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
143
value := r.Header.Get("url")
144
if value != "" {
145
if resp, _ := retryablehttp.DefaultClient().Get(value); resp != nil {
146
_ = resp.Body.Close()
147
}
148
}
149
})
150
ts := httptest.NewServer(router)
151
defer ts.Close()
152
153
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
154
if err != nil {
155
return err
156
}
157
158
return expectResultsCount(results, 1, 2)
159
}
160
161
type httpDefaultMatcherCondition struct{}
162
163
// Execute executes a test case and returns an error if occurred
164
func (d *httpDefaultMatcherCondition) Execute(filePath string) error {
165
// to simulate matcher-condition `or`
166
// - template should be run twice and vulnerable server should send response that fits for that specific run
167
router := httprouter.New()
168
var routerErr error
169
// Server endpoint where only interactsh matcher is successful and status code is not 200
170
router.GET("/interactsh/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
171
value := r.URL.Query().Get("url")
172
if value != "" {
173
if _, err := retryablehttp.DefaultClient().Get("https://" + value); err != nil {
174
routerErr = err
175
}
176
}
177
w.WriteHeader(http.StatusNotFound)
178
})
179
// Server endpoint where url is not probed but sends a 200 status code
180
router.GET("/status/", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
181
w.WriteHeader(http.StatusOK)
182
})
183
ts := httptest.NewServer(router)
184
defer ts.Close()
185
186
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/status", debug)
187
if err != nil {
188
return err
189
}
190
if err := expectResultsCount(results, 1); err != nil {
191
return err
192
}
193
194
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/interactsh", debug)
195
if err != nil {
196
return err
197
}
198
if routerErr != nil {
199
return errkit.Wrap(routerErr, "failed to send http request to interactsh server")
200
}
201
if err := expectResultsCount(results, 1); err != nil {
202
return err
203
}
204
return nil
205
}
206
207
type httpInteractshStopAtFirstMatchRequest struct{}
208
209
// Execute executes a test case and returns an error if occurred
210
func (h *httpInteractshStopAtFirstMatchRequest) Execute(filePath string) error {
211
router := httprouter.New()
212
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
213
value := r.Header.Get("url")
214
if value != "" {
215
if resp, _ := retryablehttp.DefaultClient().Get(value); resp != nil {
216
_ = resp.Body.Close()
217
}
218
}
219
})
220
ts := httptest.NewServer(router)
221
defer ts.Close()
222
223
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
224
if err != nil {
225
return err
226
}
227
// polling is asynchronous, so the interactions may be retrieved after the first request
228
return expectResultsCount(results, 1)
229
}
230
231
type httpGetHeaders struct{}
232
233
// Execute executes a test case and returns an error if occurred
234
func (h *httpGetHeaders) Execute(filePath string) error {
235
router := httprouter.New()
236
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
237
if strings.EqualFold(r.Header.Get("test"), "nuclei") {
238
_, _ = fmt.Fprintf(w, "This is test headers matcher text")
239
}
240
})
241
ts := httptest.NewServer(router)
242
defer ts.Close()
243
244
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
245
if err != nil {
246
return err
247
}
248
249
return expectResultsCount(results, 1)
250
}
251
252
type httpGetQueryString struct{}
253
254
// Execute executes a test case and returns an error if occurred
255
func (h *httpGetQueryString) Execute(filePath string) error {
256
router := httprouter.New()
257
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
258
if strings.EqualFold(r.URL.Query().Get("test"), "nuclei") {
259
_, _ = fmt.Fprintf(w, "This is test querystring matcher text")
260
}
261
})
262
ts := httptest.NewServer(router)
263
defer ts.Close()
264
265
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
266
if err != nil {
267
return err
268
}
269
270
return expectResultsCount(results, 1)
271
}
272
273
type httpGetRedirects struct{}
274
275
// Execute executes a test case and returns an error if occurred
276
func (h *httpGetRedirects) Execute(filePath string) error {
277
router := httprouter.New()
278
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
279
http.Redirect(w, r, "/redirected", http.StatusFound)
280
})
281
router.GET("/redirected", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
282
_, _ = fmt.Fprintf(w, "This is test redirects matcher text")
283
})
284
ts := httptest.NewServer(router)
285
defer ts.Close()
286
287
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
288
if err != nil {
289
return err
290
}
291
292
return expectResultsCount(results, 1)
293
}
294
295
type httpGetHostRedirects struct{}
296
297
// Execute executes a test case and returns an error if occurred
298
func (h *httpGetHostRedirects) Execute(filePath string) error {
299
router := httprouter.New()
300
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
301
http.Redirect(w, r, "/redirected1", http.StatusFound)
302
})
303
router.GET("/redirected1", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
304
http.Redirect(w, r, "redirected2", http.StatusFound)
305
})
306
router.GET("/redirected2", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
307
http.Redirect(w, r, "/redirected3", http.StatusFound)
308
})
309
router.GET("/redirected3", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
310
http.Redirect(w, r, "https://scanme.sh", http.StatusTemporaryRedirect)
311
})
312
ts := httptest.NewServer(router)
313
defer ts.Close()
314
315
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
316
if err != nil {
317
return err
318
}
319
320
return expectResultsCount(results, 1)
321
}
322
323
type httpDisableRedirects struct{}
324
325
// Execute executes a test case and returns an error if occurred
326
func (h *httpDisableRedirects) Execute(filePath string) error {
327
router := httprouter.New()
328
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
329
http.Redirect(w, r, "/redirected", http.StatusMovedPermanently)
330
})
331
router.GET("/redirected", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
332
_, _ = fmt.Fprintf(w, "This is test redirects matcher text")
333
})
334
ts := httptest.NewServer(router)
335
defer ts.Close()
336
337
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-dr")
338
if err != nil {
339
return err
340
}
341
342
return expectResultsCount(results, 0)
343
}
344
345
type httpGet struct{}
346
347
// Execute executes a test case and returns an error if occurred
348
func (h *httpGet) Execute(filePath string) error {
349
router := httprouter.New()
350
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
351
_, _ = fmt.Fprintf(w, "This is test matcher text")
352
})
353
ts := httptest.NewServer(router)
354
defer ts.Close()
355
356
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
357
if err != nil {
358
return err
359
}
360
361
return expectResultsCount(results, 1)
362
}
363
364
type httpDSLVariable struct{}
365
366
// Execute executes a test case and returns an error if occurred
367
func (h *httpDSLVariable) Execute(filePath string) error {
368
router := httprouter.New()
369
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
370
_, _ = fmt.Fprintf(w, "This is test matcher text")
371
})
372
ts := httptest.NewServer(router)
373
defer ts.Close()
374
375
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
376
if err != nil {
377
return err
378
}
379
380
return expectResultsCount(results, 5)
381
}
382
383
type httpDSLFunctions struct{}
384
385
func (h *httpDSLFunctions) Execute(filePath string) error {
386
router := httprouter.New()
387
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
388
request, err := httputil.DumpRequest(r, true)
389
if err != nil {
390
_, _ = fmt.Fprint(w, err.Error())
391
} else {
392
_, _ = fmt.Fprint(w, string(request))
393
}
394
})
395
ts := httptest.NewServer(router)
396
defer ts.Close()
397
398
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-nc")
399
if err != nil {
400
return err
401
}
402
403
if err := expectResultsCount(results, 1); err != nil {
404
return err
405
}
406
407
// get result part
408
resultPart, err := stringsutil.After(results[0], ts.URL)
409
if err != nil {
410
return err
411
}
412
413
// remove additional characters till the first valid result and ignore last ] which doesn't alter the total count
414
resultPart = stringsutil.TrimPrefixAny(resultPart, "/", " ", "[")
415
416
extracted := strings.Split(resultPart, ",")
417
numberOfDslFunctions := 88
418
if len(extracted) != numberOfDslFunctions {
419
return errors.New("incorrect number of results")
420
}
421
422
for _, header := range extracted {
423
header = strings.Trim(header, `"`)
424
parts := strings.Split(header, ": ")
425
index, err := strconv.Atoi(parts[0])
426
if err != nil {
427
return err
428
}
429
if index < 0 || index > numberOfDslFunctions {
430
return fmt.Errorf("incorrect header index found: %d", index)
431
}
432
if strings.TrimSpace(parts[1]) == "" {
433
return fmt.Errorf("the DSL expression with index %d was not evaluated correctly", index)
434
}
435
}
436
437
return nil
438
}
439
440
type httpPostBody struct{}
441
442
// Execute executes a test case and returns an error if occurred
443
func (h *httpPostBody) Execute(filePath string) error {
444
router := httprouter.New()
445
var routerErr error
446
447
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
448
if err := r.ParseForm(); err != nil {
449
routerErr = err
450
return
451
}
452
if strings.EqualFold(r.Form.Get("username"), "test") && strings.EqualFold(r.Form.Get("password"), "nuclei") {
453
_, _ = fmt.Fprintf(w, "This is test post-body matcher text")
454
}
455
})
456
ts := httptest.NewServer(router)
457
defer ts.Close()
458
459
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
460
if err != nil {
461
return err
462
}
463
if routerErr != nil {
464
return routerErr
465
}
466
467
return expectResultsCount(results, 1)
468
}
469
470
type httpPostJSONBody struct{}
471
472
// Execute executes a test case and returns an error if occurred
473
func (h *httpPostJSONBody) Execute(filePath string) error {
474
router := httprouter.New()
475
var routerErr error
476
477
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
478
type doc struct {
479
Username string `json:"username"`
480
Password string `json:"password"`
481
}
482
obj := &doc{}
483
if err := json.NewDecoder(r.Body).Decode(obj); err != nil {
484
routerErr = err
485
return
486
}
487
if strings.EqualFold(obj.Username, "test") && strings.EqualFold(obj.Password, "nuclei") {
488
_, _ = fmt.Fprintf(w, "This is test post-json-body matcher text")
489
}
490
})
491
ts := httptest.NewServer(router)
492
defer ts.Close()
493
494
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
495
if err != nil {
496
return err
497
}
498
if routerErr != nil {
499
return routerErr
500
}
501
502
return expectResultsCount(results, 1)
503
}
504
505
type httpPostMultipartBody struct{}
506
507
// Execute executes a test case and returns an error if occurred
508
func (h *httpPostMultipartBody) Execute(filePath string) error {
509
router := httprouter.New()
510
var routerErr error
511
512
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
513
if err := r.ParseMultipartForm(unitutils.Mega); err != nil {
514
routerErr = err
515
return
516
}
517
password, ok := r.MultipartForm.Value["password"]
518
if !ok || len(password) != 1 {
519
routerErr = errors.New("no password in request")
520
return
521
}
522
file := r.MultipartForm.File["username"]
523
if len(file) != 1 {
524
routerErr = errors.New("no file in request")
525
return
526
}
527
if strings.EqualFold(password[0], "nuclei") && strings.EqualFold(file[0].Filename, "username") {
528
_, _ = fmt.Fprintf(w, "This is test post-multipart matcher text")
529
}
530
})
531
ts := httptest.NewServer(router)
532
defer ts.Close()
533
534
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
535
if err != nil {
536
return err
537
}
538
if routerErr != nil {
539
return routerErr
540
}
541
542
return expectResultsCount(results, 1)
543
}
544
545
type httpRawDynamicExtractor struct{}
546
547
// Execute executes a test case and returns an error if occurred
548
func (h *httpRawDynamicExtractor) Execute(filePath string) error {
549
router := httprouter.New()
550
var routerErr error
551
552
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
553
if err := r.ParseForm(); err != nil {
554
routerErr = err
555
return
556
}
557
if strings.EqualFold(r.Form.Get("testing"), "parameter") {
558
_, _ = fmt.Fprintf(w, "Token: 'nuclei'")
559
}
560
})
561
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
562
if strings.EqualFold(r.URL.Query().Get("username"), "nuclei") {
563
_, _ = fmt.Fprintf(w, "Test is test-dynamic-extractor-raw matcher text")
564
}
565
})
566
ts := httptest.NewServer(router)
567
defer ts.Close()
568
569
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
570
if err != nil {
571
return err
572
}
573
if routerErr != nil {
574
return routerErr
575
}
576
577
return expectResultsCount(results, 1)
578
}
579
580
type httpRawGetQuery struct{}
581
582
// Execute executes a test case and returns an error if occurred
583
func (h *httpRawGetQuery) Execute(filePath string) error {
584
router := httprouter.New()
585
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
586
if strings.EqualFold(r.URL.Query().Get("test"), "nuclei") {
587
_, _ = fmt.Fprintf(w, "Test is test raw-get-query-matcher text")
588
}
589
})
590
ts := httptest.NewServer(router)
591
defer ts.Close()
592
593
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
594
if err != nil {
595
return err
596
}
597
598
return expectResultsCount(results, 1)
599
}
600
601
type httpRawGet struct{}
602
603
// Execute executes a test case and returns an error if occurred
604
func (h *httpRawGet) Execute(filePath string) error {
605
router := httprouter.New()
606
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
607
_, _ = fmt.Fprintf(w, "Test is test raw-get-matcher text")
608
})
609
ts := httptest.NewServer(router)
610
defer ts.Close()
611
612
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
613
if err != nil {
614
return err
615
}
616
617
return expectResultsCount(results, 1)
618
}
619
620
type httpRawWithParams struct{}
621
622
// Execute executes a test case and returns an error if occurred
623
func (h *httpRawWithParams) Execute(filePath string) error {
624
router := httprouter.New()
625
var errx error
626
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
627
params := r.URL.Query()
628
// we intentionally use params["test"] instead of params.Get("test") to test the case where
629
// there are multiple parameters with the same name
630
if !reflect.DeepEqual(params["key1"], []string{"value1"}) {
631
errx = errkit.Append(errx, errkit.New("key1 not found in params", "expected", []string{"value1"}, "got", params["key1"]))
632
}
633
if !reflect.DeepEqual(params["key2"], []string{"value2"}) {
634
errx = errkit.Append(errx, errkit.New("key2 not found in params", "expected", []string{"value2"}, "got", params["key2"]))
635
}
636
_, _ = fmt.Fprintf(w, "Test is test raw-params-matcher text")
637
})
638
ts := httptest.NewServer(router)
639
defer ts.Close()
640
641
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?key1=value1", debug)
642
if err != nil {
643
return err
644
}
645
if errx != nil {
646
return err
647
}
648
return expectResultsCount(results, 1)
649
}
650
651
type httpRawPathTrailingSlash struct{}
652
653
func (h *httpRawPathTrailingSlash) Execute(filepath string) error {
654
router := httprouter.New()
655
var routerErr error
656
657
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
658
if r.RequestURI != "/test/..;/..;/" {
659
routerErr = fmt.Errorf("expected path /test/..;/..;/ but got %v", r.RequestURI)
660
return
661
}
662
})
663
ts := httptest.NewServer(router)
664
defer ts.Close()
665
666
_, err := testutils.RunNucleiTemplateAndGetResults(filepath, ts.URL, debug)
667
if err != nil {
668
return err
669
}
670
if routerErr != nil {
671
return routerErr
672
}
673
return nil
674
}
675
676
type httpRawPayload struct{}
677
678
// Execute executes a test case and returns an error if occurred
679
func (h *httpRawPayload) Execute(filePath string) error {
680
router := httprouter.New()
681
var routerErr error
682
683
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
684
if err := r.ParseForm(); err != nil {
685
routerErr = err
686
return
687
}
688
if !strings.EqualFold(r.Header.Get("another_header"), "bnVjbGVp") && !strings.EqualFold(r.Header.Get("another_header"), "Z3Vlc3Q=") {
689
return
690
}
691
if strings.EqualFold(r.Form.Get("username"), "test") && (strings.EqualFold(r.Form.Get("password"), "nuclei") || strings.EqualFold(r.Form.Get("password"), "guest")) {
692
_, _ = fmt.Fprintf(w, "Test is raw-payload matcher text")
693
}
694
})
695
ts := httptest.NewServer(router)
696
defer ts.Close()
697
698
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
699
if err != nil {
700
return err
701
}
702
if routerErr != nil {
703
return routerErr
704
}
705
706
return expectResultsCount(results, 2)
707
}
708
709
type httpRawPostBody struct{}
710
711
// Execute executes a test case and returns an error if occurred
712
func (h *httpRawPostBody) Execute(filePath string) error {
713
router := httprouter.New()
714
var routerErr error
715
716
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
717
if err := r.ParseForm(); err != nil {
718
routerErr = err
719
return
720
}
721
if strings.EqualFold(r.Form.Get("username"), "test") && strings.EqualFold(r.Form.Get("password"), "nuclei") {
722
_, _ = fmt.Fprintf(w, "Test is test raw-post-body-matcher text")
723
}
724
})
725
ts := httptest.NewServer(router)
726
defer ts.Close()
727
728
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
729
if err != nil {
730
return err
731
}
732
if routerErr != nil {
733
return routerErr
734
}
735
736
return expectResultsCount(results, 1)
737
}
738
739
type httpRawUnsafePath struct{}
740
741
func (h *httpRawUnsafePath) Execute(filepath string) error {
742
// testing unsafe paths using router feedback is not possible cause they are `unsafe urls`
743
// hence it is done by parsing and matching paths from nuclei output with `-debug-req` flag
744
// read template files
745
bin, err := os.ReadFile(filepath)
746
if err != nil {
747
return err
748
}
749
750
// Instead of storing expected `paths` in code it is stored in
751
// `reference` section of template
752
type template struct {
753
Info struct {
754
Reference []string `yaml:"reference"`
755
}
756
}
757
var tpl template
758
if err = yaml.Unmarshal(bin, &tpl); err != nil {
759
return err
760
}
761
// expected relative paths
762
expected := []string{}
763
expected = append(expected, tpl.Info.Reference...)
764
if len(expected) == 0 {
765
return fmt.Errorf("something went wrong with %v template", filepath)
766
}
767
768
results, err := testutils.RunNucleiBinaryAndGetCombinedOutput(debug, []string{"-t", filepath, "-u", "scanme.sh", "-debug-req"})
769
if err != nil {
770
return err
771
}
772
773
actual := []string{}
774
for _, v := range strings.Split(results, "\n") {
775
if strings.Contains(v, "GET") {
776
parts := strings.Fields(v)
777
if len(parts) == 3 {
778
actual = append(actual, parts[1])
779
}
780
}
781
}
782
783
if !reflect.DeepEqual(expected, actual) {
784
return fmt.Errorf("%8v: %v\n%-8v: %v", "expected", expected, "actual", actual)
785
}
786
return nil
787
}
788
789
type httpPaths struct{}
790
791
func (h *httpPaths) Execute(filepath string) error {
792
// covers testcases similar to httpRawUnsafePath but when `unsafe:false`
793
bin, err := os.ReadFile(filepath)
794
if err != nil {
795
return err
796
}
797
798
// Instead of storing expected `paths` in code it is stored in
799
// `reference` section of template
800
type template struct {
801
Info struct {
802
Reference []string `yaml:"reference"`
803
}
804
}
805
var tpl template
806
if err = yaml.Unmarshal(bin, &tpl); err != nil {
807
return err
808
}
809
// expected relative paths
810
expected := []string{}
811
expected = append(expected, tpl.Info.Reference...)
812
if len(expected) == 0 {
813
return fmt.Errorf("something went wrong with %v template", filepath)
814
}
815
816
results, err := testutils.RunNucleiBinaryAndGetCombinedOutput(debug, []string{"-t", filepath, "-u", "scanme.sh", "-debug-req"})
817
if err != nil {
818
return err
819
}
820
821
actual := []string{}
822
for _, v := range strings.Split(results, "\n") {
823
if strings.Contains(v, "GET") {
824
parts := strings.Fields(v)
825
if len(parts) == 3 {
826
actual = append(actual, parts[1])
827
}
828
}
829
}
830
831
if len(expected) > len(actual) {
832
actualValuesIndex := max(len(actual)-1, 0)
833
return fmt.Errorf("missing values : %v", expected[actualValuesIndex:])
834
} else if len(expected) < len(actual) {
835
return fmt.Errorf("unexpected values : %v", actual[len(expected)-1:])
836
} else {
837
if !reflect.DeepEqual(expected, actual) {
838
return fmt.Errorf("expected: %v\n\nactual: %v", expected, actual)
839
}
840
}
841
return nil
842
}
843
844
type httpRawCookieReuse struct{}
845
846
// Execute executes a test case and returns an error if occurred
847
func (h *httpRawCookieReuse) Execute(filePath string) error {
848
router := httprouter.New()
849
var routerErr error
850
851
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
852
if err := r.ParseForm(); err != nil {
853
routerErr = err
854
return
855
}
856
if strings.EqualFold(r.Form.Get("testing"), "parameter") {
857
http.SetCookie(w, &http.Cookie{Name: "nuclei", Value: "test"})
858
}
859
})
860
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
861
if err := r.ParseForm(); err != nil {
862
routerErr = err
863
return
864
}
865
cookie, err := r.Cookie("nuclei")
866
if err != nil {
867
routerErr = err
868
return
869
}
870
871
if strings.EqualFold(cookie.Value, "test") {
872
_, _ = fmt.Fprintf(w, "Test is test-cookie-reuse matcher text")
873
}
874
})
875
ts := httptest.NewServer(router)
876
defer ts.Close()
877
878
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
879
if err != nil {
880
return err
881
}
882
if routerErr != nil {
883
return routerErr
884
}
885
886
return expectResultsCount(results, 1)
887
}
888
889
// TODO: excluded due to parsing errors with console
890
// type httpRawUnsafeRequest struct{
891
// Execute executes a test case and returns an error if occurred
892
// func (h *httpRawUnsafeRequest) Execute(filePath string) error {
893
// var routerErr error
894
//
895
// ts := testutils.NewTCPServer(nil, defaultStaticPort, func(conn net.Conn) {
896
// defer conn.Close()
897
// _, _ = conn.Write([]byte("protocols/http/1.1 200 OK\r\nContent-Length: 36\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nThis is test raw-unsafe-matcher test"))
898
// })
899
// defer ts.Close()
900
//
901
// results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "http://"+ts.URL, debug)
902
// if err != nil {
903
// return err
904
// }
905
// if routerErr != nil {
906
// return routerErr
907
// }
908
//
909
// return expectResultsCount(results, 1)
910
// }
911
912
type httpRequestCondition struct{}
913
914
// Execute executes a test case and returns an error if occurred
915
func (h *httpRequestCondition) Execute(filePath string) error {
916
router := httprouter.New()
917
918
router.GET("/200", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
919
w.WriteHeader(http.StatusOK)
920
})
921
router.GET("/400", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
922
w.WriteHeader(http.StatusBadRequest)
923
})
924
ts := httptest.NewServer(router)
925
defer ts.Close()
926
927
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
928
if err != nil {
929
return err
930
}
931
932
return expectResultsCount(results, 1)
933
}
934
935
type httpRequestSelfContained struct{}
936
937
// Execute executes a test case and returns an error if occurred
938
func (h *httpRequestSelfContained) Execute(filePath string) error {
939
router := httprouter.New()
940
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
941
_, _ = w.Write([]byte("This is self-contained response"))
942
})
943
server := &http.Server{
944
Addr: fmt.Sprintf("localhost:%d", defaultStaticPort),
945
Handler: router,
946
}
947
go func() {
948
_ = server.ListenAndServe()
949
}()
950
defer func() {
951
_ = server.Close()
952
}()
953
954
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
955
if err != nil {
956
return err
957
}
958
959
return expectResultsCount(results, 1)
960
}
961
962
// testcase to check duplicated values in params
963
type httpRequestSelfContainedWithParams struct{}
964
965
// Execute executes a test case and returns an error if occurred
966
func (h *httpRequestSelfContainedWithParams) Execute(filePath string) error {
967
router := httprouter.New()
968
var errx error
969
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
970
params := r.URL.Query()
971
// we intentionally use params["test"] instead of params.Get("test") to test the case where
972
// there are multiple parameters with the same name
973
if !reflect.DeepEqual(params["something"], []string{"here"}) {
974
errx = errkit.Append(errx, errkit.New("something not found in params", "expected", []string{"here"}, "got", params["something"]))
975
}
976
if !reflect.DeepEqual(params["key"], []string{"value"}) {
977
errx = errkit.Append(errx, errkit.New("key not found in params", "expected", []string{"value"}, "got", params["key"]))
978
}
979
_, _ = w.Write([]byte("This is self-contained response"))
980
})
981
server := &http.Server{
982
Addr: fmt.Sprintf("localhost:%d", defaultStaticPort),
983
Handler: router,
984
}
985
go func() {
986
_ = server.ListenAndServe()
987
}()
988
defer func() {
989
_ = server.Close()
990
}()
991
992
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
993
if err != nil {
994
return err
995
}
996
if errx != nil {
997
return errx
998
}
999
1000
return expectResultsCount(results, 1)
1001
}
1002
1003
type httpRequestSelfContainedFileInput struct{}
1004
1005
func (h *httpRequestSelfContainedFileInput) Execute(filePath string) error {
1006
router := httprouter.New()
1007
gotReqToEndpoints := []string{}
1008
router.GET("/one", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1009
gotReqToEndpoints = append(gotReqToEndpoints, "/one")
1010
_, _ = w.Write([]byte("This is self-contained response"))
1011
})
1012
router.GET("/two", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1013
gotReqToEndpoints = append(gotReqToEndpoints, "/two")
1014
_, _ = w.Write([]byte("This is self-contained response"))
1015
})
1016
server := &http.Server{
1017
Addr: fmt.Sprintf("localhost:%d", defaultStaticPort),
1018
Handler: router,
1019
}
1020
go func() {
1021
_ = server.ListenAndServe()
1022
}()
1023
defer func() {
1024
_ = server.Close()
1025
}()
1026
1027
// create temp file
1028
FileLoc, err := os.CreateTemp("", "self-contained-payload-*.txt")
1029
if err != nil {
1030
return errkit.Wrap(err, "failed to create temp file")
1031
}
1032
if _, err := FileLoc.Write([]byte("one\ntwo\n")); err != nil {
1033
return errkit.Wrap(err, "failed to write payload to temp file")
1034
}
1035
defer func() {
1036
_ = FileLoc.Close()
1037
}()
1038
1039
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-V", "test="+FileLoc.Name(), "-esc")
1040
if err != nil {
1041
return err
1042
}
1043
1044
if err := expectResultsCount(results, 4); err != nil {
1045
return err
1046
}
1047
1048
if !sliceutil.ElementsMatch(gotReqToEndpoints, []string{"/one", "/two", "/one", "/two"}) {
1049
return errkit.New("expected requests to be sent to `/one` and `/two` endpoints but were sent to `%v`", gotReqToEndpoints, "filePath", filePath)
1050
}
1051
return nil
1052
}
1053
1054
type httpGetCaseInsensitive struct{}
1055
1056
// Execute executes a test case and returns an error if occurred
1057
func (h *httpGetCaseInsensitive) Execute(filePath string) error {
1058
router := httprouter.New()
1059
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1060
_, _ = fmt.Fprintf(w, "THIS IS TEST MATCHER TEXT")
1061
})
1062
ts := httptest.NewServer(router)
1063
defer ts.Close()
1064
1065
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1066
if err != nil {
1067
return err
1068
}
1069
1070
return expectResultsCount(results, 1)
1071
}
1072
1073
type httpGetCaseInsensitiveCluster struct{}
1074
1075
// Execute executes a test case and returns an error if occurred
1076
func (h *httpGetCaseInsensitiveCluster) Execute(filesPath string) error {
1077
router := httprouter.New()
1078
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1079
_, _ = fmt.Fprintf(w, "This is test matcher text")
1080
})
1081
ts := httptest.NewServer(router)
1082
defer ts.Close()
1083
1084
files := strings.Split(filesPath, ",")
1085
1086
results, err := testutils.RunNucleiTemplateAndGetResults(files[0], ts.URL, debug, "-t", files[1])
1087
if err != nil {
1088
return err
1089
}
1090
1091
return expectResultsCount(results, 2)
1092
}
1093
1094
type httpGetRedirectsChainHeaders struct{}
1095
1096
// Execute executes a test case and returns an error if occurred
1097
func (h *httpGetRedirectsChainHeaders) Execute(filePath string) error {
1098
router := httprouter.New()
1099
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1100
http.Redirect(w, r, "/redirected", http.StatusFound)
1101
})
1102
router.GET("/redirected", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1103
w.Header().Set("Secret", "TestRedirectHeaderMatch")
1104
http.Redirect(w, r, "/final", http.StatusFound)
1105
})
1106
router.GET("/final", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1107
_, _ = w.Write([]byte("ok"))
1108
})
1109
ts := httptest.NewServer(router)
1110
defer ts.Close()
1111
1112
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1113
if err != nil {
1114
return err
1115
}
1116
1117
return expectResultsCount(results, 1)
1118
}
1119
1120
type httpRaceSimple struct{}
1121
1122
// Execute executes a test case and returns an error if occurred
1123
func (h *httpRaceSimple) Execute(filePath string) error {
1124
router := httprouter.New()
1125
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1126
w.WriteHeader(http.StatusOK)
1127
})
1128
ts := httptest.NewServer(router)
1129
defer ts.Close()
1130
1131
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1132
if err != nil {
1133
return err
1134
}
1135
return expectResultsCount(results, 10)
1136
}
1137
1138
type httpRaceMultiple struct{}
1139
1140
// Execute executes a test case and returns an error if occurred
1141
func (h *httpRaceMultiple) Execute(filePath string) error {
1142
router := httprouter.New()
1143
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1144
w.WriteHeader(http.StatusOK)
1145
})
1146
ts := httptest.NewServer(router)
1147
defer ts.Close()
1148
1149
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1150
if err != nil {
1151
return err
1152
}
1153
return expectResultsCount(results, 5)
1154
}
1155
1156
type httpStopAtFirstMatch struct{}
1157
1158
// Execute executes a test case and returns an error if occurred
1159
func (h *httpStopAtFirstMatch) Execute(filePath string) error {
1160
router := httprouter.New()
1161
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1162
_, _ = fmt.Fprintf(w, "This is test")
1163
})
1164
ts := httptest.NewServer(router)
1165
defer ts.Close()
1166
1167
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1168
if err != nil {
1169
return err
1170
}
1171
1172
return expectResultsCount(results, 1)
1173
}
1174
1175
type httpStopAtFirstMatchWithExtractors struct{}
1176
1177
// Execute executes a test case and returns an error if occurred
1178
func (h *httpStopAtFirstMatchWithExtractors) Execute(filePath string) error {
1179
router := httprouter.New()
1180
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1181
_, _ = fmt.Fprintf(w, "This is test")
1182
})
1183
ts := httptest.NewServer(router)
1184
defer ts.Close()
1185
1186
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1187
if err != nil {
1188
return err
1189
}
1190
1191
return expectResultsCount(results, 2)
1192
}
1193
1194
type httpVariables struct{}
1195
1196
// Execute executes a test case and returns an error if occurred
1197
func (h *httpVariables) Execute(filePath string) error {
1198
router := httprouter.New()
1199
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1200
_, _ = fmt.Fprintf(w, "%s\n%s\n%s", r.Header.Get("Test"), r.Header.Get("Another"), r.Header.Get("Email"))
1201
})
1202
ts := httptest.NewServer(router)
1203
defer ts.Close()
1204
1205
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1206
if err != nil {
1207
return err
1208
}
1209
if err := expectResultsCount(results, 1); err != nil {
1210
return err
1211
}
1212
1213
// variable override that does not have any match
1214
// to make sure the variable override is working
1215
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-var", "a1=failed")
1216
if err != nil {
1217
return err
1218
}
1219
1220
return expectResultsCount(results, 0)
1221
}
1222
1223
type httpVariableDSLFunction struct{}
1224
1225
// Execute executes a test case and returns an error if occurred
1226
func (h *httpVariableDSLFunction) Execute(filePath string) error {
1227
results, err := testutils.RunNucleiBinaryAndGetCombinedOutput(debug, []string{"-t", filePath, "-u", "https://scanme.sh", "-debug-req"})
1228
if err != nil {
1229
return err
1230
}
1231
1232
actual := []string{}
1233
for _, v := range strings.Split(results, "\n") {
1234
if strings.Contains(v, "GET") {
1235
parts := strings.Fields(v)
1236
if len(parts) == 3 {
1237
actual = append(actual, parts[1])
1238
}
1239
}
1240
}
1241
if len(actual) == 2 && actual[0] == actual[1] {
1242
return nil
1243
}
1244
1245
return fmt.Errorf("expected 2 requests with same URL, got %v", actual)
1246
}
1247
1248
type customCLISNI struct{}
1249
1250
// Execute executes a test case and returns an error if occurred
1251
func (h *customCLISNI) Execute(filePath string) error {
1252
router := httprouter.New()
1253
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1254
if r.TLS.ServerName == "test" {
1255
_, _ = w.Write([]byte("test-ok"))
1256
} else {
1257
_, _ = w.Write([]byte("test-ko"))
1258
}
1259
})
1260
ts := httptest.NewTLSServer(router)
1261
defer ts.Close()
1262
1263
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-sni", "test")
1264
if err != nil {
1265
return err
1266
}
1267
return expectResultsCount(results, 1)
1268
}
1269
1270
type httpSniAnnotation struct{}
1271
1272
// Execute executes a test case and returns an error if occurred
1273
func (h *httpSniAnnotation) Execute(filePath string) error {
1274
router := httprouter.New()
1275
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1276
if r.TLS.ServerName == "test" {
1277
_, _ = w.Write([]byte("test-ok"))
1278
} else {
1279
_, _ = w.Write([]byte("test-ko"))
1280
}
1281
})
1282
ts := httptest.NewTLSServer(router)
1283
defer ts.Close()
1284
1285
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1286
if err != nil {
1287
return err
1288
}
1289
return expectResultsCount(results, 1)
1290
}
1291
1292
type httpRedirectMatchURL struct{}
1293
1294
// Execute executes a test case and returns an error if occurred
1295
func (h *httpRedirectMatchURL) Execute(filePath string) error {
1296
router := httprouter.New()
1297
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1298
http.Redirect(w, r, "/redirected", http.StatusFound)
1299
_, _ = w.Write([]byte("This is test redirects matcher text"))
1300
})
1301
router.GET("/redirected", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1302
_, _ = fmt.Fprintf(w, "This is test redirects matcher text")
1303
})
1304
ts := httptest.NewServer(router)
1305
defer ts.Close()
1306
1307
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-no-meta")
1308
if err != nil {
1309
return err
1310
}
1311
1312
if err := expectResultsCount(results, 1); err != nil {
1313
return err
1314
}
1315
if results[0] != fmt.Sprintf("%s/redirected", ts.URL) {
1316
return fmt.Errorf("mismatched url found: %s", results[0])
1317
}
1318
return nil
1319
}
1320
1321
type customCLISNIUnsafe struct{}
1322
1323
// Execute executes a test case and returns an error if occurred
1324
func (h *customCLISNIUnsafe) Execute(filePath string) error {
1325
router := httprouter.New()
1326
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1327
if r.TLS.ServerName == "test" {
1328
_, _ = w.Write([]byte("test-ok"))
1329
} else {
1330
_, _ = w.Write([]byte("test-ko"))
1331
}
1332
})
1333
ts := httptest.NewTLSServer(router)
1334
defer ts.Close()
1335
1336
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-sni", "test")
1337
if err != nil {
1338
return err
1339
}
1340
return expectResultsCount(results, 1)
1341
}
1342
1343
type annotationTimeout struct{}
1344
1345
// Execute executes a test case and returns an error if occurred
1346
func (h *annotationTimeout) Execute(filePath string) error {
1347
router := httprouter.New()
1348
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1349
time.Sleep(4 * time.Second)
1350
_, _ = fmt.Fprintf(w, "This is test matcher text")
1351
})
1352
ts := httptest.NewTLSServer(router)
1353
defer ts.Close()
1354
1355
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-timeout", "1")
1356
if err != nil {
1357
return err
1358
}
1359
return expectResultsCount(results, 1)
1360
}
1361
1362
type customAttackType struct{}
1363
1364
// Execute executes a test case and returns an error if occurred
1365
func (h *customAttackType) Execute(filePath string) error {
1366
router := httprouter.New()
1367
got := []string{}
1368
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1369
got = append(got, r.URL.RawQuery)
1370
_, _ = fmt.Fprintf(w, "This is test custom payload")
1371
})
1372
ts := httptest.NewTLSServer(router)
1373
defer ts.Close()
1374
1375
_, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-attack-type", "clusterbomb")
1376
if err != nil {
1377
return err
1378
}
1379
return expectResultsCount(got, 4)
1380
}
1381
1382
// Disabled as GH doesn't support ipv6
1383
type scanAllIPS struct{}
1384
1385
// Execute executes a test case and returns an error if occurred
1386
func (h *scanAllIPS) Execute(filePath string) error {
1387
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, "https://scanme.sh", debug, "-scan-all-ips", "-iv", "4")
1388
if err != nil {
1389
return err
1390
}
1391
// limiting test to ipv4 (GH doesn't support ipv6)
1392
return expectResultsCount(got, 1)
1393
}
1394
1395
// ensure that ip|host are handled without http|https scheme
1396
type httpGetWithoutScheme struct{}
1397
1398
// Execute executes a test case and returns an error if occurred
1399
func (h *httpGetWithoutScheme) Execute(filePath string) error {
1400
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, "scanme.sh", debug)
1401
if err != nil {
1402
return err
1403
}
1404
return expectResultsCount(got, 1)
1405
}
1406
1407
// content-length in case the response has no header but has a body
1408
type httpCLBodyWithoutHeader struct{}
1409
1410
// Execute executes a test case and returns an error if occurred
1411
func (h *httpCLBodyWithoutHeader) Execute(filePath string) error {
1412
logutil.DisableDefaultLogger()
1413
defer logutil.EnableDefaultLogger()
1414
1415
router := httprouter.New()
1416
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1417
w.Header()["Content-Length"] = []string{"-1"}
1418
_, _ = fmt.Fprintf(w, "this is a test")
1419
})
1420
ts := httptest.NewTLSServer(router)
1421
defer ts.Close()
1422
1423
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1424
if err != nil {
1425
return err
1426
}
1427
return expectResultsCount(got, 1)
1428
}
1429
1430
// content-length in case the response has content-length header and a body
1431
type httpCLBodyWithHeader struct{}
1432
1433
// Execute executes a test case and returns an error if occurred
1434
func (h *httpCLBodyWithHeader) Execute(filePath string) error {
1435
router := httprouter.New()
1436
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1437
w.Header()["Content-Length"] = []string{"50000"}
1438
_, _ = fmt.Fprintf(w, "this is a test")
1439
})
1440
ts := httptest.NewTLSServer(router)
1441
defer ts.Close()
1442
1443
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1444
if err != nil {
1445
return err
1446
}
1447
return expectResultsCount(got, 1)
1448
}
1449
1450
// constant shouldn't be overwritten by cli var with same name
1451
type ConstantWithCliVar struct{}
1452
1453
// Execute executes a test case and returns an error if occurred
1454
func (h *ConstantWithCliVar) Execute(filePath string) error {
1455
router := httprouter.New()
1456
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1457
_, _ = fmt.Fprint(w, r.URL.Query().Get("p"))
1458
})
1459
ts := httptest.NewTLSServer(router)
1460
defer ts.Close()
1461
1462
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-V", "test=fromcli")
1463
if err != nil {
1464
return err
1465
}
1466
return expectResultsCount(got, 1)
1467
}
1468
1469
type matcherStatusTest struct{}
1470
1471
// Execute executes a test case and returns an error if occurred
1472
func (h *matcherStatusTest) Execute(filePath string) error {
1473
router := httprouter.New()
1474
router.GET("/200", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1475
w.WriteHeader(http.StatusOK)
1476
})
1477
ts := httptest.NewServer(router)
1478
defer ts.Close()
1479
1480
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-ms")
1481
if err != nil {
1482
return err
1483
}
1484
return expectResultsCount(results, 1)
1485
}
1486
1487
// disable path automerge in raw request
1488
type httpDisablePathAutomerge struct{}
1489
1490
// Execute executes a test case and returns an error if occurred
1491
func (h *httpDisablePathAutomerge) Execute(filePath string) error {
1492
router := httprouter.New()
1493
router.GET("/api/v1/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1494
_, _ = fmt.Fprint(w, r.URL.Query().Get("id"))
1495
})
1496
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1497
_, _ = fmt.Fprint(w, "empty path in raw request")
1498
})
1499
1500
ts := httptest.NewServer(router)
1501
defer ts.Close()
1502
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/api/v1/user", debug)
1503
if err != nil {
1504
return err
1505
}
1506
return expectResultsCount(got, 2)
1507
}
1508
1509
type httpInteractshRequestsWithMCAnd struct{}
1510
1511
func (h *httpInteractshRequestsWithMCAnd) Execute(filePath string) error {
1512
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, "honey.scanme.sh", debug)
1513
if err != nil {
1514
return err
1515
}
1516
return expectResultsCount(got, 1)
1517
}
1518
1519
// integration test to check if preprocessor i.e {{randstr}}
1520
// is working correctly
1521
type httpPreprocessor struct{}
1522
1523
// Execute executes a test case and returns an error if occurred
1524
func (h *httpPreprocessor) Execute(filePath string) error {
1525
router := httprouter.New()
1526
re := regexp.MustCompile(`[A-Za-z0-9]{25,}`)
1527
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1528
value := r.URL.RequestURI()
1529
if re.MatchString(value) {
1530
w.WriteHeader(http.StatusOK)
1531
_, _ = fmt.Fprint(w, "ok")
1532
} else {
1533
w.WriteHeader(http.StatusBadRequest)
1534
_, _ = fmt.Fprint(w, "not ok")
1535
}
1536
})
1537
ts := httptest.NewServer(router)
1538
defer ts.Close()
1539
1540
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1541
if err != nil {
1542
return err
1543
}
1544
1545
return expectResultsCount(results, 1)
1546
}
1547
1548
type httpMultiRequest struct{}
1549
1550
// Execute executes a test case and returns an error if occurred
1551
func (h *httpMultiRequest) Execute(filePath string) error {
1552
router := httprouter.New()
1553
router.GET("/ping", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1554
w.WriteHeader(http.StatusOK)
1555
_, _ = fmt.Fprint(w, "ping")
1556
})
1557
router.GET("/pong", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
1558
w.WriteHeader(http.StatusOK)
1559
_, _ = fmt.Fprint(w, "pong")
1560
})
1561
ts := httptest.NewServer(router)
1562
defer ts.Close()
1563
1564
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
1565
if err != nil {
1566
return err
1567
}
1568
1569
return expectResultsCount(results, 1)
1570
}
1571
1572
type httpRawPathSingleSlash struct{}
1573
1574
func (h *httpRawPathSingleSlash) Execute(filepath string) error {
1575
expectedPath := "/index.php"
1576
results, err := testutils.RunNucleiBinaryAndGetCombinedOutput(debug, []string{"-t", filepath, "-u", "scanme.sh/index.php", "-debug-req"})
1577
if err != nil {
1578
return err
1579
}
1580
1581
var actual string
1582
for _, v := range strings.Split(results, "\n") {
1583
if strings.Contains(v, "GET") {
1584
parts := strings.Fields(v)
1585
if len(parts) == 3 {
1586
actual = parts[1]
1587
}
1588
}
1589
}
1590
1591
if actual != expectedPath {
1592
return fmt.Errorf("expected: %v\n\nactual: %v", expectedPath, actual)
1593
}
1594
return nil
1595
}
1596
1597
type httpRawUnsafePathSingleSlash struct{}
1598
1599
func (h *httpRawUnsafePathSingleSlash) Execute(filepath string) error {
1600
expectedPath := "/index.php"
1601
results, err := testutils.RunNucleiBinaryAndGetCombinedOutput(debug, []string{"-t", filepath, "-u", "scanme.sh/index.php", "-debug-req"})
1602
if err != nil {
1603
return err
1604
}
1605
1606
var actual string
1607
for _, v := range strings.Split(results, "\n") {
1608
if strings.Contains(v, "GET") {
1609
parts := strings.Fields(v)
1610
if len(parts) == 3 {
1611
actual = parts[1]
1612
}
1613
}
1614
}
1615
1616
if actual != expectedPath {
1617
return fmt.Errorf("expected: %v\n\nactual: %v", expectedPath, actual)
1618
}
1619
return nil
1620
}
1621
1622