Add recon form fingerprint library and SSRF canary mode.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Score crawl inputs by SSRF-prone field names and register ping-back canaries for operator paste confirmation.
This commit is contained in:
AetherForge
2026-06-07 12:23:11 -07:00
parent 251bdfa1ac
commit 49c24e611c
19 changed files with 1410 additions and 78 deletions

View File

@@ -184,6 +184,9 @@ func runOwnedTargetScan(req ScanRequest, scanID string, emit StreamEmit) (*ScanR
if !opts.SkipPorts {
ports := scanPortsList(host, portsToScan)
report.Ports = ports
for _, p := range ports {
emitReconPort(emit, scanID, host, p)
}
report.Banners = GrabBanners(host, ports)
}
if shouldCrawlProfile(req, uxProfile, report.Ports, opts) {
@@ -264,6 +267,7 @@ func crawlWithOptions(host string, port int, scheme string, seedPaths []string,
report.PagesFetched++
title, _ := htmlParseTitle(body)
report.Pages = append(report.Pages, PageFinding{URL: item.url, StatusCode: status, Title: title})
emitReconPage(emit, scanID, host, item.url, status, title)
if len(headers) > 0 { headerSnaps = append(headerSnaps, HTTPHeaderSnap{URL: item.url, Headers: headers}) }
htmlBodies = append(htmlBodies, body)
files, multi, fields, pageScore, cms := ParseHTML(item.url, body)
@@ -271,7 +275,9 @@ func crawlWithOptions(host string, port int, scheme string, seedPaths []string,
report.MultipartForms = append(report.MultipartForms, multi...)
report.URLFields = append(report.URLFields, fields...)
report.SSRFScore += pageScore
AppendPageFingerprints(report, item.url, body)
report.CMSFingerprints = mergeCMS(report.CMSFingerprints, cms)
emitReconFindings(emit, scanID, host, files, multi, fields)
uploadRaw = append(uploadRaw, collectUploadFromPage(item.url, files, multi)...)
uploadRaw = append(uploadRaw, detectDragDropZones(item.url, body)...)
collectUploadJSAtDepth(base, item.url, body, item.depth, maxDepth, jsSeen, &jsQueue)
@@ -289,14 +295,38 @@ func crawlWithOptions(host string, port int, scheme string, seedPaths []string,
return report, nil
}
func emitReconPort(emit StreamEmit, scanID, host string, p PortResult) {
if emit == nil { return }
emit("recon_port", map[string]interface{}{"scan_id": scanID, "host": host, "port": p.Port, "open": p.Open})
}
func emitReconPage(emit StreamEmit, scanID, host, pageURL string, status int, title string) {
if emit == nil { return }
emit("recon_page", map[string]interface{}{"scan_id": scanID, "host": host, "url": pageURL, "status_code": status, "title": title})
}
func emitReconFindings(emit StreamEmit, scanID, host string, files, multi []FormFinding, fields []URLFieldFinding) {
if emit == nil { return }
for _, f := range files { emit("recon_finding", map[string]interface{}{"scan_id": scanID, "host": host, "kind": "file_input", "finding": f}) }
for _, f := range multi { emit("recon_finding", map[string]interface{}{"scan_id": scanID, "host": host, "kind": "multipart_form", "finding": f}) }
for _, f := range fields { emit("recon_finding", map[string]interface{}{"scan_id": scanID, "host": host, "kind": "url_field", "finding": f}) }
}
func formFindingKey(f FormFinding) string { return f.PageURL + "|" + f.Action + "|" + strings.Join(f.Fields, ",") }
func collectFormFindings(r *ScanReport) []FormFinding {
if r == nil || r.Crawl == nil { return nil }
out := append([]FormFinding{}, r.Crawl.FileInputs...)
return append(out, r.Crawl.MultipartForms...)
}
func OpenPorts(ports []PortResult) []int { var o []int; for _, p := range ports { if p.Open { o = append(o, p.Port) } }; return o }
func DiffReports(prev, cur *ScanReport) *ReconScanDiff {
if cur == nil { return nil }
d := &ReconScanDiff{}
if prev == nil { d.NewPorts = OpenPorts(cur.Ports); return d }
if prev == nil { d.NewPorts = OpenPorts(cur.Ports); d.NewForms = collectFormFindings(cur); return d }
po := map[int]bool{}
for _, p := range prev.Ports { if p.Open { po[p.Port] = true } }
for _, p := range cur.Ports { if p.Open && !po[p.Port] { d.NewPorts = append(d.NewPorts, p.Port) } }
seen := map[string]bool{}
for _, f := range collectFormFindings(prev) { seen[formFindingKey(f)] = true }
for _, f := range collectFormFindings(cur) { if !seen[formFindingKey(f)] { d.NewForms = append(d.NewForms, f) } }
return d
}
func BuildHistory(rows []*ScanReport) []ReconHistoryEntry {