@@ -4,12 +4,15 @@ package cmd
44import (
55 "context"
66 "fmt"
7+ "strings"
78 "time"
89
910 "github.com/CodeMonkeyCybersecurity/shells/internal/core"
11+ "github.com/CodeMonkeyCybersecurity/shells/internal/discovery"
1012 "github.com/CodeMonkeyCybersecurity/shells/internal/logger"
1113 "github.com/CodeMonkeyCybersecurity/shells/internal/orchestrator"
1214 "github.com/CodeMonkeyCybersecurity/shells/internal/validation"
15+ "github.com/CodeMonkeyCybersecurity/shells/pkg/correlation"
1316 "github.com/CodeMonkeyCybersecurity/shells/pkg/types"
1417 "github.com/fatih/color"
1518 "github.com/spf13/cobra"
@@ -83,6 +86,16 @@ func runIntelligentOrchestrator(ctx context.Context, target string, cmd *cobra.C
8386 return fmt .Errorf ("orchestrator execution failed: %w" , err )
8487 }
8588
89+ // Display organization footprinting results if available
90+ if result .OrganizationInfo != nil {
91+ displayOrganizationFootprinting (result .OrganizationInfo )
92+ }
93+
94+ // Display asset discovery results if available
95+ if len (result .DiscoveredAssets ) > 0 {
96+ displayAssetDiscoveryResults (result .DiscoveredAssets , result .DiscoverySession )
97+ }
98+
8699 // Display results
87100 displayOrchestratorResults (result , config )
88101
@@ -211,6 +224,9 @@ func displayOrchestratorResults(result *orchestrator.BugBountyResult, config orc
211224 fmt .Println ()
212225 }
213226
227+ // Display vulnerability test coverage
228+ displayTestCoverage (result )
229+
214230 // Display findings by severity using modularized display functions
215231 if len (result .Findings ) > 0 {
216232 log .Info ("═══ Findings by Severity ═══" , "component" , "orchestrator_main" )
@@ -272,5 +288,354 @@ func saveOrchestratorReport(result *orchestrator.BugBountyResult, filename strin
272288 return fmt .Errorf ("report export not yet implemented" )
273289}
274290
291+ // displayOrganizationFootprinting displays organization footprinting results
292+ func displayOrganizationFootprinting (org * correlation.Organization ) {
293+ if org == nil || org .Name == "" {
294+ return
295+ }
296+
297+ fmt .Println ()
298+ color .Cyan ("═══ Phase 0: Organization Footprinting ═══" )
299+ fmt .Println ()
300+
301+ // Organization info
302+ fmt .Printf (" Organization: %s\n " , color .GreenString (org .Name ))
303+ if org .Confidence > 0 {
304+ confidencePct := org .Confidence * 100
305+ confidenceColor := color .GreenString
306+ if confidencePct < 50 {
307+ confidenceColor = color .YellowString
308+ }
309+ fmt .Printf (" Confidence: %s\n " , confidenceColor ("%.1f%%" , confidencePct ))
310+ }
311+
312+ // Related domains
313+ if len (org .Domains ) > 0 {
314+ fmt .Printf ("\n ✓ Found %s related domains:\n " , color .GreenString ("%d" , len (org .Domains )))
315+ displayLimit := 10
316+ for i , domain := range org .Domains {
317+ if i < displayLimit {
318+ fmt .Printf (" • %s\n " , domain )
319+ }
320+ }
321+ if len (org .Domains ) > displayLimit {
322+ fmt .Printf (" %s\n " , color .CyanString ("... and %d more" , len (org .Domains )- displayLimit ))
323+ }
324+ }
325+
326+ // IP ranges
327+ if len (org .IPRanges ) > 0 {
328+ fmt .Printf ("\n ✓ Found %s IP ranges:\n " , color .GreenString ("%d" , len (org .IPRanges )))
329+ for _ , ipRange := range org .IPRanges {
330+ fmt .Printf (" • %s\n " , ipRange )
331+ }
332+ }
333+
334+ // ASNs
335+ if len (org .ASNs ) > 0 {
336+ fmt .Printf ("\n ✓ Found %s ASNs:\n " , color .GreenString ("%d" , len (org .ASNs )))
337+ for _ , asn := range org .ASNs {
338+ fmt .Printf (" • %s\n " , asn )
339+ }
340+ }
341+
342+ // Certificates
343+ if len (org .Certificates ) > 0 {
344+ fmt .Printf ("\n ✓ Found %s SSL certificates\n " , color .GreenString ("%d" , len (org .Certificates )))
345+ }
346+
347+ // Subsidiaries
348+ if len (org .Subsidiaries ) > 0 {
349+ fmt .Printf ("\n ✓ Found %s subsidiaries:\n " , color .GreenString ("%d" , len (org .Subsidiaries )))
350+ for _ , sub := range org .Subsidiaries {
351+ fmt .Printf (" • %s\n " , sub )
352+ }
353+ }
354+
355+ // Sources
356+ if len (org .Sources ) > 0 {
357+ fmt .Printf ("\n Sources: %s\n " , color .CyanString (strings .Join (org .Sources , ", " )))
358+ }
359+
360+ fmt .Println ()
361+ }
362+
363+ // displayAssetDiscoveryResults displays detailed asset discovery results
364+ func displayAssetDiscoveryResults (assets []* discovery.Asset , session * discovery.DiscoverySession ) {
365+ if len (assets ) == 0 {
366+ return
367+ }
368+
369+ fmt .Println ()
370+ color .Cyan ("═══ Phase 1: Asset Discovery ═══" )
371+ fmt .Println ()
372+
373+ // Group assets by type
374+ assetsByType := make (map [discovery.AssetType ][]* discovery.Asset )
375+ for _ , asset := range assets {
376+ assetsByType [asset .Type ] = append (assetsByType [asset .Type ], asset )
377+ }
378+
379+ // Display subdomains
380+ if subdomains := assetsByType [discovery .AssetTypeSubdomain ]; len (subdomains ) > 0 {
381+ fmt .Printf (" ✓ Discovered %s subdomains:\n " , color .GreenString ("%d" , len (subdomains )))
382+ displayLimit := 15
383+ for i , asset := range subdomains {
384+ if i < displayLimit {
385+ priority := ""
386+ if asset .Priority >= 80 { // High priority assets
387+ priority = color .RedString (" [HIGH VALUE]" )
388+ }
389+ fmt .Printf (" • %s%s\n " , asset .Value , priority )
390+ }
391+ }
392+ if len (subdomains ) > displayLimit {
393+ fmt .Printf (" %s\n " , color .CyanString ("... and %d more" , len (subdomains )- displayLimit ))
394+ }
395+ fmt .Println ()
396+ }
397+
398+ // Display IPs with open ports
399+ if ips := assetsByType [discovery .AssetTypeIP ]; len (ips ) > 0 {
400+ fmt .Printf (" ✓ Found %s IP addresses:\n " , color .GreenString ("%d" , len (ips )))
401+ for i , asset := range ips {
402+ if i < 10 { // Show first 10
403+ ports := ""
404+ if p , ok := asset .Metadata ["open_ports" ]; ok {
405+ ports = fmt .Sprintf (" - Ports: %s" , p )
406+ }
407+ fmt .Printf (" • %s%s\n " , asset .Value , ports )
408+ }
409+ }
410+ if len (ips ) > 10 {
411+ fmt .Printf (" %s\n " , color .CyanString ("... and %d more" , len (ips )- 10 ))
412+ }
413+ fmt .Println ()
414+ }
415+
416+ // Display services with versions
417+ if services := assetsByType [discovery .AssetTypeService ]; len (services ) > 0 {
418+ fmt .Printf (" ✓ Found %s services:\n " , color .GreenString ("%d" , len (services )))
419+ for i , asset := range services {
420+ if i < 10 { // Show first 10
421+ version := ""
422+ if v , ok := asset .Metadata ["version" ]; ok {
423+ version = fmt .Sprintf (" (%s)" , v )
424+ }
425+ port := ""
426+ if p , ok := asset .Metadata ["port" ]; ok {
427+ port = fmt .Sprintf (":%s" , p )
428+ }
429+ serviceName := asset .Value
430+ if name , ok := asset .Metadata ["service_name" ]; ok {
431+ serviceName = name
432+ }
433+ fmt .Printf (" • %s%s - %s%s\n " , asset .IP , port , serviceName , version )
434+ }
435+ }
436+ if len (services ) > 10 {
437+ fmt .Printf (" %s\n " , color .CyanString ("... and %d more" , len (services )- 10 ))
438+ }
439+ fmt .Println ()
440+ }
441+
442+ // Display URLs/endpoints
443+ if urls := assetsByType [discovery .AssetTypeURL ]; len (urls ) > 0 {
444+ fmt .Printf (" ✓ Found %s URLs:\n " , color .GreenString ("%d" , len (urls )))
445+ for i , asset := range urls {
446+ if i < 8 { // Show first 8
447+ fmt .Printf (" • %s\n " , asset .Value )
448+ }
449+ }
450+ if len (urls ) > 8 {
451+ fmt .Printf (" %s\n " , color .CyanString ("... and %d more" , len (urls )- 8 ))
452+ }
453+ fmt .Println ()
454+ }
455+
456+ // Display technologies detected
457+ techSet := make (map [string ]bool )
458+ for _ , asset := range assets {
459+ for _ , tech := range asset .Technology {
460+ techSet [tech ] = true
461+ }
462+ }
463+ if len (techSet ) > 0 {
464+ techs := make ([]string , 0 , len (techSet ))
465+ for tech := range techSet {
466+ techs = append (techs , tech )
467+ }
468+ fmt .Printf (" ✓ Technologies detected: %s\n \n " , color .CyanString (strings .Join (techs , ", " )))
469+ }
470+
471+ // High-value asset summary
472+ if session != nil && session .HighValueAssets > 0 {
473+ fmt .Printf (" %s Found %s high-value assets (login pages, admin panels, APIs)\n \n " ,
474+ color .RedString ("⚠️" ),
475+ color .RedString ("%d" , session .HighValueAssets ),
476+ )
477+ }
478+
479+ fmt .Println ()
480+ }
481+
482+ // displayTestCoverage shows what vulnerability tests were run and their results
483+ func displayTestCoverage (result * orchestrator.BugBountyResult ) {
484+ fmt .Println ()
485+ color .Cyan ("═══ Phase 3: Vulnerability Testing ═══" )
486+ fmt .Println ()
487+
488+ // Authentication Testing
489+ fmt .Printf (" %s Authentication Testing:\n " , color .CyanString ("🔐" ))
490+ if authPhase , ok := result .PhaseResults ["auth" ]; ok {
491+ if authPhase .Status == "completed" {
492+ if authPhase .Findings > 0 {
493+ fmt .Printf (" • Tested SAML/OAuth2/WebAuthn: %s (%d findings)\n " ,
494+ color .RedString ("✗ Vulnerabilities found" ), authPhase .Findings )
495+ } else {
496+ fmt .Printf (" • Tested SAML/OAuth2/WebAuthn: %s\n " ,
497+ color .GreenString ("✓ No issues found" ))
498+ }
499+ } else if authPhase .Status == "skipped" {
500+ fmt .Printf (" • %s (no authentication endpoints discovered)\n " ,
501+ color .YellowString ("⊘ Not applicable" ))
502+ }
503+ } else {
504+ fmt .Printf (" • %s (authentication testing disabled)\n " ,
505+ color .YellowString ("⊘ Skipped" ))
506+ }
507+
508+ // API Security Testing
509+ fmt .Printf ("\n %s API Security Testing:\n " , color .CyanString ("🔌" ))
510+
511+ // GraphQL
512+ if graphqlPhase , ok := result .PhaseResults ["graphql" ]; ok {
513+ if graphqlPhase .Status == "completed" {
514+ if graphqlPhase .Findings > 0 {
515+ fmt .Printf (" • GraphQL introspection: %s (%d findings)\n " ,
516+ color .RedString ("✗ Issues found" ), graphqlPhase .Findings )
517+ } else {
518+ endpointCount := 1 // Default
519+ if graphqlPhase .Findings == 0 {
520+ fmt .Printf (" • GraphQL introspection: %s\n " ,
521+ color .GreenString ("✓ Tested %d endpoint, no issues" , endpointCount ))
522+ }
523+ }
524+ }
525+ } else {
526+ fmt .Printf (" • GraphQL testing: %s (no GraphQL endpoints found)\n " ,
527+ color .YellowString ("⊘ Not applicable" ))
528+ }
529+
530+ // REST API
531+ if restapiPhase , ok := result .PhaseResults ["rest_api" ]; ok {
532+ if restapiPhase .Status == "completed" {
533+ if restapiPhase .Findings > 0 {
534+ fmt .Printf (" • REST API security: %s (%d findings)\n " ,
535+ color .RedString ("✗ Issues found" ), restapiPhase .Findings )
536+ } else {
537+ fmt .Printf (" • REST API security: %s\n " ,
538+ color .GreenString ("✓ No issues found" ))
539+ }
540+ }
541+ } else {
542+ fmt .Printf (" • REST API testing: %s (API testing disabled)\n " ,
543+ color .YellowString ("⊘ Skipped" ))
544+ }
545+
546+ // Access Control Testing
547+ fmt .Printf ("\n %s Access Control Testing:\n " , color .CyanString ("🔒" ))
548+
549+ // IDOR
550+ if idorPhase , ok := result .PhaseResults ["idor" ]; ok {
551+ if idorPhase .Status == "completed" {
552+ if idorPhase .Findings > 0 {
553+ fmt .Printf (" • IDOR testing: %s (%d findings)\n " ,
554+ color .RedString ("✗ Vulnerabilities found" ), idorPhase .Findings )
555+ } else {
556+ fmt .Printf (" • IDOR testing: %s\n " ,
557+ color .GreenString ("✓ No issues found" ))
558+ }
559+ }
560+ } else {
561+ fmt .Printf (" • IDOR testing: %s (no suitable endpoints found)\n " ,
562+ color .YellowString ("⊘ Not applicable" ))
563+ }
564+
565+ // SCIM
566+ if scimPhase , ok := result .PhaseResults ["scim" ]; ok {
567+ if scimPhase .Status == "completed" {
568+ if scimPhase .Findings > 0 {
569+ fmt .Printf (" • SCIM vulnerabilities: %s (%d findings)\n " ,
570+ color .RedString ("✗ Issues found" ), scimPhase .Findings )
571+ } else {
572+ fmt .Printf (" • SCIM vulnerabilities: %s\n " ,
573+ color .GreenString ("✓ No issues found" ))
574+ }
575+ }
576+ } else {
577+ fmt .Printf (" • SCIM testing: %s (no SCIM endpoints found)\n " ,
578+ color .YellowString ("⊘ Not applicable" ))
579+ }
580+
581+ // Service Fingerprinting
582+ fmt .Printf ("\n %s Service Fingerprinting:\n " , color .CyanString ("🔍" ))
583+ if nmapPhase , ok := result .PhaseResults ["nmap" ]; ok {
584+ if nmapPhase .Status == "completed" {
585+ hostsScanned := 1 // Default
586+ if nmapPhase .Findings > 0 {
587+ fmt .Printf (" • Nmap scan: %s (%d hosts, %d services found)\n " ,
588+ color .GreenString ("✓ Completed" ), hostsScanned , nmapPhase .Findings )
589+ } else {
590+ fmt .Printf (" • Nmap scan: %s (%d host)\n " ,
591+ color .GreenString ("✓ Completed" ), hostsScanned )
592+ }
593+ } else if nmapPhase .Status == "failed" {
594+ fmt .Printf (" • Nmap scan: %s\n " ,
595+ color .RedString ("✗ Failed" ))
596+ if nmapPhase .Error != "" {
597+ fmt .Printf (" Error: %s\n " , color .RedString (nmapPhase .Error ))
598+ }
599+ }
600+ } else {
601+ fmt .Printf (" • Nmap scan: %s (service fingerprinting disabled)\n " ,
602+ color .YellowString ("⊘ Skipped" ))
603+ }
604+
605+ // Nuclei Scanning
606+ if nucleiPhase , ok := result .PhaseResults ["nuclei" ]; ok {
607+ if nucleiPhase .Status == "completed" {
608+ if nucleiPhase .Findings > 0 {
609+ fmt .Printf (" • Nuclei CVE scan: %s (%d findings)\n " ,
610+ color .RedString ("✗ Vulnerabilities found" ), nucleiPhase .Findings )
611+ } else {
612+ fmt .Printf (" • Nuclei CVE scan: %s\n " ,
613+ color .GreenString ("✓ No CVEs found" ))
614+ }
615+ }
616+ } else {
617+ fmt .Printf (" • Nuclei scanning: %s (nuclei not installed)\n " ,
618+ color .YellowString ("⊘ Skipped" ))
619+ }
620+
621+ // Summary
622+ fmt .Println ()
623+ totalCategories := 0
624+ testedCategories := 0
625+
626+ for _ , phase := range []string {"auth" , "graphql" , "rest_api" , "idor" , "scim" , "nmap" , "nuclei" } {
627+ totalCategories ++
628+ if pr , ok := result .PhaseResults [phase ]; ok && pr .Status == "completed" {
629+ testedCategories ++
630+ }
631+ }
632+
633+ fmt .Printf (" Summary: %s/%s test categories executed, %s total findings\n \n " ,
634+ color .CyanString ("%d" , testedCategories ),
635+ color .CyanString ("%d" , totalCategories ),
636+ color .GreenString ("%d" , result .TotalFindings ),
637+ )
638+ }
639+
275640// Note: Helper functions (colorStatus, colorSeverity, displayTopFindings, etc.)
276641// are now in display_helpers.go to avoid duplication across commands
0 commit comments