2020-12-26 17:27:40 +00:00
|
|
|
package http
|
2021-02-03 23:18:45 +00:00
|
|
|
|
|
|
|
import (
|
2021-02-04 09:28:34 +00:00
|
|
|
"net/url"
|
2021-02-03 23:18:45 +00:00
|
|
|
"testing"
|
2021-11-05 09:57:49 +00:00
|
|
|
"time"
|
2021-09-03 13:48:39 +00:00
|
|
|
|
2021-07-19 18:04:08 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/model"
|
2021-09-03 13:48:39 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
2021-11-03 21:11:56 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
|
2021-11-05 09:57:49 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
|
2021-11-04 21:31:41 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
2021-11-05 09:57:49 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-02-03 23:18:45 +00:00
|
|
|
)
|
|
|
|
|
2021-02-04 09:28:34 +00:00
|
|
|
func TestBaseURLWithTemplatePrefs(t *testing.T) {
|
2021-02-05 09:13:11 +00:00
|
|
|
baseURL := "http://localhost:53/test"
|
|
|
|
parsed, _ := url.Parse(baseURL)
|
2021-02-04 09:28:34 +00:00
|
|
|
|
2021-02-05 09:13:11 +00:00
|
|
|
data := "{{BaseURL}}:8000/newpath"
|
2021-02-06 22:16:26 +00:00
|
|
|
data, parsed = baseURLWithTemplatePrefs(data, parsed)
|
|
|
|
require.Equal(t, "http://localhost:8000/test", parsed.String(), "could not get correct value")
|
2021-02-05 09:13:11 +00:00
|
|
|
require.Equal(t, "{{BaseURL}}/newpath", data, "could not get correct data")
|
2021-02-04 09:28:34 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 17:10:35 +00:00
|
|
|
func TestVariables(t *testing.T) {
|
|
|
|
baseURL := "http://localhost:9001/test/123"
|
|
|
|
parsed, _ := url.Parse(baseURL)
|
|
|
|
values := generateVariables(parsed, true)
|
|
|
|
|
|
|
|
require.Equal(t, values["BaseURL"], parsed.String(), "incorrect baseurl")
|
2021-08-13 14:38:18 +00:00
|
|
|
require.Equal(t, values["RootURL"], "http://localhost:9001", "incorrect rootURL")
|
|
|
|
require.Equal(t, values["Host"], "localhost", "incorrect domain name")
|
2021-08-30 08:05:11 +00:00
|
|
|
require.Equal(t, values["Path"], "/test", "incorrect path")
|
|
|
|
require.Equal(t, values["File"], "123", "incorrect file")
|
2021-08-12 17:10:35 +00:00
|
|
|
require.Equal(t, values["Port"], "9001", "incorrect port number")
|
2021-08-13 14:38:18 +00:00
|
|
|
require.Equal(t, values["Scheme"], "http", "incorrect scheme")
|
2021-08-12 17:10:35 +00:00
|
|
|
require.Equal(t, values["Hostname"], "localhost:9001", "incorrect hostname")
|
|
|
|
|
|
|
|
baseURL = "https://example.com"
|
|
|
|
parsed, _ = url.Parse(baseURL)
|
|
|
|
values = generateVariables(parsed, false)
|
|
|
|
|
|
|
|
require.Equal(t, values["BaseURL"], parsed.String(), "incorrect baseurl")
|
2021-08-13 14:38:18 +00:00
|
|
|
require.Equal(t, values["Host"], "example.com", "incorrect domain name")
|
|
|
|
require.Equal(t, values["RootURL"], "https://example.com", "incorrect rootURL")
|
2021-08-12 17:10:35 +00:00
|
|
|
require.Equal(t, values["Path"], "", "incorrect path")
|
|
|
|
require.Equal(t, values["Port"], "443", "incorrect port number")
|
2021-08-13 14:38:18 +00:00
|
|
|
require.Equal(t, values["Scheme"], "https", "incorrect scheme")
|
2021-08-12 17:10:35 +00:00
|
|
|
require.Equal(t, values["Hostname"], "example.com", "incorrect hostname")
|
|
|
|
|
|
|
|
baseURL = "ftp://foobar.com/"
|
|
|
|
parsed, _ = url.Parse(baseURL)
|
|
|
|
values = generateVariables(parsed, true)
|
|
|
|
|
|
|
|
require.Equal(t, values["BaseURL"], parsed.String(), "incorrect baseurl")
|
2021-08-13 14:38:18 +00:00
|
|
|
require.Equal(t, values["Host"], "foobar.com", "incorrect domain name")
|
|
|
|
require.Equal(t, values["RootURL"], "ftp://foobar.com", "incorrect rootURL")
|
2021-08-12 17:10:35 +00:00
|
|
|
require.Equal(t, values["Path"], "", "incorrect path")
|
|
|
|
require.Equal(t, values["Port"], "", "incorrect port number") // Unsupported protocol results in a blank port
|
2021-08-13 14:38:18 +00:00
|
|
|
require.Equal(t, values["Scheme"], "ftp", "incorrect scheme")
|
2021-08-12 17:10:35 +00:00
|
|
|
require.Equal(t, values["Hostname"], "foobar.com", "incorrect hostname")
|
|
|
|
}
|
|
|
|
|
2021-02-03 23:18:45 +00:00
|
|
|
func TestMakeRequestFromModal(t *testing.T) {
|
2021-02-04 09:28:34 +00:00
|
|
|
options := testutils.DefaultOptions
|
|
|
|
|
|
|
|
testutils.Init(options)
|
|
|
|
templateID := "testing-http"
|
|
|
|
request := &Request{
|
|
|
|
ID: templateID,
|
|
|
|
Name: "testing",
|
|
|
|
Path: []string{"{{BaseURL}}/login.php"},
|
2021-11-18 13:50:21 +00:00
|
|
|
Method: HTTPMethodTypeHolder{MethodType: HTTPPost},
|
2021-02-04 09:28:34 +00:00
|
|
|
Body: "username=test&password=pass",
|
|
|
|
Headers: map[string]string{
|
|
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
|
|
"Content-Length": "1",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
|
|
|
|
ID: templateID,
|
2021-09-03 13:48:39 +00:00
|
|
|
Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
|
2021-02-04 09:28:34 +00:00
|
|
|
})
|
|
|
|
err := request.Compile(executerOpts)
|
|
|
|
require.Nil(t, err, "could not compile http request")
|
|
|
|
|
|
|
|
generator := request.newGenerator()
|
2021-11-04 11:43:47 +00:00
|
|
|
req, err := generator.Make("https://example.com", map[string]interface{}{})
|
2021-02-04 09:28:34 +00:00
|
|
|
require.Nil(t, err, "could not make http request")
|
2021-02-03 23:18:45 +00:00
|
|
|
|
2021-02-04 09:28:34 +00:00
|
|
|
bodyBytes, _ := req.request.BodyBytes()
|
|
|
|
require.Equal(t, "/login.php", req.request.URL.Path, "could not get correct request path")
|
|
|
|
require.Equal(t, "username=test&password=pass", string(bodyBytes), "could not get correct request body")
|
2021-02-03 23:18:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-04 12:26:53 +00:00
|
|
|
func TestMakeRequestFromModalTrimSuffixSlash(t *testing.T) {
|
|
|
|
options := testutils.DefaultOptions
|
|
|
|
|
|
|
|
testutils.Init(options)
|
|
|
|
templateID := "testing-http"
|
|
|
|
request := &Request{
|
|
|
|
ID: templateID,
|
|
|
|
Name: "testing",
|
|
|
|
Path: []string{"{{BaseURL}}?query=example"},
|
2021-11-18 13:50:21 +00:00
|
|
|
Method: HTTPMethodTypeHolder{MethodType: HTTPGet},
|
2021-02-04 12:26:53 +00:00
|
|
|
}
|
|
|
|
executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
|
|
|
|
ID: templateID,
|
2021-09-03 13:48:39 +00:00
|
|
|
Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
|
2021-02-04 12:26:53 +00:00
|
|
|
})
|
|
|
|
err := request.Compile(executerOpts)
|
|
|
|
require.Nil(t, err, "could not compile http request")
|
|
|
|
|
|
|
|
generator := request.newGenerator()
|
2021-11-04 11:43:47 +00:00
|
|
|
req, err := generator.Make("https://example.com/test.php", map[string]interface{}{})
|
2021-02-04 12:26:53 +00:00
|
|
|
require.Nil(t, err, "could not make http request")
|
|
|
|
require.Equal(t, "https://example.com/test.php?query=example", req.request.URL.String(), "could not get correct request path")
|
|
|
|
|
|
|
|
generator = request.newGenerator()
|
2021-11-04 11:43:47 +00:00
|
|
|
req, err = generator.Make("https://example.com/test/", map[string]interface{}{})
|
2021-02-04 12:26:53 +00:00
|
|
|
require.Nil(t, err, "could not make http request")
|
|
|
|
require.Equal(t, "https://example.com/test/?query=example", req.request.URL.String(), "could not get correct request path")
|
|
|
|
}
|
|
|
|
|
2021-02-04 09:28:34 +00:00
|
|
|
func TestMakeRequestFromRawWithPayloads(t *testing.T) {
|
2021-02-03 23:18:45 +00:00
|
|
|
options := testutils.DefaultOptions
|
|
|
|
|
|
|
|
testutils.Init(options)
|
|
|
|
templateID := "testing-http"
|
|
|
|
request := &Request{
|
|
|
|
ID: templateID,
|
|
|
|
Name: "testing",
|
|
|
|
Payloads: map[string]interface{}{
|
|
|
|
"username": []string{"admin"},
|
|
|
|
"password": []string{"admin", "guest", "password", "test", "12345", "123456"},
|
|
|
|
},
|
2021-11-03 21:14:47 +00:00
|
|
|
AttackType: generators.AttackTypeHolder{Value: generators.ClusterbombAttack},
|
2021-02-03 23:18:45 +00:00
|
|
|
Raw: []string{`GET /manager/html HTTP/1.1
|
|
|
|
Host: {{Hostname}}
|
2021-02-04 09:28:34 +00:00
|
|
|
User-Agent: Nuclei - Open-source project (github.com/projectdiscovery/nuclei)
|
|
|
|
Connection: close
|
|
|
|
Authorization: Basic {{username + ':' + password}}
|
|
|
|
Accept-Encoding: gzip`},
|
2021-02-03 23:18:45 +00:00
|
|
|
}
|
|
|
|
executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
|
|
|
|
ID: templateID,
|
2021-09-03 13:48:39 +00:00
|
|
|
Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
|
2021-02-03 23:18:45 +00:00
|
|
|
})
|
|
|
|
err := request.Compile(executerOpts)
|
|
|
|
require.Nil(t, err, "could not compile http request")
|
|
|
|
|
|
|
|
generator := request.newGenerator()
|
2021-11-04 11:43:47 +00:00
|
|
|
req, err := generator.Make("https://example.com", map[string]interface{}{})
|
2021-02-03 23:18:45 +00:00
|
|
|
require.Nil(t, err, "could not make http request")
|
2021-02-04 09:28:34 +00:00
|
|
|
authorization := req.request.Header.Get("Authorization")
|
|
|
|
require.Equal(t, "Basic admin:admin", authorization, "could not get correct authorization headers from raw")
|
2021-02-03 23:18:45 +00:00
|
|
|
|
2021-11-04 11:43:47 +00:00
|
|
|
req, err = generator.Make("https://example.com", map[string]interface{}{})
|
2021-02-04 09:28:34 +00:00
|
|
|
require.Nil(t, err, "could not make http request")
|
|
|
|
authorization = req.request.Header.Get("Authorization")
|
|
|
|
require.Equal(t, "Basic admin:guest", authorization, "could not get correct authorization headers from raw")
|
2021-02-03 23:18:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-04 09:28:34 +00:00
|
|
|
func TestMakeRequestFromRawPayloadExpressions(t *testing.T) {
|
|
|
|
options := testutils.DefaultOptions
|
|
|
|
|
|
|
|
testutils.Init(options)
|
|
|
|
templateID := "testing-http"
|
|
|
|
request := &Request{
|
|
|
|
ID: templateID,
|
|
|
|
Name: "testing",
|
2021-02-03 23:18:45 +00:00
|
|
|
Payloads: map[string]interface{}{
|
2021-02-04 09:28:34 +00:00
|
|
|
"username": []string{"admin"},
|
|
|
|
"password": []string{"admin", "guest", "password", "test", "12345", "123456"},
|
2021-02-03 23:18:45 +00:00
|
|
|
},
|
2021-11-03 21:14:47 +00:00
|
|
|
AttackType: generators.AttackTypeHolder{Value: generators.ClusterbombAttack},
|
2021-02-04 09:28:34 +00:00
|
|
|
Raw: []string{`GET /manager/html HTTP/1.1
|
|
|
|
Host: {{Hostname}}
|
|
|
|
User-Agent: Nuclei - Open-source project (github.com/projectdiscovery/nuclei)
|
|
|
|
Connection: close
|
|
|
|
Authorization: Basic {{base64(username + ':' + password)}}
|
|
|
|
Accept-Encoding: gzip`},
|
2021-02-03 23:18:45 +00:00
|
|
|
}
|
2021-02-04 09:28:34 +00:00
|
|
|
executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
|
|
|
|
ID: templateID,
|
2021-09-03 13:48:39 +00:00
|
|
|
Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
|
2021-02-04 09:28:34 +00:00
|
|
|
})
|
|
|
|
err := request.Compile(executerOpts)
|
|
|
|
require.Nil(t, err, "could not compile http request")
|
|
|
|
|
|
|
|
generator := request.newGenerator()
|
2021-11-04 11:43:47 +00:00
|
|
|
req, err := generator.Make("https://example.com", map[string]interface{}{})
|
2021-02-04 09:28:34 +00:00
|
|
|
require.Nil(t, err, "could not make http request")
|
|
|
|
authorization := req.request.Header.Get("Authorization")
|
|
|
|
require.Equal(t, "Basic YWRtaW46YWRtaW4=", authorization, "could not get correct authorization headers from raw")
|
|
|
|
|
2021-11-04 11:43:47 +00:00
|
|
|
req, err = generator.Make("https://example.com", map[string]interface{}{})
|
2021-02-04 09:28:34 +00:00
|
|
|
require.Nil(t, err, "could not make http request")
|
|
|
|
authorization = req.request.Header.Get("Authorization")
|
|
|
|
require.Equal(t, "Basic YWRtaW46Z3Vlc3Q=", authorization, "could not get correct authorization headers from raw")
|
2021-02-03 23:18:45 +00:00
|
|
|
}
|
2021-11-05 09:57:49 +00:00
|
|
|
|
|
|
|
func TestMakeRequestFromModelUniqueInteractsh(t *testing.T) {
|
|
|
|
|
|
|
|
options := testutils.DefaultOptions
|
|
|
|
|
|
|
|
testutils.Init(options)
|
|
|
|
templateID := "testing-unique-interactsh"
|
|
|
|
request := &Request{
|
|
|
|
ID: templateID,
|
|
|
|
Name: "testing",
|
|
|
|
Path: []string{"{{BaseURL}}/?u=http://{{interactsh-url}}/&href=http://{{interactsh-url}}/&action=http://{{interactsh-url}}/&host={{interactsh-url}}"},
|
2021-11-18 13:50:21 +00:00
|
|
|
Method: HTTPMethodTypeHolder{MethodType: HTTPGet},
|
2021-11-05 09:57:49 +00:00
|
|
|
}
|
|
|
|
executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{
|
|
|
|
ID: templateID,
|
|
|
|
Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},
|
|
|
|
})
|
|
|
|
err := request.Compile(executerOpts)
|
|
|
|
require.Nil(t, err, "could not compile http request")
|
|
|
|
|
|
|
|
generator := request.newGenerator()
|
|
|
|
|
|
|
|
generator.options.Interactsh, err = interactsh.New(&interactsh.Options{
|
|
|
|
ServerURL: options.InteractshURL,
|
|
|
|
CacheSize: int64(options.InteractionsCacheSize),
|
|
|
|
Eviction: time.Duration(options.InteractionsEviction) * time.Second,
|
|
|
|
ColldownPeriod: time.Duration(options.InteractionsCooldownPeriod) * time.Second,
|
|
|
|
PollDuration: time.Duration(options.InteractionsPollDuration) * time.Second,
|
|
|
|
})
|
|
|
|
require.Nil(t, err, "could not create interactsh client")
|
|
|
|
|
|
|
|
got, err := generator.Make("https://example.com", map[string]interface{}{})
|
|
|
|
require.Nil(t, err, "could not make http request")
|
|
|
|
|
2021-11-05 14:30:46 +00:00
|
|
|
// check if all the interactsh markers are replaced with unique urls
|
2021-11-05 09:57:49 +00:00
|
|
|
require.NotContains(t, got.request.URL.String(), "{{interactsh-url}}", "could not get correct interactsh url")
|
2021-11-05 14:30:46 +00:00
|
|
|
// check the length of returned urls
|
2021-11-05 09:57:49 +00:00
|
|
|
require.Equal(t, len(got.interactshURLs), 4, "could not get correct interactsh url")
|
2021-11-05 14:30:46 +00:00
|
|
|
// check if the interactsh urls are unique
|
|
|
|
require.True(t, areUnique(got.interactshURLs), "interactsh urls are not unique")
|
|
|
|
}
|
|
|
|
|
|
|
|
// areUnique checks if the elements of string slice are unique
|
|
|
|
func areUnique(elements []string) bool {
|
|
|
|
encountered := map[string]bool{}
|
|
|
|
for v := range elements {
|
|
|
|
if encountered[elements[v]] {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
encountered[elements[v]] = true
|
|
|
|
}
|
|
|
|
return true
|
2021-11-05 09:57:49 +00:00
|
|
|
}
|