feat(modules): legacy shodan scan

Converted legacy Go shodan scan to be able to run as module.
This commit is contained in:
vmfunc
2026-01-07 13:05:08 +01:00
parent f309198f69
commit 0383c49bbd
2 changed files with 160 additions and 1 deletions
+3 -1
View File
@@ -12,8 +12,10 @@
package builtin
import "github.com/dropalldatabases/sif/internal/modules"
// Register registers all Go-based built-in scans as modules.
// Allows complex Go scans to participate in the module system
func Register() {
// Built-in modules will be registered here
modules.Register(&ShodanModule{})
}
+157
View File
@@ -0,0 +1,157 @@
/*
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
: :
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
: ▄█ █ █▀ · BSD 3-Clause License :
: :
: (c) 2022-2025 vmfunc, xyzeva, :
: lunchcat alumni & contributors :
: :
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
*/
package builtin
import (
"context"
"fmt"
"github.com/dropalldatabases/sif/internal/modules"
"github.com/dropalldatabases/sif/internal/scan"
"strings"
)
type ShodanModule struct{}
func (m *ShodanModule) Info() modules.Info {
return modules.Info{
ID: "shodan-lookup",
Name: "Shodan Host Intelligence",
Author: "sif",
Severity: "info",
Description: "Queries Shodan API for host information, open ports, and vulnerabilities (requires SHODAN_API_KEY)",
Tags: []string{"recon", "osint", "shodan", "vulns"},
}
}
func (m *ShodanModule) Type() modules.ModuleType {
return modules.TypeScript
}
func (m *ShodanModule) Execute(ctx context.Context, target string, opts modules.Options) (*modules.Result, error) {
// Call existing legacy scan.Shodan function
shodanResult, err := scan.Shodan(target, opts.Timeout, opts.LogDir)
if err != nil {
return nil, err
}
result := &modules.Result{
ModuleID: m.Info().ID,
Target: target,
Findings: []modules.Finding{},
}
// If nothing returned, return empty result
if shodanResult == nil || shodanResult.IP == "" {
return result, nil
}
// Create main finding
evidence := fmt.Sprintf("Shodan data found for %s", shodanResult.IP)
severity := "info"
if len(shodanResult.Vulns) > 0 {
severity = "high"
evidence = fmt.Sprintf("Host %s has %d known vulnerabilities", shodanResult.IP, len(shodanResult.Vulns))
}
finding := modules.Finding{
URL: target,
Severity: severity,
Evidence: evidence,
Extracted: map[string]string{
"ip": shodanResult.IP,
},
}
// Add hostnames
if len(shodanResult.Hostnames) > 0 {
finding.Extracted["hostnames"] = strings.Join(shodanResult.Hostnames, ", ")
}
// Add organization info
if shodanResult.Organization != "" {
finding.Extracted["organization"] = shodanResult.Organization
}
// Add ISP info
if shodanResult.ISP != "" {
finding.Extracted["isp"] = shodanResult.ISP
}
// Add ASN
if shodanResult.ASN != "" {
finding.Extracted["asn"] = shodanResult.ASN
}
// Add location
if shodanResult.Country != "" {
location := shodanResult.Country
if shodanResult.City != "" {
location = shodanResult.City + ", " + shodanResult.Country
}
finding.Extracted["location"] = location
}
// Add OS
if shodanResult.OS != "" {
finding.Extracted["os"] = shodanResult.OS
}
// Add open ports
if len(shodanResult.Ports) > 0 {
portStrs := make([]string, len(shodanResult.Ports))
for i, port := range shodanResult.Ports {
portStrs[i] = fmt.Sprintf("%d", port)
}
finding.Extracted["open_ports"] = strings.Join(portStrs, ", ")
finding.Extracted["port_count"] = fmt.Sprintf("%d", len(shodanResult.Ports))
}
// Add vulnerabilities
if len(shodanResult.Vulns) > 0 {
finding.Extracted["vulnerabilities"] = strings.Join(shodanResult.Vulns, ", ")
finding.Extracted["vuln_count"] = fmt.Sprintf("%d", len(shodanResult.Vulns))
}
// Add last update
if shodanResult.LastUpdate != "" {
finding.Extracted["last_update"] = shodanResult.LastUpdate
}
// Add service count
if len(shodanResult.Services) > 0 {
finding.Extracted["service_count"] = fmt.Sprintf("%d", len(shodanResult.Services))
// Add service details
serviceDetails := make([]string, 0, len(shodanResult.Services))
for _, service := range shodanResult.Services {
detail := fmt.Sprintf("%d/%s", service.Port, service.Protocol)
if service.Product != "" {
detail += " " + service.Product
if service.Version != "" {
detail += " " + service.Version
}
}
serviceDetails = append(serviceDetails, detail)
}
finding.Extracted["services"] = strings.Join(serviceDetails, "; ")
}
result.Findings = append(result.Findings, finding)
return result, nil
}