Skip to content

Commit

Permalink
Merge pull request #53 from cerberauth/powered-by-scan
Browse files Browse the repository at this point in the history
feat: add server signature scan
  • Loading branch information
emmanuelgautier authored Feb 28, 2024
2 parents dd09888 + b370d41 commit 3eb2cb1
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 1 deletion.
6 changes: 5 additions & 1 deletion scan/best_practices.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ func (s *Scan) WithHTTPTraceMethodBestPracticesScan() *Scan {
return s.AddScanHandler(bestpractices.HTTPTraceMethodScanHandler)
}

func (s *Scan) WithServerSignatureScan() *Scan {
return s.AddScanHandler(bestpractices.ServerSignatureScanHandler)
}

func (s *Scan) WithAllBestPracticesScans() *Scan {
return s.WithHTTPHeadersBestPracticesScan().WithHTTPTraceMethodBestPracticesScan()
return s.WithHTTPHeadersBestPracticesScan().WithHTTPTraceMethodBestPracticesScan().WithServerSignatureScan()
}
53 changes: 53 additions & 0 deletions scan/best_practices/server_signature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package bestpractices

import (
"github.com/cerberauth/vulnapi/internal/auth"
"github.com/cerberauth/vulnapi/internal/request"
"github.com/cerberauth/vulnapi/internal/scan"
"github.com/cerberauth/vulnapi/report"
)

const (
ServerSignatureSeverityLevel = 1
ServerSignatureVulnerabilityName = "Server Signature Exposed"
ServerSignatureVulnerabilityDescription = "A Server signature is exposed in an header."
)

var SignatureHeaders = []string{"Server", "X-Powered-By", "X-AspNet-Version", "X-AspNetMvc-Version"}

func CheckSignatureHeader(operation *request.Operation, headers map[string][]string, r *report.ScanReport) bool {
for _, header := range SignatureHeaders {
value := headers[header]
if len(value) > 0 {
r.AddVulnerabilityReport(&report.VulnerabilityReport{
SeverityLevel: ServerSignatureSeverityLevel,
Name: ServerSignatureVulnerabilityName,
Description: ServerSignatureVulnerabilityDescription,
Operation: operation,
})

return false
}
}

return true
}

func ServerSignatureScanHandler(operation *request.Operation, ss auth.SecurityScheme) (*report.ScanReport, error) {
r := report.NewScanReport()

ss.SetAttackValue(ss.GetValidValue())
vsa, err := scan.ScanURL(operation, &ss)
r.AddScanAttempt(vsa).End()
if err != nil {
return r, err
}

if vsa.Err != nil {
return r, vsa.Err
}

CheckSignatureHeader(operation, vsa.Response.Header, r)

return r, nil
}
55 changes: 55 additions & 0 deletions scan/best_practices/server_signature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package bestpractices_test

import (
"net/http"
"testing"

"github.com/cerberauth/vulnapi/internal/auth"
"github.com/cerberauth/vulnapi/internal/request"
"github.com/cerberauth/vulnapi/report"
bestpractices "github.com/cerberauth/vulnapi/scan/best_practices"
"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCheckSignatureHeaderWithSignatureHeader(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

token := "token"
securityScheme := auth.NewAuthorizationBearerSecurityScheme("default", &token)
operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil)
vulnerabilityReport := report.VulnerabilityReport{
SeverityLevel: bestpractices.ServerSignatureSeverityLevel,
Name: bestpractices.ServerSignatureVulnerabilityName,
Description: bestpractices.ServerSignatureVulnerabilityDescription,
Operation: operation,
}

httpmock.RegisterResponder(operation.Method, operation.Url, httpmock.NewBytesResponder(204, nil).HeaderAdd(http.Header{"Server": []string{"Apache/2.4.29 (Ubuntu)"}}))

report, err := bestpractices.ServerSignatureScanHandler(operation, securityScheme)

require.NoError(t, err)
assert.Equal(t, 1, httpmock.GetTotalCallCount())
assert.True(t, report.HasVulnerabilityReport())
assert.Equal(t, report.GetVulnerabilityReports()[0], &vulnerabilityReport)
}

func TestCheckSignatureHeaderWithoutSignatureHeader(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()

token := "token"
securityScheme := auth.NewAuthorizationBearerSecurityScheme("default", &token)
operation := request.NewOperation("http://localhost:8080/", "GET", nil, nil, nil)

httpmock.RegisterResponder(operation.Method, operation.Url, httpmock.NewBytesResponder(204, nil))

report, err := bestpractices.ServerSignatureScanHandler(operation, securityScheme)

require.NoError(t, err)
assert.Equal(t, 1, httpmock.GetTotalCallCount())
assert.False(t, report.HasVulnerabilityReport())
}

0 comments on commit 3eb2cb1

Please sign in to comment.