Add recon network batch 1: stack banners and smart port profiles.
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
Parse technology stack from crawl headers, grab SSH/HTTP/WinRM banners, merge smart port bundles with FleetPorts, and suggest deploy-kit lane plus SSM for EC2 metadata targets.
This commit is contained in:
232
scripts/_batch1_embed.py
Normal file
232
scripts/_batch1_embed.py
Normal file
@@ -0,0 +1,232 @@
|
||||
TYPES = '''package recon
|
||||
|
||||
import "time"
|
||||
|
||||
var FleetPorts = []int{22, 80, 443, 445, 3389, 5985, 5986, 6262, 8080, 8443}
|
||||
|
||||
const (
|
||||
DefaultPortDialTimeout = 2 * time.Second
|
||||
DefaultCrawlDepth = 2
|
||||
DefaultCrawlMaxPages = 50
|
||||
)
|
||||
|
||||
type ScanRequest struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port,omitempty"`
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
Paths []string `json:"paths,omitempty"`
|
||||
Profile string `json:"profile,omitempty"`
|
||||
Profiles []string `json:"profiles,omitempty"`
|
||||
}
|
||||
|
||||
type PortResult struct {
|
||||
Port int `json:"port"`
|
||||
Open bool `json:"open"`
|
||||
}
|
||||
|
||||
type PortBanner struct {
|
||||
Port int `json:"port"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Banner string `json:"banner,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Hint string `json:"hint,omitempty"`
|
||||
}
|
||||
|
||||
type StackEntry struct {
|
||||
Name string `json:"name"`
|
||||
Source string `json:"source"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
type HTTPHeaderSnap struct {
|
||||
URL string
|
||||
Headers map[string]string
|
||||
}
|
||||
|
||||
type FormFinding struct {
|
||||
PageURL string `json:"page_url"`
|
||||
Action string `json:"action,omitempty"`
|
||||
Method string `json:"method,omitempty"`
|
||||
Enctype string `json:"enctype,omitempty"`
|
||||
Fields []string `json:"fields,omitempty"`
|
||||
HasFile bool `json:"has_file_input,omitempty"`
|
||||
Multipart bool `json:"multipart,omitempty"`
|
||||
}
|
||||
|
||||
type URLFieldFinding struct {
|
||||
PageURL string `json:"page_url"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Hint string `json:"hint"`
|
||||
}
|
||||
|
||||
type PageFinding struct {
|
||||
URL string `json:"url"`
|
||||
StatusCode int `json:"status_code"`
|
||||
Title string `json:"title,omitempty"`
|
||||
}
|
||||
|
||||
type CrawlReport struct {
|
||||
PagesFetched int `json:"pages_fetched"`
|
||||
Pages []PageFinding `json:"pages,omitempty"`
|
||||
FileInputs []FormFinding `json:"file_inputs,omitempty"`
|
||||
MultipartForms []FormFinding `json:"multipart_forms,omitempty"`
|
||||
URLFields []URLFieldFinding `json:"url_fields,omitempty"`
|
||||
SSRFScore int `json:"ssrf_score"`
|
||||
CMSFingerprints []string `json:"cms_fingerprints,omitempty"`
|
||||
Stack []StackEntry `json:"stack,omitempty"`
|
||||
}
|
||||
|
||||
type DeployRecommendation struct {
|
||||
Lane string `json:"lane,omitempty"`
|
||||
Template string `json:"template,omitempty"`
|
||||
Reason string `json:"reason"`
|
||||
Priority int `json:"priority"`
|
||||
}
|
||||
|
||||
type ReconScanDiff struct {
|
||||
NewPorts []int `json:"new_ports,omitempty"`
|
||||
NewForms []FormFinding `json:"new_forms,omitempty"`
|
||||
}
|
||||
|
||||
type ReconHistoryEntry struct {
|
||||
ScanID string `json:"scan_id"`
|
||||
Host string `json:"host"`
|
||||
Profile string `json:"profile,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
ScannedAt time.Time `json:"scanned_at"`
|
||||
Report *ScanReport `json:"report"`
|
||||
Diff *ReconScanDiff `json:"diff,omitempty"`
|
||||
}
|
||||
|
||||
type ScanReport struct {
|
||||
ScanID string `json:"scan_id,omitempty"`
|
||||
Host string `json:"host"`
|
||||
Profile string `json:"profile,omitempty"`
|
||||
ProfilesUsed []string `json:"profiles_used,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
ScannedAt time.Time `json:"scanned_at"`
|
||||
Ports []PortResult `json:"ports"`
|
||||
Banners []PortBanner `json:"banners,omitempty"`
|
||||
Stack []StackEntry `json:"stack,omitempty"`
|
||||
DeployKitLane string `json:"deploy_kit_lane,omitempty"`
|
||||
Crawl *CrawlReport `json:"crawl,omitempty"`
|
||||
RelayVia string `json:"relay_via,omitempty"`
|
||||
Recommendations []DeployRecommendation `json:"recommendations,omitempty"`
|
||||
}
|
||||
'''
|
||||
|
||||
PORTSCAN = '''package recon
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
PortProfileWeb = "web"
|
||||
PortProfileWindows = "windows"
|
||||
PortProfileLinux = "linux"
|
||||
PortProfileCloudMetadata = "cloud_metadata"
|
||||
)
|
||||
|
||||
var portProfilePorts = map[string][]int{
|
||||
PortProfileWeb: {80, 443, 6262},
|
||||
PortProfileWindows: {445, 5985, 3389},
|
||||
PortProfileLinux: {22},
|
||||
}
|
||||
|
||||
var dialPortFn func(host string, port int, timeout time.Duration) bool
|
||||
|
||||
func ScanPorts(host string, ports []int) []PortResult {
|
||||
if len(ports) == 0 {
|
||||
ports = FleetPorts
|
||||
}
|
||||
out := make([]PortResult, 0, len(ports))
|
||||
for _, port := range ports {
|
||||
out = append(out, PortResult{Port: port, Open: dialPort(host, port, DefaultPortDialTimeout)})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func dialPort(host string, port int, timeout time.Duration) bool {
|
||||
if dialPortFn != nil {
|
||||
return dialPortFn(host, port, timeout)
|
||||
}
|
||||
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(port)), timeout)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_ = conn.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
func ResolveScanPortsFromRequest(req ScanRequest) ([]int, []string) {
|
||||
return ResolveScanPorts(req.Profiles)
|
||||
}
|
||||
|
||||
func ResolveScanPorts(profiles []string) ([]int, []string) {
|
||||
seen := map[int]bool{}
|
||||
var ports []int
|
||||
for _, p := range FleetPorts {
|
||||
if !seen[p] {
|
||||
seen[p] = true
|
||||
ports = append(ports, p)
|
||||
}
|
||||
}
|
||||
var used []string
|
||||
for _, raw := range profiles {
|
||||
name := strings.ToLower(strings.TrimSpace(raw))
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if name == PortProfileCloudMetadata {
|
||||
if !containsPortProfile(used, name) {
|
||||
used = append(used, name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
bundle, ok := portProfilePorts[name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if !containsPortProfile(used, name) {
|
||||
used = append(used, name)
|
||||
}
|
||||
for _, p := range bundle {
|
||||
if !seen[p] {
|
||||
seen[p] = true
|
||||
ports = append(ports, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Ints(ports)
|
||||
return ports, used
|
||||
}
|
||||
|
||||
func containsPortProfile(list []string, want string) bool {
|
||||
for _, s := range list {
|
||||
if s == want {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TargetLooksEC2(host string) bool {
|
||||
host = strings.ToLower(strings.TrimSpace(host))
|
||||
if host == "" {
|
||||
return false
|
||||
}
|
||||
if host == "169.254.169.254" {
|
||||
return true
|
||||
}
|
||||
return strings.Contains(host, ".compute.amazonaws.com") ||
|
||||
strings.Contains(host, ".compute.internal") ||
|
||||
strings.HasPrefix(host, "ip-10-") ||
|
||||
strings.HasPrefix(host, "ec2-")
|
||||
}
|
||||
'''
|
||||
Reference in New Issue
Block a user