package recon import ( "sort" "strings" "golang.org/x/net/html" ) var formFingerprintKeywords = []struct { keyword string weight int }{ {"url", 12}, {"src", 10}, {"href", 10}, {"callback", 14}, {"redirect", 13}, {"avatar", 8}, {"import", 11}, {"feed", 9}, {"screenshot", 12}, {"pdf", 10}, {"proxy", 11}, } func ScoreFormFieldFingerprint(name, id, placeholder string) (score int, matches []string) { joined := strings.ToLower(strings.Join([]string{name, id, placeholder}, " ")) seen := map[string]bool{} for _, kw := range formFingerprintKeywords { if strings.Contains(joined, kw.keyword) { score += kw.weight if !seen[kw.keyword] { seen[kw.keyword] = true matches = append(matches, kw.keyword) } } } return score, matches } func ExtractFormFieldFingerprints(pageURL, body string) []FormFieldFingerprint { root, err := html.Parse(strings.NewReader(body)) if err != nil { return nil } var out []FormFieldFingerprint var walk func(*html.Node) walk = func(n *html.Node) { if n.Type == html.ElementNode && (n.Data == "input" || n.Data == "textarea" || n.Data == "select") { name := fingerprintAttr(n, "name") id := fingerprintAttr(n, "id") placeholder := fingerprintAttr(n, "placeholder") score, matches := ScoreFormFieldFingerprint(name, id, placeholder) if score > 0 { out = append(out, FormFieldFingerprint{ PageURL: pageURL, Name: name, ID: id, Placeholder: placeholder, Score: score, Matches: matches, }) } } for c := n.FirstChild; c != nil; c = c.NextSibling { walk(c) } } walk(root) sort.Slice(out, func(i, j int) bool { if out[i].Score != out[j].Score { return out[i].Score > out[j].Score } if out[i].Name != out[j].Name { return out[i].Name < out[j].Name } return out[i].ID < out[j].ID }) return out } func fingerprintAttr(n *html.Node, key string) string { for _, a := range n.Attr { if a.Key == key { return a.Val } } return "" } func TopFormFieldFingerprint(fields []FormFieldFingerprint) *FormFieldFingerprint { if len(fields) == 0 { return nil } top := fields[0] return &top } func ApplyCanaryPasteTarget(fields []FormFieldFingerprint, canaryURL string) { for i := range fields { fields[i].PasteTarget = canaryURL } } func AppendPageFingerprints(report *CrawlReport, pageURL, body string) { if report == nil { return } fps := ExtractFormFieldFingerprints(pageURL, body) report.FingerprintFields = append(report.FingerprintFields, fps...) for _, fp := range fps { if fp.Score >= 10 { report.SSRFScore += fp.Score / 5 } } }