2021-12-04 18:40:11 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2025-02-10 21:46:35 +07:00
|
|
|
"fmt"
|
2023-01-05 12:56:18 +01:00
|
|
|
"io"
|
2021-12-04 18:40:11 +01:00
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
|
|
|
|
|
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
|
|
2023-10-17 17:44:13 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
2021-12-04 18:40:11 +01:00
|
|
|
)
|
|
|
|
|
|
2023-07-28 18:50:57 +03:00
|
|
|
var headlessTestcases = []TestCaseInfo{
|
2023-08-04 20:21:22 +05:30
|
|
|
{Path: "protocols/headless/headless-basic.yaml", TestCase: &headlessBasic{}},
|
2023-12-06 19:08:26 +05:30
|
|
|
{Path: "protocols/headless/headless-waitevent.yaml", TestCase: &headlessBasic{}},
|
2025-02-10 21:46:35 +07:00
|
|
|
{Path: "protocols/headless/headless-dsl.yaml", TestCase: &headlessBasic{}},
|
2023-11-02 16:38:20 +03:00
|
|
|
{Path: "protocols/headless/headless-self-contained.yaml", TestCase: &headlessSelfContained{}},
|
2023-08-04 20:21:22 +05:30
|
|
|
{Path: "protocols/headless/headless-header-action.yaml", TestCase: &headlessHeaderActions{}},
|
|
|
|
|
{Path: "protocols/headless/headless-extract-values.yaml", TestCase: &headlessExtractValues{}},
|
|
|
|
|
{Path: "protocols/headless/headless-payloads.yaml", TestCase: &headlessPayloads{}},
|
|
|
|
|
{Path: "protocols/headless/variables.yaml", TestCase: &headlessVariables{}},
|
2023-09-13 20:28:48 +05:30
|
|
|
{Path: "protocols/headless/headless-local.yaml", TestCase: &headlessLocal{}},
|
2023-08-04 20:21:22 +05:30
|
|
|
{Path: "protocols/headless/file-upload.yaml", TestCase: &headlessFileUpload{}},
|
2023-09-13 20:28:48 +05:30
|
|
|
{Path: "protocols/headless/file-upload-negative.yaml", TestCase: &headlessFileUploadNegative{}},
|
2023-08-04 20:21:22 +05:30
|
|
|
{Path: "protocols/headless/headless-header-status-test.yaml", TestCase: &headlessHeaderStatus{}},
|
2021-12-04 18:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type headlessBasic struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessBasic) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2025-02-10 21:46:35 +07:00
|
|
|
_, _ = fmt.Fprintf(w, "<html><body>%s</body></html>", r.URL.Query().Get("_"))
|
2021-12-04 18:40:11 +01:00
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-12-15 16:03:57 +02:00
|
|
|
|
|
|
|
|
return expectResultsCount(results, 1)
|
2021-12-04 18:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
2023-11-02 16:38:20 +03:00
|
|
|
type headlessSelfContained struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessSelfContained) Execute(filePath string) error {
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-headless", "-var query=selfcontained")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return expectResultsCount(results, 1)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-25 18:30:46 +05:30
|
|
|
type headlessLocal struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
// in this testcases local network access is disabled
|
|
|
|
|
func (h *headlessLocal) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
_, _ = w.Write([]byte("<html><body></body></html>"))
|
|
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
|
|
args := []string{"-t", filePath, "-u", ts.URL, "-headless", "-lna"}
|
|
|
|
|
|
|
|
|
|
results, err := testutils.RunNucleiWithArgsAndGetResults(debug, args...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return expectResultsCount(results, 0)
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-04 18:40:11 +01:00
|
|
|
type headlessHeaderActions struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessHeaderActions) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
testValue := r.Header.Get("test")
|
|
|
|
|
if r.Header.Get("test") != "" {
|
|
|
|
|
_, _ = w.Write([]byte("<html><body>" + testValue + "</body></html>"))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-12-15 16:03:57 +02:00
|
|
|
|
|
|
|
|
return expectResultsCount(results, 1)
|
2021-12-04 18:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type headlessExtractValues struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessExtractValues) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
_, _ = w.Write([]byte("<html><body><a href='/test.html'>test</a></body></html>"))
|
|
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-12-15 16:03:57 +02:00
|
|
|
|
2024-01-12 23:10:00 +05:30
|
|
|
return expectResultsCount(results, 1)
|
2021-12-04 18:40:11 +01:00
|
|
|
}
|
2022-02-04 11:43:42 +01:00
|
|
|
|
|
|
|
|
type headlessPayloads struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessPayloads) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
_, _ = w.Write([]byte("<html><body>test</body></html>"))
|
|
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-04 11:51:29 +01:00
|
|
|
return expectResultsCount(results, 4)
|
2022-02-04 11:43:42 +01:00
|
|
|
}
|
2022-04-02 02:14:00 +05:30
|
|
|
|
|
|
|
|
type headlessVariables struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessVariables) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
2022-04-20 15:36:02 +05:30
|
|
|
_, _ = w.Write([]byte("<html><body>aGVsbG8=</body></html>"))
|
2022-04-02 02:14:00 +05:30
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return expectResultsCount(results, 1)
|
|
|
|
|
}
|
2023-01-05 12:56:18 +01:00
|
|
|
|
|
|
|
|
type headlessFileUpload struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessFileUpload) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
_, _ = w.Write([]byte(`
|
|
|
|
|
<!doctype html>
|
|
|
|
|
<body>
|
|
|
|
|
<form method=post enctype=multipart/form-data>
|
|
|
|
|
<input type=file name=file>
|
|
|
|
|
<input type=submit value=Upload>
|
|
|
|
|
</form>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`))
|
|
|
|
|
})
|
|
|
|
|
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
file, _, err := r.FormFile("file")
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-01 00:40:44 +07:00
|
|
|
defer func() {
|
2025-07-09 14:47:26 -05:00
|
|
|
_ = file.Close()
|
|
|
|
|
}()
|
2023-01-05 12:56:18 +01:00
|
|
|
|
|
|
|
|
content, err := io.ReadAll(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, _ = w.Write(content)
|
|
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return expectResultsCount(results, 1)
|
|
|
|
|
}
|
2023-06-09 19:52:56 +05:30
|
|
|
|
|
|
|
|
type headlessHeaderStatus struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessHeaderStatus) Execute(filePath string) error {
|
|
|
|
|
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "https://scanme.sh", debug, "-headless")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return expectResultsCount(results, 1)
|
|
|
|
|
}
|
2023-08-25 18:30:46 +05:30
|
|
|
|
|
|
|
|
type headlessFileUploadNegative struct{}
|
|
|
|
|
|
|
|
|
|
// Execute executes a test case and returns an error if occurred
|
|
|
|
|
func (h *headlessFileUploadNegative) Execute(filePath string) error {
|
|
|
|
|
router := httprouter.New()
|
|
|
|
|
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
_, _ = w.Write([]byte(`
|
|
|
|
|
<!doctype html>
|
|
|
|
|
<body>
|
|
|
|
|
<form method=post enctype=multipart/form-data>
|
|
|
|
|
<input type=file name=file>
|
|
|
|
|
<input type=submit value=Upload>
|
|
|
|
|
</form>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`))
|
|
|
|
|
})
|
|
|
|
|
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
|
file, _, err := r.FormFile("file")
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-01 00:40:44 +07:00
|
|
|
defer func() {
|
2025-07-09 14:47:26 -05:00
|
|
|
_ = file.Close()
|
|
|
|
|
}()
|
2023-08-25 18:30:46 +05:30
|
|
|
|
|
|
|
|
content, err := io.ReadAll(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, _ = w.Write(content)
|
|
|
|
|
})
|
|
|
|
|
ts := httptest.NewServer(router)
|
|
|
|
|
defer ts.Close()
|
|
|
|
|
args := []string{"-t", filePath, "-u", ts.URL, "-headless"}
|
|
|
|
|
|
|
|
|
|
results, err := testutils.RunNucleiWithArgsAndGetResults(debug, args...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return expectResultsCount(results, 0)
|
|
|
|
|
}
|