From 75115d568933b7e26e9492500087d48bc104d899 Mon Sep 17 00:00:00 2001 From: Emmanuel Gautier Date: Sun, 22 Dec 2024 12:22:33 +0100 Subject: [PATCH] feat: discover well known paths and leaked files --- .github/workflows/scans.yml | 2 +- README.md | 13 +- .../cmd/printtable/wellknown_paths_table.go | 52 +- .../jwt/weak_secret/weak_secret.go | 3 +- .../discoverable_graphql.go | 14 +- .../discoverable_openapi.go | 13 +- scan/discover/exposed_files/exposed_files.go | 38 + .../exposed_files/exposed_files_test.go | 50 + scan/discover/utils.go | 30 +- scan/discover/utils_test.go | 66 +- scan/discover/well-known/well_known.go | 38 + scan/discover/well-known/well_known_test.go | 50 + scenario/discover_api.go | 4 + seclist/lists/exposed-paths.txt | 1067 +++++++++++++++++ ...craped-JWT-secrets.txt => jwt-secrets.txt} | 0 seclist/lists/well-known.txt | 6 + seclist/seclist.go | 15 +- 17 files changed, 1360 insertions(+), 101 deletions(-) create mode 100644 scan/discover/exposed_files/exposed_files.go create mode 100644 scan/discover/exposed_files/exposed_files_test.go create mode 100644 scan/discover/well-known/well_known.go create mode 100644 scan/discover/well-known/well_known_test.go create mode 100644 seclist/lists/exposed-paths.txt rename seclist/lists/{scraped-JWT-secrets.txt => jwt-secrets.txt} (100%) create mode 100644 seclist/lists/well-known.txt diff --git a/.github/workflows/scans.yml b/.github/workflows/scans.yml index 8d6d3a98..f8f6c2ed 100644 --- a/.github/workflows/scans.yml +++ b/.github/workflows/scans.yml @@ -45,7 +45,7 @@ jobs: - name: VulnAPI id: vulnapi run: | - go run main.go discover api http://localhost:8080 --sqa-opt-out + go run main.go discover api http://localhost:8080 --rate-limit 500 --sqa-opt-out - name: Stop Server if: ${{ always() }} diff --git a/README.md b/README.md index 29888e53..8f7cabfe 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The Vulnerability Scanner CLI offers two methods for scanning APIs: ### Discover Command -To discover target API useful information, execute the following command: +To discover target API useful information, leaked files and well-known path execute the following command: ```bash vulnapi discover api [API_URL] @@ -41,11 +41,12 @@ vulnapi discover api [API_URL] Example output: ```bash -| WELL-KNOWN PATHS | URL | -|------------------|------------------------------------| -| OpenAPI | http://localhost:5000/openapi.json | -| GraphQL | N/A | - +| TYPE | URL | +|---------------|---------------------------------------------| +| OpenAPI | http://localhost:5000/openapi.json | +| GraphQL | http://localhost:5000/graphql | +| Well-Known | http://localhost:8080/.well-known/jwks.json | +| Exposed Files | http://localhost:8080/.env.dev | | TECHNOLOGIE/SERVICE | VALUE | |---------------------|---------------| diff --git a/internal/cmd/printtable/wellknown_paths_table.go b/internal/cmd/printtable/wellknown_paths_table.go index b7bdc12e..6eb6c798 100644 --- a/internal/cmd/printtable/wellknown_paths_table.go +++ b/internal/cmd/printtable/wellknown_paths_table.go @@ -4,47 +4,57 @@ import ( "fmt" "github.com/cerberauth/vulnapi/report" + "github.com/cerberauth/vulnapi/scan/discover" discoverablegraphql "github.com/cerberauth/vulnapi/scan/discover/discoverable_graphql" discoverableopenapi "github.com/cerberauth/vulnapi/scan/discover/discoverable_openapi" + exposedfiles "github.com/cerberauth/vulnapi/scan/discover/exposed_files" + wellknown "github.com/cerberauth/vulnapi/scan/discover/well-known" "github.com/olekukonko/tablewriter" ) +func wellKnownPathsFromReport(r *report.ScanReport, header string) [][]string { + rows := [][]string{} + if r == nil || !r.HasData() { + return rows + } + + data, ok := r.Data.(discover.DiscoverData) + if ok && len(data) > 0 { + rows = append(rows, []string{header, data[0].URL}) + } + + return rows +} + func WellKnownPathsScanReport(reporter *report.Reporter) { - openapiURL := "" + rows := [][]string{} + openapiReport := reporter.GetScanReportByID(discoverableopenapi.DiscoverableOpenAPIScanID) - if openapiReport != nil && openapiReport.HasData() { - openapiData, ok := openapiReport.Data.(discoverableopenapi.DiscoverableOpenAPIData) - if ok { - openapiURL = openapiData.URL - } - } + rows = append(rows, wellKnownPathsFromReport(openapiReport, "OpenAPI")...) - graphqlURL := "" graphqlReport := reporter.GetScanReportByID(discoverablegraphql.DiscoverableGraphQLPathScanID) - if graphqlReport != nil && graphqlReport.HasData() { - graphqlData, ok := graphqlReport.Data.(discoverablegraphql.DiscoverableGraphQLPathData) - if ok { - graphqlURL = graphqlData.URL - } - } + rows = append(rows, wellKnownPathsFromReport(graphqlReport, "GraphQL")...) - if openapiURL == "" && graphqlURL == "" { + wellKnownReport := reporter.GetScanReportByID(wellknown.DiscoverableWellKnownScanID) + rows = append(rows, wellKnownPathsFromReport(wellKnownReport, "Well-Known")...) + + exposedFiles := reporter.GetScanReportByID(exposedfiles.DiscoverableFilesScanID) + rows = append(rows, wellKnownPathsFromReport(exposedFiles, "Exposed Files")...) + + if len(rows) == 0 { return } fmt.Println() - headers := []string{"Well-Known Paths", "URL"} + headers := []string{"Type", "URL"} table := CreateTable(headers) tableColors := make([]tablewriter.Colors, len(headers)) tableColors[0] = tablewriter.Colors{tablewriter.Bold} tableColors[1] = tablewriter.Colors{tablewriter.Bold} - if openapiURL != "" { - table.Rich([]string{"OpenAPI", openapiURL}, tableColors) - } - if graphqlURL != "" { - table.Rich([]string{"GraphQL", graphqlURL}, tableColors) + for _, row := range rows { + table.Rich(row, tableColors) } table.Render() diff --git a/scan/broken_authentication/jwt/weak_secret/weak_secret.go b/scan/broken_authentication/jwt/weak_secret/weak_secret.go index 18d3f31f..88966431 100644 --- a/scan/broken_authentication/jwt/weak_secret/weak_secret.go +++ b/scan/broken_authentication/jwt/weak_secret/weak_secret.go @@ -49,7 +49,8 @@ func ShouldBeScanned(securityScheme *auth.SecurityScheme) bool { var defaultJwtSecretDictionary = []string{"secret", "password", "123456", "changeme", "admin", "token"} -const jwtSecretDictionarySeclistUrl = "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/scraped-JWT-secrets.txt" +// From https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/scraped-JWT-secrets.txt +const jwtSecretDictionarySeclistUrl = "https://raw.githubusercontent.com/cerberauth/vulnapi/main/seclist/lists/jwt-secrets.txt" func ScanHandler(op *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { vulnReport := report.NewIssueReport(issue).WithOperation(op).WithSecurityScheme(securityScheme) diff --git a/scan/discover/discoverable_graphql/discoverable_graphql.go b/scan/discover/discoverable_graphql/discoverable_graphql.go index 7eeedcdc..538e416d 100644 --- a/scan/discover/discoverable_graphql/discoverable_graphql.go +++ b/scan/discover/discoverable_graphql/discoverable_graphql.go @@ -29,20 +29,10 @@ var issue = report.Issue{ }, } -var graphqlSeclistUrl = "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/graphql.txt" -var potentialGraphQLEndpoints = []string{ - "/graphql", - "/graph", - "/api/graphql", - "/graphql/console", - "/v1/graphql", - "/v1/graphiql", -} +var graphqlSeclistUrl = "https://raw.githubusercontent.com/cerberauth/vulnapi/main/seclist/lists/graphql.txt" func ScanHandler(op *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { vulnReport := report.NewIssueReport(issue).WithOperation(op).WithSecurityScheme(securityScheme) r := report.NewScanReport(DiscoverableGraphQLPathScanID, DiscoverableGraphQLPathScanName, op) - handler := discover.CreateURLScanHandler("GraphQL", graphqlSeclistUrl, potentialGraphQLEndpoints, r, vulnReport) - - return handler(op, securityScheme) + return discover.DownloadAndScanURLs("GraphQL", graphqlSeclistUrl, r, vulnReport, op, securityScheme) } diff --git a/scan/discover/discoverable_openapi/discoverable_openapi.go b/scan/discover/discoverable_openapi/discoverable_openapi.go index d1c829fa..735fadc2 100644 --- a/scan/discover/discoverable_openapi/discoverable_openapi.go +++ b/scan/discover/discoverable_openapi/discoverable_openapi.go @@ -29,19 +29,10 @@ var issue = report.Issue{ }, } -var openapiSeclistUrl = "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/swagger.txt" -var potentialOpenAPIPaths = []string{ - "/openapi", - "/api-docs.json", - "/api-docs.yaml", - "/api-docs.yml", - "/.well-known/openapi.yml", -} +var openapiSeclistUrl = "https://raw.githubusercontent.com/cerberauth/vulnapi/main/seclist/lists/swagger.txt" func ScanHandler(op *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { vulnReport := report.NewIssueReport(issue).WithOperation(op).WithSecurityScheme(securityScheme) r := report.NewScanReport(DiscoverableOpenAPIScanID, DiscoverableOpenAPIScanName, op) - handler := discover.CreateURLScanHandler("OpenAPI", openapiSeclistUrl, potentialOpenAPIPaths, r, vulnReport) - - return handler(op, securityScheme) + return discover.DownloadAndScanURLs("OpenAPI", openapiSeclistUrl, r, vulnReport, op, securityScheme) } diff --git a/scan/discover/exposed_files/exposed_files.go b/scan/discover/exposed_files/exposed_files.go new file mode 100644 index 00000000..5941b3b4 --- /dev/null +++ b/scan/discover/exposed_files/exposed_files.go @@ -0,0 +1,38 @@ +package exposedfiles + +import ( + "github.com/cerberauth/vulnapi/internal/auth" + "github.com/cerberauth/vulnapi/internal/operation" + "github.com/cerberauth/vulnapi/report" + "github.com/cerberauth/vulnapi/scan/discover" +) + +const ( + DiscoverableFilesScanID = "discover.exposed_files" + DiscoverableFilesScanName = "Discoverable exposed files" +) + +type DiscoverableFilesData = discover.DiscoverData + +var issue = report.Issue{ + ID: "discover.exposed_files", + Name: "Discoverable exposed files", + + Classifications: &report.Classifications{ + OWASP: report.OWASP_2023_SSRF, + }, + + CVSS: report.CVSS{ + Version: 4.0, + Vector: "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:N/SA:N", + Score: 0, + }, +} + +var discoverableFilesSeclistUrl = "https://raw.githubusercontent.com/cerberauth/vulnapi/main/seclist/lists/exposed-paths.txt" + +func ScanHandler(op *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { + vulnReport := report.NewIssueReport(issue).WithOperation(op).WithSecurityScheme(securityScheme) + r := report.NewScanReport(DiscoverableFilesScanID, DiscoverableFilesScanName, op) + return discover.DownloadAndScanURLs("Exposed Files", discoverableFilesSeclistUrl, r, vulnReport, op, securityScheme) +} diff --git a/scan/discover/exposed_files/exposed_files_test.go b/scan/discover/exposed_files/exposed_files_test.go new file mode 100644 index 00000000..4d59c69d --- /dev/null +++ b/scan/discover/exposed_files/exposed_files_test.go @@ -0,0 +1,50 @@ +package exposedfiles_test + +import ( + "net/http" + "testing" + + "github.com/cerberauth/vulnapi/internal/auth" + "github.com/cerberauth/vulnapi/internal/operation" + "github.com/cerberauth/vulnapi/internal/request" + exposedfiles "github.com/cerberauth/vulnapi/scan/discover/exposed_files" + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDiscoverableScanner_Passed_WhenNoDiscoverableGraphqlPathFound(t *testing.T) { + client := request.NewClient(request.NewClientOptions{ + RateLimit: 500, + }) + httpmock.ActivateNonDefault(client.Client) + defer httpmock.DeactivateAndReset() + + op := operation.MustNewOperation(http.MethodGet, "http://localhost:8080/", nil, client) + httpmock.RegisterResponder(op.Method, op.URL.String(), httpmock.NewBytesResponder(http.StatusNoContent, nil)) + httpmock.RegisterNoResponder(httpmock.NewBytesResponder(http.StatusNotFound, nil)) + + report, err := exposedfiles.ScanHandler(op, auth.MustNewNoAuthSecurityScheme()) + + require.NoError(t, err) + assert.Greater(t, httpmock.GetTotalCallCount(), 7) + assert.True(t, report.Issues[0].HasPassed()) +} + +func TestDiscoverableScanner_Failed_WhenOneGraphQLPathFound(t *testing.T) { + client := request.NewClient(request.NewClientOptions{ + RateLimit: 500, + }) + httpmock.ActivateNonDefault(client.Client) + defer httpmock.DeactivateAndReset() + + operation := operation.MustNewOperation(http.MethodGet, "http://localhost:8080/.aws/credentials", nil, client) + httpmock.RegisterResponder(operation.Method, operation.URL.String(), httpmock.NewBytesResponder(http.StatusOK, nil)) + httpmock.RegisterNoResponder(httpmock.NewBytesResponder(http.StatusNotFound, nil)) + + report, err := exposedfiles.ScanHandler(operation, auth.MustNewNoAuthSecurityScheme()) + + require.NoError(t, err) + assert.Greater(t, httpmock.GetTotalCallCount(), 0) + assert.True(t, report.Issues[0].HasFailed()) +} diff --git a/scan/discover/utils.go b/scan/discover/utils.go index 20030165..d10f6d50 100644 --- a/scan/discover/utils.go +++ b/scan/discover/utils.go @@ -1,6 +1,7 @@ package discover import ( + "log" "net/http" "net/url" @@ -11,7 +12,7 @@ import ( "github.com/cerberauth/vulnapi/seclist" ) -type DiscoverData struct { +type DiscoverData []struct { URL string } @@ -56,32 +57,35 @@ func ScanURLs(scanUrls []string, op *operation.Operation, securityScheme *auth.S }(chunk) } + data := DiscoverData{} for i := 0; i < len(scanUrls); i++ { select { case attempt := <-results: r.AddScanAttempt(attempt) if attempt.Response.GetStatusCode() == http.StatusOK { // TODO: check if the response contains the expected content - r.WithData(DiscoverData{ - URL: attempt.Request.GetURL(), - }).AddIssueReport(vulnReport.Fail()).End() - return r, nil + data = append(data, struct{ URL string }{URL: attempt.Request.GetURL()}) } case err := <-errors: - return r, err + log.Printf("Error scanning URL: %v", err) + continue } } + if len(data) > 0 { + r.WithData(data).AddIssueReport(vulnReport.Fail()).End() + return r, nil + } + r.AddIssueReport(vulnReport.Pass()).End() return r, nil } -func CreateURLScanHandler(name string, seclistUrl string, defaultUrls []string, r *report.ScanReport, vulnReport *report.IssueReport) func(operation *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { - scanUrls := defaultUrls - if urlsFromSeclist, err := seclist.NewSecListFromURL(name, seclistUrl); err == nil && urlsFromSeclist != nil { - scanUrls = urlsFromSeclist.Items +func DownloadAndScanURLs(name string, seclistUrl string, r *report.ScanReport, vulnReport *report.IssueReport, op *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { + urlsFromSeclist, err := seclist.NewSecListFromURL(name, seclistUrl) + if err != nil { + return nil, err } + scanUrls := urlsFromSeclist.Items - return func(op *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { - return ScanURLs(scanUrls, op, securityScheme, r, vulnReport) - } + return ScanURLs(scanUrls, op, securityScheme, r, vulnReport) } diff --git a/scan/discover/utils_test.go b/scan/discover/utils_test.go index acb88d2a..6de1fafb 100644 --- a/scan/discover/utils_test.go +++ b/scan/discover/utils_test.go @@ -25,8 +25,8 @@ func TestExtractBaseURL(t *testing.T) { expected: "https://example.com", }, { - inputURL: "http://localhost:8080", - expected: "http://localhost:8080", + inputURL: "http://localhost:1234", + expected: "http://localhost:1234", }, } @@ -42,75 +42,77 @@ func TestExtractBaseURL(t *testing.T) { } } -func TestCreateURLScanHandler_WithTimeout(t *testing.T) { +func TestDownloadAndScanURLs_Failed_WhenNotFoundSeclist(t *testing.T) { client := request.GetDefaultClient() httpmock.ActivateNonDefault(client.Client) - defer httpmock.DeactivateAndReset() + t.Cleanup(httpmock.DeactivateAndReset) - seclistUrl := "http://localhost:8080/seclist" - defaultUrls := []string{"/path1", "/path2"} + seclistUrl := "http://localhost:1234/not_found_seclist" securitySchemes := []*auth.SecurityScheme{auth.MustNewNoAuthSecurityScheme()} - operation := operation.MustNewOperation(http.MethodGet, "http://localhost:8080", nil, client) + operation := operation.MustNewOperation(http.MethodGet, "http://localhost:1234", nil, client) operation.SetSecuritySchemes(securitySchemes) r := report.NewScanReport("test", "test", operation) vulnReport := &report.IssueReport{} - handler := discover.CreateURLScanHandler("test", seclistUrl, defaultUrls, r, vulnReport) - + httpmock.RegisterResponder(http.MethodGet, seclistUrl, httpmock.NewBytesResponder(http.StatusNotFound, nil)) httpmock.RegisterResponder(operation.Method, operation.URL.String(), httpmock.NewBytesResponder(http.StatusNoContent, nil)) - _, err := handler(operation, securitySchemes[0]) + _, err := discover.DownloadAndScanURLs("test", seclistUrl, r, vulnReport, operation, securitySchemes[0]) assert.Error(t, err) - assert.EqualError(t, err, "request has an unexpected error") + assert.EqualError(t, err, "sec list download failed") } -func TestCreateURLScanHandler_Passed_WhenNotFoundURLs(t *testing.T) { +func TestDownloadAndScanURLs_Passed_WhenNotFoundURLs(t *testing.T) { client := request.GetDefaultClient() httpmock.ActivateNonDefault(client.Client) - defer httpmock.DeactivateAndReset() + t.Cleanup(httpmock.DeactivateAndReset) - seclistUrl := "http://localhost:8080/seclist" - defaultUrls := []string{"/path1", "/path2"} + seclistUrl := "http://localhost:1234/passed_seclist" securitySchemes := []*auth.SecurityScheme{auth.MustNewNoAuthSecurityScheme()} - operation := operation.MustNewOperation(http.MethodGet, "http://localhost:8080", nil, client) + operation := operation.MustNewOperation(http.MethodGet, "http://localhost:1234", nil, client) operation.SetSecuritySchemes(securitySchemes) r := report.NewScanReport("test", "test", operation) vulnReport := &report.IssueReport{} - handler := discover.CreateURLScanHandler("test", seclistUrl, defaultUrls, r, vulnReport) + httpmock.RegisterResponder( + http.MethodGet, + seclistUrl, + httpmock.NewBytesResponder(http.StatusOK, []byte("path1\npath2")), + ) httpmock.RegisterResponder(operation.Method, operation.URL.String(), httpmock.NewBytesResponder(http.StatusNoContent, nil)) - httpmock.RegisterResponder(http.MethodGet, "http://localhost:8080/path1", httpmock.NewStringResponder(http.StatusNotFound, "Not Found")) - httpmock.RegisterResponder(http.MethodGet, "http://localhost:8080/path2", httpmock.NewStringResponder(http.StatusNotFound, "Not Found")) + httpmock.RegisterResponder(http.MethodGet, "http://localhost:1234/path1", httpmock.NewStringResponder(http.StatusNotFound, "Not Found")) + httpmock.RegisterResponder(http.MethodGet, "http://localhost:1234/path2", httpmock.NewStringResponder(http.StatusNotFound, "Not Found")) - _, err := handler(operation, securitySchemes[0]) + _, err := discover.DownloadAndScanURLs("test", seclistUrl, r, vulnReport, operation, securitySchemes[0]) assert.NoError(t, err) - assert.Equal(t, 2, httpmock.GetTotalCallCount()) + assert.Equal(t, 3, httpmock.GetTotalCallCount()) assert.True(t, r.Issues[0].HasPassed()) } -func TestCreateURLScanHandler_Failed_WhenFoundExposedURLs(t *testing.T) { +func TestDownloadAndScanURLs_Failed_WhenFoundExposedURLs(t *testing.T) { client := request.GetDefaultClient() httpmock.ActivateNonDefault(client.Client) - defer httpmock.DeactivateAndReset() + t.Cleanup(httpmock.DeactivateAndReset) - seclistUrl := "http://localhost:8080/seclist" - defaultUrls := []string{"/path1", "/path2"} + seclistUrl := "http://localhost:1234/failed_seclist" securitySchemes := []*auth.SecurityScheme{auth.MustNewNoAuthSecurityScheme()} - operation := operation.MustNewOperation(http.MethodGet, "http://localhost:8080", nil, client) + operation := operation.MustNewOperation(http.MethodGet, "http://localhost:1234", nil, client) operation.SetSecuritySchemes(securitySchemes) r := report.NewScanReport("test", "test", operation) vulnReport := &report.IssueReport{} - handler := discover.CreateURLScanHandler("test", seclistUrl, defaultUrls, r, vulnReport) - + httpmock.RegisterResponder( + http.MethodGet, + seclistUrl, + httpmock.NewBytesResponder(http.StatusOK, []byte("path1\npath2")), + ) httpmock.RegisterResponder(operation.Method, operation.URL.String(), httpmock.NewBytesResponder(http.StatusNoContent, nil)) - httpmock.RegisterResponder(http.MethodGet, "http://localhost:8080/path1", httpmock.NewStringResponder(http.StatusOK, "OK")) - httpmock.RegisterResponder(http.MethodGet, "http://localhost:8080/path2", httpmock.NewStringResponder(http.StatusOK, "OK")) + httpmock.RegisterResponder(http.MethodGet, "http://localhost:1234/path1", httpmock.NewStringResponder(http.StatusOK, "OK")) - _, err := handler(operation, securitySchemes[0]) + _, err := discover.DownloadAndScanURLs("test", seclistUrl, r, vulnReport, operation, securitySchemes[0]) assert.NoError(t, err) - assert.Equal(t, 1, httpmock.GetTotalCallCount()) + assert.Equal(t, 2, httpmock.GetTotalCallCount()) assert.True(t, r.Issues[0].HasFailed()) } diff --git a/scan/discover/well-known/well_known.go b/scan/discover/well-known/well_known.go new file mode 100644 index 00000000..5968e46e --- /dev/null +++ b/scan/discover/well-known/well_known.go @@ -0,0 +1,38 @@ +package wellknown + +import ( + "github.com/cerberauth/vulnapi/internal/auth" + "github.com/cerberauth/vulnapi/internal/operation" + "github.com/cerberauth/vulnapi/report" + "github.com/cerberauth/vulnapi/scan/discover" +) + +const ( + DiscoverableWellKnownScanID = "discover.well-known" + DiscoverableWellKnownScanName = "Discoverable well-known path" +) + +type DiscoverableGraphQLPathData = discover.DiscoverData + +var issue = report.Issue{ + ID: "discover.discoverable_well_known", + Name: "Discoverable well-known path", + + Classifications: &report.Classifications{ + OWASP: report.OWASP_2023_SSRF, + }, + + CVSS: report.CVSS{ + Version: 4.0, + Vector: "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:N/SA:N", + Score: 0, + }, +} + +var wellKnownSeclistUrl = "https://raw.githubusercontent.com/cerberauth/vulnapi/main/seclist/lists/well-known.txt" + +func ScanHandler(op *operation.Operation, securityScheme *auth.SecurityScheme) (*report.ScanReport, error) { + vulnReport := report.NewIssueReport(issue).WithOperation(op).WithSecurityScheme(securityScheme) + r := report.NewScanReport(DiscoverableWellKnownScanID, DiscoverableWellKnownScanName, op) + return discover.DownloadAndScanURLs("Well-Known", wellKnownSeclistUrl, r, vulnReport, op, securityScheme) +} diff --git a/scan/discover/well-known/well_known_test.go b/scan/discover/well-known/well_known_test.go new file mode 100644 index 00000000..c39e9c3d --- /dev/null +++ b/scan/discover/well-known/well_known_test.go @@ -0,0 +1,50 @@ +package wellknown_test + +import ( + "net/http" + "testing" + + "github.com/cerberauth/vulnapi/internal/auth" + "github.com/cerberauth/vulnapi/internal/operation" + "github.com/cerberauth/vulnapi/internal/request" + wellknown "github.com/cerberauth/vulnapi/scan/discover/well-known" + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDiscoverableScanner_Passed_WhenNoDiscoverableWellKnownPathFound(t *testing.T) { + client := request.NewClient(request.NewClientOptions{ + RateLimit: 500, + }) + httpmock.ActivateNonDefault(client.Client) + defer httpmock.DeactivateAndReset() + + op := operation.MustNewOperation(http.MethodGet, "http://localhost:8080/", nil, client) + httpmock.RegisterResponder(op.Method, op.URL.String(), httpmock.NewBytesResponder(http.StatusNoContent, nil)) + httpmock.RegisterNoResponder(httpmock.NewBytesResponder(http.StatusNotFound, nil)) + + report, err := wellknown.ScanHandler(op, auth.MustNewNoAuthSecurityScheme()) + + require.NoError(t, err) + assert.Greater(t, httpmock.GetTotalCallCount(), 5) + assert.True(t, report.Issues[0].HasPassed()) +} + +func TestDiscoverableScanner_Failed_WhenOneWellKnownPathFound(t *testing.T) { + client := request.NewClient(request.NewClientOptions{ + RateLimit: 500, + }) + httpmock.ActivateNonDefault(client.Client) + defer httpmock.DeactivateAndReset() + + operation := operation.MustNewOperation(http.MethodGet, "http://localhost:8080/.well-known/jwks.json", nil, client) + httpmock.RegisterResponder(operation.Method, operation.URL.String(), httpmock.NewBytesResponder(http.StatusOK, nil)) + httpmock.RegisterNoResponder(httpmock.NewBytesResponder(http.StatusNotFound, nil)) + + report, err := wellknown.ScanHandler(operation, auth.MustNewNoAuthSecurityScheme()) + + require.NoError(t, err) + assert.Greater(t, httpmock.GetTotalCallCount(), 0) + assert.True(t, report.Issues[0].HasFailed()) +} diff --git a/scenario/discover_api.go b/scenario/discover_api.go index dbebae18..cf9208d6 100644 --- a/scenario/discover_api.go +++ b/scenario/discover_api.go @@ -6,7 +6,9 @@ import ( "github.com/cerberauth/vulnapi/scan" discoverablegraphql "github.com/cerberauth/vulnapi/scan/discover/discoverable_graphql" discoverableopenapi "github.com/cerberauth/vulnapi/scan/discover/discoverable_openapi" + exposedfiles "github.com/cerberauth/vulnapi/scan/discover/exposed_files" fingerprint "github.com/cerberauth/vulnapi/scan/discover/fingerprint" + wellknown "github.com/cerberauth/vulnapi/scan/discover/well-known" ) func NewDiscoverAPIScan(method string, url string, client *request.Client, opts *scan.ScanOptions) (*scan.Scan, error) { @@ -33,6 +35,8 @@ func NewDiscoverAPIScan(method string, url string, client *request.Client, opts urlScan.AddScanHandler(scan.NewOperationScanHandler(fingerprint.DiscoverFingerPrintScanID, fingerprint.ScanHandler)) urlScan.AddScanHandler(scan.NewOperationScanHandler(discoverableopenapi.DiscoverableOpenAPIScanID, discoverableopenapi.ScanHandler)) urlScan.AddScanHandler(scan.NewOperationScanHandler(discoverablegraphql.DiscoverableGraphQLPathScanID, discoverablegraphql.ScanHandler)) + urlScan.AddScanHandler(scan.NewOperationScanHandler(exposedfiles.DiscoverableFilesScanID, exposedfiles.ScanHandler)) + urlScan.AddScanHandler(scan.NewOperationScanHandler(wellknown.DiscoverableWellKnownScanID, wellknown.ScanHandler)) return urlScan, nil } diff --git a/seclist/lists/exposed-paths.txt b/seclist/lists/exposed-paths.txt new file mode 100644 index 00000000..4cdcad7c --- /dev/null +++ b/seclist/lists/exposed-paths.txt @@ -0,0 +1,1067 @@ +.0 +.FBCIndex +.ICEauthority +.JustCode +.LICENSE.bud +.LSOverride +.PDF +.Python +.RData +.README.md.bud +.Rapp.history +.Rbuildignore +.Rhistory +.Rprofile +.SRCINFO +.SyncID +.SyncIgnore +.Xauthority +.Xdefaults +.Xresources +.accdb +.ackrc +.action +.actionScriptProperties +.admin/ +.agignore +.agilekeychain +.agilekeychain.zip +.aliases +.all-contributorsrc +.analysis_options +.angular-cli.json +.ansible/ +.apport-ignore.xml +.appveyor.yml +.arcconfig +.architect +.arclint +.arcrc +.asa +.ashx +.asmx +.asp +.aspnet/DataProtection-Keys/ +.aspx +.atfp_history +.atom/config.cson +.atoum.php +.autotest +.autotools +.aws/ +.aws/config +.aws/credentials +.axd +.azure-pipelines.yml +.azure/accessTokens.json +.babel.json +.babelrc.cjs +.babelrc.js +.badarg.log +.badsegment.log +.bak +.bak_0.log +.bash_aliases +.bash_history +.bash_prompt +.bashrc +.binstar.yml +.bithoundrc +.blg +.bluemix/pipeline.yaml +.bluemix/pipeline.yml +.bootstraprc +.boto +.bower.json +.bowerrc +.brackets.json +.browserslistrc +.buckconfig +.build +.buildignore +.buildkite/pipeline.json +.buildkite/pipeline.yaml +.buildkite/pipeline.yml +.buildlog +.buildpacks +.bumpversion.cfg +.byebug_history +.bzr/README +.bzr/branch-format +.bzrignore +.c9/metadata/environment/.env +.cache-main +.cane +.cask +.catalog +.cer +.cert +.cfg/ +.cfignore +.cfm +.cgi +.checkignore +.chef/config.rb +.chef/knife.rb +.circleci/ +.circleci/circle.yml +.circleci/config.yml +.clang-format +.clang_complete +.clcbio/ +.clog.toml +.coafile +.cocoadocs.yml +.codacy.yml +.codeclimate.json +.codeclimate.yml +.codecov.yml +.codefresh/codefresh.yml +.codeship.yaml +.codeship.yml +.coffee_history +.coffeelintignore +.cointop/config +.com +.components +.components/ +.composer/auth.json +.concrete/dev_mode +.conda/ +.condarc +.config +.config.inc.php.swp +.config/ +.config/configstore/snyk.json +.config/gcloud/access_tokens.db +.config/gcloud/configurations/config_default +.config/gcloud/credentials +.config/gcloud/credentials.db +.config/pip/pip.conf +.config/stripe/config.toml +.config/yarn/global/package.json +.config/yarn/global/yarn.lock +.configuration +.configuration.php +.configuration/ +.controls/ +.cookiecutterrc +.cordova/config.json +.coveragerc +.coveralls.yml +.cpan/ +.cpanel/caches/config/ +.cpanm/ +.cpcache/ +.credential +.credentials +.credo.exs +.crt +.csdp.cache +.csi +.css +.csscomb.json +.csslintrc +.ctags +.curlrc +.data/ +.db +.db3 +.dbshell +.dbus/ +.dep.inc +.depend +.dependabot +.deploy/values.yaml +.deployment +.deployment-config.json +.dir-locals.el +.divzero.log +.do +.doc +.docker +.docker/ +.docker/.env +.docker/config.json +.docker/daemon.json +.docker/laravel/app/.env +.dockercfg +.dockerignore +.docs/ +.document +.dotfiles.boto +.drone.jsonnet +.drone.sec +.drone.yaml +.dropbox +.dropbox.attr +.dropbox.cache +.dropbox/ +.ds_store +.dsk +.dub +.dummy +.dump +.dynamodb/ +.eggs/ +.elixir_ls/ +.emacs +.emails/ +.ember-cli +.ensime +.ensime_cache/ +.ensime_lucene/ +.env-example +.env-sample +.env.backup +.env.dev +.env.development.local +.env.development.sample +.env.dist +.env.docker.dev +.env.example +.env.local +.env.prod +.env.production +.env.production.local +.env.sample +.env.save +.env.stage +.env.test +.env.test.local +.env.test.sample +.env.travis +.environment +.envrc +.envs +.env~ +.esdoc.json +.esformatter +.eslintcache +.eslintrc.js +.eslintrc.json +.eslintrc.yaml +.eslintrc.yml +.esmtprc +.eunit +.evg.yml +.exe +.exercism +.exit.log +.exports +.externalnativebuild +.externaltoolbuilders/ +.extra +.factorypath +.fake/ +.faultread.log +.faultreadkernel.log +.fbprefs +.fetch +.filetree +.filezilla/ +.finished-upgraders +.firebaserc +.fixtures.yml +.flake8 +.flexLibProperties +.floo +.flooignore +.flv +.foodcritic +.fop/ +.forktest.log +.forktree.log +.formatter.exs +.frlog +.fseventsd +.ftpconfig +.functions +.fuse_hidden +.fusebox/ +.gdbinit +.gdrive/token_v2.json +.gem/credentials +.gemfile +.gemrc +.gems +.gemspec +.gemtest +.generators +.geppetto-rc.json +.ghc.environment +.ghci +.gho +.gif +.git-credentials +.git-rewrite/ +.git.json +.git/ +.git/COMMIT_EDITMSG +.git/FETCH_HEAD +.git/branches/ +.git/config +.git/description +.git/head +.git/hooks/ +.git/index +.git/info/ +.git/info/attributes +.git/info/exclude +.git/logs/ +.git/logs/head +.git/logs/refs +.git/logs/refs/heads +.git/logs/refs/heads/master +.git/logs/refs/remotes +.git/logs/refs/remotes/origin +.git/logs/refs/remotes/origin/HEAD +.git/logs/refs/remotes/origin/master +.git/objects/ +.git/packed-refs +.git/refs/ +.git/refs/heads +.git/refs/heads/master +.git/refs/remotes +.git/refs/remotes/origin +.git/refs/remotes/origin/HEAD +.git/refs/remotes/origin/master +.git/refs/tags +.git2/ +.gitchangelog.rc +.github/ +.github/ISSUE_TEMPLATE.md +.github/PULL_REQUEST_TEMPLATE.md +.github/workflows/blank.yml +.github/workflows/ci.yml +.github/workflows/dependabot.yml +.github/workflows/docker.yml +.github/workflows/master.yml +.github/workflows/maven.yml +.github/workflows/nodejs.yml +.github/workflows/publish.yml +.gitignore.orig +.gitignore.swp +.gitignore/ +.gitlab +.gitlab-ci.off.yml +.gitlab-ci.yml +.gitlab-ci/.env +.gnome/ +.gnupg/ +.gnupg/trustdb.gpg +.godir +.golangci.yml +.google.token +.goreleaser.yml +.goxc.json +.gphoto/ +.gradle +.gradle/ +.gradle/gradle.properties +.gradletasknamecache +.groc.json +.grunt +.gtkrc +.guile_history +.gvimrc +.gwt-tmp/ +.gwt/ +.gz +.hello.log +.helm/repository/repositories.yaml +.helm/values.conf +.helm/values.yaml +.hg/ +.hg/branch +.hg/dirstate +.hg/hgrc +.hg/requires +.hg/store/data/ +.hg/store/undo +.hg/undo.dirstate +.hg_archival.txt +.hgsigs +.hgsub +.hgsubstate +.hgtags +.hhconfig +.histfile +.hound.yml +.hpc +.hsdoc +.hsenv +.htaccess +.htaccess-dev +.htaccess-local +.htaccess-marco +.htaccess.bak +.htaccess.bak1 +.htaccess.inc +.htaccess.old +.htaccess.orig +.htaccess.sample +.htaccess.save +.htaccess.txt +.htaccess/ +.htaccessBAK +.htaccessOLD +.htaccessOLD2 +.htm +.html +.htpasswd-old +.htpasswd.bak +.htpasswd.inc +.htpasswd/ +.httr-oauth +.hushlogin +.hypothesis/ +.ico +.id +.idea.name +.idea/ +.idea/.name +.idea/Sites.iml +.idea/assetwizardsettings.xml +.idea/caches/build_file_checksums.ser +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/dataSources.ids +.idea/dataSources.local.xml +.idea/dataSources.xml +.idea/deployment.xml +.idea/dictionaries +.idea/drush_stats.iml +.idea/encodings.xml +.idea/gradle.xml +.idea/httprequests +.idea/inspectionProfiles/Project_Default.xml +.idea/libraries +.idea/libraries/ +.idea/misc.xml +.idea/modules +.idea/modules.xml +.idea/naveditor.xml +.idea/replstate.xml +.idea/runConfigurations.xml +.idea/scopes/scope_settings.xml +.idea/sqlDataSources.xml +.idea/tasks.xml +.idea/uiDesigner.xml +.idea/vcs.xml +.idea/webServers.xml +.idea/woaWordpress.iml +.idea/workspace(2).xml +.idea/workspace(3).xml +.idea/workspace(4).xml +.idea/workspace(5).xml +.idea/workspace(6).xml +.idea/workspace(7).xml +.idea/workspace.xml +.idea0/ +.identcache +.import/ +.inc +.inc.php +.indent.pro +.index.php.swp +.influx_history +.ini +.inputrc +.install4j +.interproscan-5/ +.ionide/ +.ipynb_checkpoints +.irb-history +.irb_history +.irbrc +.isort.cfg +.istanbul.yml +.java-buildpack.log +.java-version +.java/ +.jazzy.yaml +.jekyll-cache/ +.jekyll-metadata +.jenkins.sh +.jenkins.yml +.jenv-version +.jestrc +.jobs +.jpeg +.jpg +.js +.jsbeautifyrc +.jscs.json +.jscsrc.json +.jsdoc.json +.jsdtscope +.jsfmtrc +.jslintrc +.json +.jsp +.jupyter/jupyter_notebook_config.json +.kdbx +.kdev4/ +.key +.keys +.keys.yml.swp +.kick +.kitchen.cloud.yml +.kitchen.docker.yml +.kitchen.dokken.yml +.kitchen.local.yml +.kitchen/ +.kube/config +.landscape.yaml +.landscape.yml +.lanproxy/config.json +.last_cover_stats +.leaky-meta +.learn +.lein-deps-sum +.lein-failures +.lein-plugins/ +.lein-repl-history +.lgt_tmp/ +.lgtm +.lgtm.yam +.lgtm.yml +.lia.cache +.lib/ +.libs/ +.local/ +.localhistory/ +.lock +.log +.logout +.luacheckrc +.luacov +.luna/user_info.json +.luna_manager/luna-manager.log +.lvimrc +.m/ +.macos +.magnolia +.magnolia/installer/start +.mailmap +.markdownlint.json +.masterpages/ +.mdb +.merlin +.meteor/ +.metrics +.mfractor/ +.mongorc.js +.mono/ +.mp3 +.msync.yml +.mtj.tmp/ +.muttrc +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.mypy_cache/ +.mysql.txt +.mysql_history +.nakignore +.name +.navigation/ +.nb-gradle/ +.nbgrader.log +.next +.nfs +.ngrok2/ngrok.yml +.nia.cache +.ninja_deps +.ninja_log +.nlia.cache +.no-sublime-package +.node-version +.node_repl_history +.nodemonignore +.nodeset.yml +.nojekyll +.noserc +.nox/ +.npm +.npm/ +.npm/anonymous-cli-metrics.json +.nra.cache +.nrepl-port +.ntvs_analysis.dat +.nuget/ +.nuxt +.nv/ +.nvm/ +.nvmrc +.nyc_output +.nycrc +.ocp-indent +.oh-my-zsh/ +.old +.op/config +.oracle_jre_usage/ +.ori +.osx +.otto/ +.overcommit.yml +.pac +.pac.pac +.pac/ +.pac/proxy.pac +.packages +.pairs +.paket/ +.paket/paket.exe +.pallet/services/aws.clj +.pam_environment +.parallel/ +.path +.pdb +.pdf +.pdkignore +.pem +.pep8 +.perlbrew/ +.perltidyrc +.pfx +.pgadmin3 +.pgdir.log +.pgpass +.pgsql.txt +.php +.php-ini +.php-version +.php3 +.php_cs +.php_cs.cache +.php_cs.dist +.phpcs.xml +.phpspec.yml +.phpunit.result.cache +.pip.conf +.pip/pip.conf +.pkgmeta +.pki/ +.pl +.pl-history +.playground +.pm2/ +.pmd +.pmtignore +.png +.poggit.yml +.postcssrc.js +.powenv +.powrc +.pre-commit-config.yaml +.precomp +.prettierignore +.prettierrc +.prettierrc.js +.prettierrc.json +.prettierrc.toml +.prettierrc.yaml +.preview/ +.priority.log +.pro.user +.production +.projdata +.project-settings.yml +.projectOptions +.projectile +.projections.json +.prospectus +.pry_history +.pryrc +.psci +.psci_modules +.psql_history +.publishrc +.pullapprove.yml +.puppet-lint.rc +.puppet/ +.pwd.lock +.py +.pyc +.pylintrc +.pypirc +.pyre/ +.pytest_cache/ +.python-eggs +.python-history +.python-version +.python_history +.pyup.yml +.qmake.cache +.qmake.conf +.qmake.stash +.rakeTasks +.rar +.rbenv-gemsets +.rbenv-version +.readthedocs.yml +.rebar +.rebar3 +.recommenders +.recommenders/ +.redcar +.rediscli_history +.reduxrc +.reek +.release.json +.remarkrc +.repl_history +.repo-metadata.json +.reviewboardrc +.ropeproject +.rpmdb/ +.rpt2_cache/ +.rspec +.rspec_parallel +.rsync-filter +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ +.rubocop.yml +.rultor.yml +.s3.yml +.s3cfg +.sailsrc +.sass-lint.yml +.scala_dependencies +.scala_history +.scalafmt.conf +.sconf_temp +.sconsign.dblite +.scrapy +.screenrc +.scss-lint.yml +.semaphore/semaphore.yaml +.semaphore/semaphore.yml +.semver +.sensiolabs.yml +.sequelizerc +.serverless/ +.settings/org.eclipse.jdt.core.prefs +.shell.pre-oh-my-zsh +.shtml +.simplecov +.slather.yml +.slugignore +.smalltalk.ston +.snyk +.softint.log +.spacemacs +.spin.log +.springbeans +.spyderproject +.spyproject +.sqlite +.sqlite3 +.sqlite_history +.ssh/ansible_rsa +.ssh/authorized_keys +.ssh/config +.ssh/google_compute_engine +.ssh/google_compute_engine.pub +.ssh/id_dsa +.ssh/id_dsa.pub +.ssh/id_rsa +.ssh/id_rsa.pub +.ssh/identity +.ssh/identity.pub +.ssh/known_hosts +.stack-work/ +.stat/ +.stestr.conf +.stickler.yml +.style.yapf +.styleci.yml +.stylelintignore +.stylelintrc +.stylelintrc.json +.stylintrc +.stylish-haskell.yaml +.sublimelinterrc +.sudo_as_admin_successful +.suo +.svn/wc.db +.swf +.swift-version +.swiftlint.yml +.swiftpm +.sync.yml +.tachikoma.yml +.tar +.target +.tcshrc +.teamcity/settings.kts +.temp/ +.template-lintrc.js +.templates/ +.temporaryitems +.tern-port +.tern-project +.terraform.d/checkpoint_cache +.terraform.d/checkpoint_signature +.terraform.tfstate.lock.info +.terraform/ +.terraform/modules/modules.json +.testbss.log +.testr.conf +.texlipse +.texpadtmp +.tfignore +.tfstate +.tfvars +.tgz +.thunderbird/ +.tm_properties +.tmp/ +.tmp_versions/ +.tmux.conf +.tool-versions +.tox/ +.trash/ +.trashes +.travis.sh +.travis.yml.swp +.travis.yml~ +.travis/ +.travis/config.yml +.travisci.yml +.tugboat +.tvsconfig +.tx/config +.txt +.vagrant/ +.venv +.verb.md +.verbrc.md +.versions +.vim.custom +.vim.netrwhist +.vim/ +.viminfo +.vimrc +.vmware/ +.vs/ +.vscode +.vscode/ +.vscode/.env +.vscode/extensions.json +.vscode/ftp-sync.json +.vscode/launch.json +.vscode/settings.json +.vscode/sftp.json +.vscode/tasks.json +.vscodeignore +.vuepress/dist +.w3m/ +.waitkill.log +.watchmanconfig +.watchr +.web-server-pid +.webassets-cache +.wget-hsts +.wgetrc +.whitesource +.wm_style +.wmv +.worksheet +.wp-cli/config.yml +.wp-config.php.swp +.wp-config.swp +.x-formation/ +.xctool-args +.xhtml +.xinitrc +.xinputrc +.xls +.xml +.xsession +.yamllint +.yardoc/ +.yardopts +.yarn-integrity +.yarnclean +.yarnrc +.ycm_extra_conf.py +.yield.log +.yo-rc.json +.zcompdump-remote-desktop-5.7.1 +.zip +.zprofile +.zsh_history +.zshenv +.zshrc +.zuul.yaml +.zuul.yml +access +access/ +AWStats/ +backstage/ +backup +backup-db/ +bak/ +ban +banlist +bugs/ +build +build/ +CACHE/ +CGI-BIN/ +CHANGELOG.txt +COPYRIGHT +CREDITS +cache +cache/ +cache_files/ +caches/ +Cache/ +Captcha +cert/ +certificate +certs/ +cf/ +cfc/ +cfdocs/ +cfg +cgi +cgi-bin +cgi-bin.%EXT% +cgi-bin/ +cgi-bin2/ +cgi-data/ +cgi-image/ +cgi-local/ +cgi-php/ +cgi-script/ +cgi-shl/ +cgi-src/ +cgi-sys/ +cgi-win/ +cgi.%EXT% +cgi/ +cgi_bin/ +cgibin/ +cloud +conf +conf/ +conf_global +config.php +config/ +config1 +configs/ +configuration +Config +Config/ +credit +credit/ +credits +cron.php +cron/ +cron_jobs +cronjob +cronjob/ +cronjobs/ +crons/ +crossdomain +crossdomain.xml +dat/ +data +data/ +DATA/ +db +db/ +db_backup/ +db_config +db_settings +DB/ +Data/ +DataBackUp/ +Database/ +default +default/ +default1 +dist/ +doc +doc/ +docs/ +doku +Download +Download/ +Downloads +Downloads/ +dump +dump/ +EULA +files +files/ +fileupload/ +Go +History +INSTALL.mysql.txt +INSTALL.pgsql.txt +INSTALL.txt +INSTALL/ +LICENSE.html +LICENSE.txt +LICENSES +LocalSettings +Logs/ +MAINTAINERS.txt +META-INF/ +OLD/ +Old/ +PDF/ +PDFs/ +PEAR/ +PHP/ +PLUGI/ +PRINT/ +SCRIPT/ +SSL/ +Shared/ +UPGRADE.txt +URLrewrite +Upload +Upload/ +UploadFile/ +UploadFiles/ +Uploads/ +VERSION/ +Version +WEB-INF/ +WS_FTP +Web +Web.config +Web/ +WebObjects/ +XMLImporter/ +XPath +Xml/ +Zend/ +_/ +_404 +_archive/ +_backup/ +_baks/ +_cache/ +_config +_config/ +_data/ +_database/ +_db_backups/ +_files/ +_lib/ +_logs/ +_media/ +_notes/ +_old/ +_php/ +_private/ +_temp/ +_temp_/ +_tmp/ \ No newline at end of file diff --git a/seclist/lists/scraped-JWT-secrets.txt b/seclist/lists/jwt-secrets.txt similarity index 100% rename from seclist/lists/scraped-JWT-secrets.txt rename to seclist/lists/jwt-secrets.txt diff --git a/seclist/lists/well-known.txt b/seclist/lists/well-known.txt new file mode 100644 index 00000000..6c6a1476 --- /dev/null +++ b/seclist/lists/well-known.txt @@ -0,0 +1,6 @@ +.well-known/apple-app-site-association +.well-known/security.txt +.well-known/jwks.json +.well-known/oauth-authorization-server +.well-known/openid-configuration +.well-known/openid-federation diff --git a/seclist/seclist.go b/seclist/seclist.go index f4fdc880..78d4407c 100644 --- a/seclist/seclist.go +++ b/seclist/seclist.go @@ -9,6 +9,8 @@ import ( "net/http" "os" "path" + + "github.com/cerberauth/vulnapi/internal/request" ) //go:embed lists/*.txt @@ -92,13 +94,18 @@ func (s *SecList) loadFromTmpFile(filepath string) error { } func (s *SecList) DownloadFromURL(url string) error { - resp, err := http.Get(url) + client := request.GetDefaultClient() + req, err := request.NewRequest(http.MethodGet, url, nil, client) + if err != nil { + return err + } + + resp, err := req.Do() if err != nil { return err } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { + if resp.GetStatusCode() != http.StatusOK { return errors.New("sec list download failed") } @@ -108,7 +115,7 @@ func (s *SecList) DownloadFromURL(url string) error { } defer tempFile.Close() - _, err = io.Copy(tempFile, resp.Body) + _, err = io.Copy(tempFile, resp.GetBody()) if err != nil { return err }