Add recon upload hunter and admin surface probing for owned-target scans.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Extend web crawl with multipart/drag-drop/JS upload ranking and probe common admin paths for 200 vs 401/403 signals in scan JSON.
This commit is contained in:
@@ -34,6 +34,7 @@ func scanLegacy(req ScanRequest) (*ScanReport, error) {
|
||||
if err == nil && crawl != nil {
|
||||
report.Crawl = crawl
|
||||
}
|
||||
report.AdminSurface = ProbeAdminSurface(host, req.Port, req.Scheme)
|
||||
}
|
||||
report.Recommendations = BuildRecommendations(ports, report.Crawl, nil, host, false)
|
||||
return report, nil
|
||||
@@ -127,7 +128,7 @@ func BuildRecommendations(ports []PortResult, crawl *CrawlReport, stack []StackE
|
||||
}
|
||||
|
||||
if crawl != nil {
|
||||
if len(crawl.FileInputs) > 0 || len(crawl.MultipartForms) > 0 {
|
||||
if len(crawl.FileInputs) > 0 || len(crawl.MultipartForms) > 0 || len(crawl.UploadHunter) > 0 {
|
||||
recs = append(recs, DeployRecommendation{
|
||||
Lane: "stage_fetch",
|
||||
Reason: "Multipart or file-upload form — stage_fetch manifest staging",
|
||||
@@ -183,9 +184,6 @@ 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) {
|
||||
@@ -194,6 +192,7 @@ func runOwnedTargetScan(req ScanRequest, scanID string, emit StreamEmit) (*ScanR
|
||||
report.Crawl = crawl
|
||||
report.Stack = MergeStack(crawl.Stack)
|
||||
}
|
||||
report.AdminSurface = ProbeAdminSurface(host, req.Port, req.Scheme)
|
||||
}
|
||||
report.DeployKitLane = SuggestDeployKitLane(report.Stack)
|
||||
cloudMeta := containsPortProfile(profilesUsed, PortProfileCloudMetadata)
|
||||
@@ -245,6 +244,9 @@ func crawlWithOptions(host string, port int, scheme string, seedPaths []string,
|
||||
if maxPages <= 0 { maxPages = DefaultCrawlMaxPages }
|
||||
if maxDepth < 0 { maxDepth = DefaultCrawlDepth }
|
||||
report := &CrawlReport{}
|
||||
var uploadRaw []UploadHunterFinding
|
||||
var jsQueue []string
|
||||
jsSeen := map[string]bool{}
|
||||
var headerSnaps []HTTPHeaderSnap
|
||||
var htmlBodies []string
|
||||
visited := map[string]bool{}
|
||||
@@ -262,7 +264,6 @@ 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 +272,9 @@ func crawlWithOptions(host string, port int, scheme string, seedPaths []string,
|
||||
report.URLFields = append(report.URLFields, fields...)
|
||||
report.SSRFScore += pageScore
|
||||
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)
|
||||
if item.depth >= maxDepth { continue }
|
||||
for _, link := range extractLinks(body) {
|
||||
abs, err := resolveSameOrigin(base, link)
|
||||
@@ -282,50 +285,10 @@ func crawlWithOptions(host string, port int, scheme string, seedPaths []string,
|
||||
if report.SSRFScore > 100 { report.SSRFScore = 100 }
|
||||
report.CMSFingerprints = mergeCMS(nil, report.CMSFingerprints)
|
||||
report.Stack = BuildStack(headerSnaps, htmlBodies)
|
||||
report.UploadHunter = finalizeUploadHunter(base, uploadRaw, jsQueue)
|
||||
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 }
|
||||
|
||||
Reference in New Issue
Block a user