diff --git a/pkg/scan/frameworks/detect.go b/pkg/scan/frameworks/detect.go index c96638a..c1b0814 100644 --- a/pkg/scan/frameworks/detect.go +++ b/pkg/scan/frameworks/detect.go @@ -22,42 +22,48 @@ type FrameworkResult struct { Suggestions []string `json:"suggestions,omitempty"` } -var frameworkSignatures = map[string][]string{ +type FrameworkSignature struct { + Pattern string + Weight float32 + HeaderOnly bool +} + +var frameworkSignatures = map[string][]FrameworkSignature{ "Laravel": { - `laravel_session`, - `XSRF-TOKEN`, - ` highestConfidence { highestConfidence = confidence bestMatch = framework @@ -118,7 +133,6 @@ func DetectFramework(url string, timeout time.Duration, logdir string) (*Framewo frameworklog.Infof("Detected %s framework (version: %s) with %.2f confidence", styles.Highlight.Render(bestMatch), version, highestConfidence) - // Add CVEs and suggestions based on version if cves, suggestions := getVulnerabilities(bestMatch, version); len(cves) > 0 { result.CVEs = cves result.Suggestions = suggestions @@ -146,23 +160,34 @@ func containsHeader(headers http.Header, signature string) bool { } func detectVersion(body string, framework string) string { - patterns := map[string]*regexp.Regexp{ - "Laravel": regexp.MustCompile(`Laravel[/\s+]?([\d.]+)`), - "Django": regexp.MustCompile(`Django/([\d.]+)`), - "Ruby on Rails": regexp.MustCompile(`Rails/([\d.]+)`), - "Express.js": regexp.MustCompile(`express/([\d.]+)`), - "ASP.NET": regexp.MustCompile(`ASP\.NET[/\s+]?([\d.]+)`), - "Spring": regexp.MustCompile(`spring-(core|framework)/([\d.]+)`), - "Flask": regexp.MustCompile(`Flask/([\d.]+)`), + version := extractVersion(body, framework) + if version == "Unknown" { + return version } - if pattern, exists := patterns[framework]; exists { - matches := pattern.FindStringSubmatch(body) - if len(matches) > 1 { - return matches[1] - } + parts := strings.Split(version, ".") + var normalized string + if len(parts) >= 3 { + normalized = fmt.Sprintf("%05s.%05s.%05s", parts[0], parts[1], parts[2]) } - return "Unknown" + return normalized +} + +func exp(x float64) float64 { + if x > 88.0 { + return 1e38 + } + if x < -88.0 { + return 0 + } + + sum := 1.0 + term := 1.0 + for i := 1; i <= 20; i++ { + term *= x / float64(i) + sum += term + } + return sum } func getVulnerabilities(framework, version string) ([]string, []string) { @@ -177,3 +202,24 @@ func getVulnerabilities(framework, version string) ([]string, []string) { } return nil, nil } + +func extractVersion(body string, framework string) string { + versionPatterns := map[string]string{ + "Laravel": `Laravel\s+[Vv]?(\d+\.\d+\.\d+)`, + "Django": `Django\s+[Vv]?(\d+\.\d+\.\d+)`, + "Ruby on Rails": `Rails\s+[Vv]?(\d+\.\d+\.\d+)`, + "Express.js": `Express\s+[Vv]?(\d+\.\d+\.\d+)`, + "ASP.NET": `ASP\.NET\s+[Vv]?(\d+\.\d+\.\d+)`, + "Spring": `Spring\s+[Vv]?(\d+\.\d+\.\d+)`, + "Flask": `Flask\s+[Vv]?(\d+\.\d+\.\d+)`, + } + + if pattern, exists := versionPatterns[framework]; exists { + re := regexp.MustCompile(pattern) + matches := re.FindStringSubmatch(body) + if len(matches) > 1 { + return matches[1] + } + } + return "Unknown" +}