diff --git a/Core/PortInfo.go b/Core/PortInfo.go index fe582aa..bec4e86 100644 --- a/Core/PortInfo.go +++ b/Core/PortInfo.go @@ -9,56 +9,58 @@ import ( "time" ) -// 服务信息结构 +// ServiceInfo 定义服务识别的结果信息 type ServiceInfo struct { - Name string // 服务名称 - Banner string // 服务横幅 - Version string // 版本信息 - Extras map[string]string // 额外信息 + Name string // 服务名称,如 http、ssh 等 + Banner string // 服务返回的横幅信息 + Version string // 服务版本号 + Extras map[string]string // 其他额外信息,如操作系统、产品名等 } -// Result 结构体 +// Result 定义单次探测的结果 type Result struct { - Service Service - Banner string - Extras map[string]string - Send []byte // 发送的数据 - Recv []byte // 接收到的数据 + Service Service // 识别出的服务信息 + Banner string // 服务横幅 + Extras map[string]string // 额外信息 + Send []byte // 发送的探测数据 + Recv []byte // 接收到的响应数据 } +// Service 定义服务的基本信息 type Service struct { - Name string - Extras map[string]string + Name string // 服务名称 + Extras map[string]string // 服务的额外属性 } -// 扫描器相关结构 +// Info 定义单个端口探测的上下文信息 type Info struct { - Address string - Port int - Conn net.Conn - Result Result - Found bool + Address string // 目标IP地址 + Port int // 目标端口 + Conn net.Conn // 网络连接 + Result Result // 探测结果 + Found bool // 是否成功识别服务 } +// PortInfoScanner 定义端口服务识别器 type PortInfoScanner struct { - Address string - Port int - Conn net.Conn - Timeout time.Duration - info *Info + Address string // 目标IP地址 + Port int // 目标端口 + Conn net.Conn // 网络连接 + Timeout time.Duration // 超时时间 + info *Info // 探测上下文 } -// 预定义探测器 +// 预定义的基础探测器 var ( - null = new(Probe) - common = new(Probe) + null = new(Probe) // 空探测器,用于基本协议识别 + common = new(Probe) // 通用探测器,用于常见服务识别 ) -// NewPortInfoScanner 创建新的端口服务识别器 +// NewPortInfoScanner 创建新的端口服务识别器实例 func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration) *PortInfoScanner { return &PortInfoScanner{ Address: addr, - Port: port, + Port: port, Conn: conn, Timeout: timeout, info: &Info{ @@ -72,12 +74,12 @@ func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Durat } } -// Identify 识别端口服务 +// Identify 执行服务识别,返回识别结果 func (s *PortInfoScanner) Identify() (*ServiceInfo, error) { Common.LogDebug(fmt.Sprintf("开始识别服务 %s:%d", s.Address, s.Port)) s.info.PortInfo() - // 转换识别结果 + // 构造返回结果 serviceInfo := &ServiceInfo{ Name: s.info.Result.Service.Name, Banner: s.info.Result.Banner, @@ -94,13 +96,13 @@ func (s *PortInfoScanner) Identify() (*ServiceInfo, error) { return serviceInfo, nil } -// PortInfo 用于获取端口服务信息 +// PortInfo 执行端口服务识别的主要逻辑 func (i *Info) PortInfo() { - // 首次尝试读取响应 + // 1. 首先尝试读取服务的初始响应 if response, err := i.Read(); err == nil && len(response) > 0 { Common.LogDebug(fmt.Sprintf("收到初始响应: %d 字节", len(response))) - // 依次使用 null 和 common 探测器检查响应 + // 使用基础探测器检查响应 Common.LogDebug("尝试使用基础探测器(null/common)检查响应") if i.tryProbes(response, []*Probe{null, common}) { Common.LogDebug("基础探测器匹配成功") @@ -111,10 +113,10 @@ func (i *Info) PortInfo() { Common.LogDebug(fmt.Sprintf("读取初始响应失败: %v", err)) } - // 记录已使用的探测器 + // 记录已使用的探测器,避免重复使用 usedProbes := make(map[string]struct{}) - // 处理特定端口映射的探测 + // 2. 尝试使用端口专用探测器 Common.LogDebug(fmt.Sprintf("尝试使用端口 %d 的专用探测器", i.Port)) if i.processPortMapProbes(usedProbes) { Common.LogDebug("端口专用探测器匹配成功") @@ -122,7 +124,7 @@ func (i *Info) PortInfo() { } Common.LogDebug("端口专用探测器未匹配") - // 使用默认探测器进行检测 + // 3. 使用默认探测器列表 Common.LogDebug("尝试使用默认探测器列表") if i.processDefaultProbes(usedProbes) { Common.LogDebug("默认探测器匹配成功") @@ -130,14 +132,14 @@ func (i *Info) PortInfo() { } Common.LogDebug("默认探测器未匹配") - // 如果未能识别服务,标记为未知 + // 4. 如果所有探测都失败,标记为未知服务 if strings.TrimSpace(i.Result.Service.Name) == "" { - Common.LogDebug("未识别出服务,标记为 unknown") + Common.LogDebug("未识别出服务,标记为 unknown") i.Result.Service.Name = "unknown" } } -// tryProbes 尝试使用给定的探测器列表检查响应 +// tryProbes 尝试使用指定的探测器列表检查响应 func (i *Info) tryProbes(response []byte, probes []*Probe) bool { for _, probe := range probes { Common.LogDebug(fmt.Sprintf("尝试探测器: %s", probe.Name)) @@ -150,16 +152,18 @@ func (i *Info) tryProbes(response []byte, probes []*Probe) bool { return false } -// processPortMapProbes 处理端口映射中的探测器 +// processPortMapProbes 处理端口映射中的专用探测器 func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool { + // 检查是否存在端口专用探测器 if len(Common.PortMap[i.Port]) == 0 { Common.LogDebug(fmt.Sprintf("端口 %d 没有专用探测器", i.Port)) return false } + // 遍历端口专用探测器 for _, name := range Common.PortMap[i.Port] { Common.LogDebug(fmt.Sprintf("尝试端口专用探测器: %s", name)) - usedProbes[name] = struct{}{} + usedProbes[name] = struct{}{} probe := v.ProbesMapKName[name] // 解码探测数据 @@ -169,7 +173,7 @@ func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool { continue } - // 建立连接获取响应 + // 发送探测数据并获取响应 Common.LogDebug(fmt.Sprintf("发送探测数据: %d 字节", len(probeData))) if response := i.Connect(probeData); len(response) > 0 { Common.LogDebug(fmt.Sprintf("收到响应: %d 字节", len(response))) @@ -198,11 +202,12 @@ func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool { return false } -// processDefaultProbes 处理默认探测器 +// processDefaultProbes 处理默认探测器列表 func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool { failCount := 0 - const maxFailures = 10 + const maxFailures = 10 // 最大失败次数 + // 遍历默认探测器列表 for _, name := range Common.DefaultMap { // 跳过已使用的探测器 if _, used := usedProbes[name]; used { @@ -215,7 +220,7 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool { continue } - // 建立连接获取响应 + // 发送探测数据并获取响应 response := i.Connect(probeData) if len(response) == 0 { failCount++ @@ -260,11 +265,11 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool { return false } -// GetInfo 分析响应数据并获取服务信息 +// GetInfo 分析响应数据并提取服务信息 func (i *Info) GetInfo(response []byte, probe *Probe) { - Common.LogDebug(fmt.Sprintf("开始分析响应数据,长度: %d", len(response))) + Common.LogDebug(fmt.Sprintf("开始分析响应数据,长度: %d", len(response))) - // 响应数据长度检查 + // 响应数据有效性检查 if len(response) <= 0 { Common.LogDebug("响应数据为空") return @@ -276,8 +281,8 @@ func (i *Info) GetInfo(response []byte, probe *Probe) { softFound bool ) - Common.LogDebug(fmt.Sprintf("处理探测器 %s 的主要匹配规则", probe.Name)) // 处理主要匹配规则 + Common.LogDebug(fmt.Sprintf("处理探测器 %s 的主要匹配规则", probe.Name)) if matched, match := i.processMatches(response, probe.Matchs); matched { Common.LogDebug("找到硬匹配") return @@ -304,14 +309,14 @@ func (i *Info) GetInfo(response []byte, probe *Probe) { // 处理未找到匹配的情况 if !i.Found { - Common.LogDebug("未找到硬匹配,处理未匹配情况") + Common.LogDebug("未找到硬匹配,处理未匹配情况") i.handleNoMatch(response, result, softFound, softMatch) } } // processMatches 处理匹配规则集 func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match) { - Common.LogDebug(fmt.Sprintf("开始处理匹配规则,共 %d 条", len(*matches))) + Common.LogDebug(fmt.Sprintf("开始处理匹配规则,共 %d 条", len(*matches))) var softMatch *Match for _, match := range *matches { @@ -387,7 +392,7 @@ func (i *Info) Connect(msg []byte) []byte { return reply } -const WrTimeout = 5 // 默认超时时间(秒) +const WrTimeout = 5 // 默认读写超时时间(秒) // Write 写入数据到连接 func (i *Info) Write(msg []byte) error { @@ -402,7 +407,7 @@ func (i *Info) Write(msg []byte) error { _, err := i.Conn.Write(msg) if err != nil && strings.Contains(err.Error(), "close") { i.Conn.Close() - // 重试连接 + // 连接关闭时重试 i.Conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second) if err == nil { i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout))) @@ -430,7 +435,6 @@ func (i *Info) Read() ([]byte, error) { // 读取数据 result, err := readFromConn(i.Conn) if err != nil && strings.Contains(err.Error(), "close") { - // 连接关闭的错误处理 return result, err } @@ -444,7 +448,7 @@ func (i *Info) Read() ([]byte, error) { // readFromConn 从连接读取数据的辅助函数 func readFromConn(conn net.Conn) ([]byte, error) { - size := 2 * 1024 + size := 2 * 1024 // 读取缓冲区大小 var result []byte for { diff --git a/Core/PortScan.go b/Core/PortScan.go index 889a239..eb048f3 100644 --- a/Core/PortScan.go +++ b/Core/PortScan.go @@ -19,16 +19,21 @@ type Addr struct { // ScanResult 扫描结果 type ScanResult struct { Address string // IP地址 - Port int // 端口号 + Port int // 端口号 Service *ServiceInfo // 服务信息 } +// PortScan 执行端口扫描 +// hostslist: 待扫描的主机列表 +// ports: 待扫描的端口范围 +// timeout: 超时时间(秒) +// 返回活跃地址列表 func PortScan(hostslist []string, ports string, timeout int64) []string { var results []ScanResult - var aliveAddrs []string // 新增:存储活跃地址 + var aliveAddrs []string var mu sync.Mutex - // 解析端口列表 + // 解析并验证端口列表 probePorts := Common.ParsePort(ports) if len(probePorts) == 0 { Common.LogError(fmt.Sprintf("端口格式错误: %s", ports)) @@ -38,14 +43,14 @@ func PortScan(hostslist []string, ports string, timeout int64) []string { // 排除指定端口 probePorts = excludeNoPorts(probePorts) - // 创建通道 + // 初始化并发控制 workers := Common.ThreadNum - addrs := make(chan Addr, 100) - scanResults := make(chan ScanResult, 100) + addrs := make(chan Addr, 100) // 待扫描地址通道 + scanResults := make(chan ScanResult, 100) // 扫描结果通道 var wg sync.WaitGroup var workerWg sync.WaitGroup - // 启动扫描协程 + // 启动扫描工作协程 for i := 0; i < workers; i++ { workerWg.Add(1) go func() { @@ -56,7 +61,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string { }() } - // 接收扫描结果 + // 启动结果处理协程 var resultWg sync.WaitGroup resultWg.Add(1) go func() { @@ -64,14 +69,13 @@ func PortScan(hostslist []string, ports string, timeout int64) []string { for result := range scanResults { mu.Lock() results = append(results, result) - // 构造活跃地址字符串 aliveAddr := fmt.Sprintf("%s:%d", result.Address, result.Port) aliveAddrs = append(aliveAddrs, aliveAddr) mu.Unlock() } }() - // 添加扫描目标 + // 分发扫描任务 for _, port := range probePorts { for _, host := range hostslist { wg.Add(1) @@ -79,6 +83,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string { } } + // 等待所有任务完成 close(addrs) workerWg.Wait() wg.Wait() @@ -88,6 +93,11 @@ func PortScan(hostslist []string, ports string, timeout int64) []string { return aliveAddrs } +// PortConnect 执行单个端口连接检测 +// addr: 待检测的地址 +// results: 结果通道 +// timeout: 超时时间 +// wg: 等待组 func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.WaitGroup) { defer wg.Done() @@ -95,6 +105,7 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W var err error var conn net.Conn + // 尝试建立TCP连接 conn, err = Common.WrapperTcpWithTimeout("tcp4", fmt.Sprintf("%s:%v", addr.ip, addr.port), time.Duration(timeout)*time.Second) @@ -107,10 +118,11 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W return } + // 记录开放端口 address := fmt.Sprintf("%s:%d", addr.ip, addr.port) Common.LogSuccess(fmt.Sprintf("端口开放 %s", address)) - // 保存端口开放信息 + // 保存端口扫描结果 portResult := &Common.ScanResult{ Time: time.Now(), Type: Common.PORT, @@ -122,19 +134,19 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W } Common.SaveResult(portResult) - // 创建扫描结果 + // 构造扫描结果 result := ScanResult{ Address: addr.ip, Port: addr.port, } - // 服务识别 + // 执行服务识别 if !Common.SkipFingerprint && conn != nil { scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second) if serviceInfo, err := scanner.Identify(); err == nil { result.Service = serviceInfo - // 构造日志消息 + // 构造服务识别日志 var logMsg strings.Builder logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address)) @@ -146,27 +158,36 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version)) } - // 构造服务详情 + // 收集服务详细信息 details := map[string]interface{}{ "port": addr.port, "service": serviceInfo.Name, } + // 添加版本信息 if serviceInfo.Version != "" { details["version"] = serviceInfo.Version } + + // 添加产品信息 if v, ok := serviceInfo.Extras["vendor_product"]; ok && v != "" { details["product"] = v logMsg.WriteString(fmt.Sprintf(" 产品:%s", v)) } + + // 添加操作系统信息 if v, ok := serviceInfo.Extras["os"]; ok && v != "" { details["os"] = v logMsg.WriteString(fmt.Sprintf(" 系统:%s", v)) } + + // 添加额外信息 if v, ok := serviceInfo.Extras["info"]; ok && v != "" { details["info"] = v logMsg.WriteString(fmt.Sprintf(" 信息:%s", v)) } + + // 添加Banner信息 if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 { details["banner"] = strings.TrimSpace(serviceInfo.Banner) logMsg.WriteString(fmt.Sprintf(" Banner:[%s]", strings.TrimSpace(serviceInfo.Banner))) @@ -190,6 +211,9 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W } // NoPortScan 生成端口列表(不进行扫描) +// hostslist: 主机列表 +// ports: 端口范围 +// 返回地址列表 func NoPortScan(hostslist []string, ports string) []string { var AliveAddress []string @@ -208,6 +232,8 @@ func NoPortScan(hostslist []string, ports string) []string { } // excludeNoPorts 排除指定的端口 +// ports: 原始端口列表 +// 返回过滤后的端口列表 func excludeNoPorts(ports []int) []int { noPorts := Common.ParsePort(Common.ExcludePorts) if len(noPorts) == 0 { @@ -220,11 +246,12 @@ func excludeNoPorts(ports []int) []int { temp[port] = struct{}{} } + // 移除需要排除的端口 for _, port := range noPorts { delete(temp, port) } - // 转换为切片并排序 + // 转换为有序切片 var newPorts []int for port := range temp { newPorts = append(newPorts, port) diff --git a/Core/Registry.go b/Core/Registry.go index 021e7cd..44fc693 100644 --- a/Core/Registry.go +++ b/Core/Registry.go @@ -5,8 +5,11 @@ import ( "github.com/shadow1ng/fscan/Plugins" ) +// init 初始化并注册所有扫描插件 +// 包括标准端口服务扫描、特殊扫描类型和本地信息收集等 func init() { - // 注册标准端口服务扫描 + // 1. 标准网络服务扫描插件 + // 文件传输和远程访问服务 Common.RegisterPlugin("ftp", Common.ScanPlugin{ Name: "FTP", Ports: []int{21}, @@ -14,7 +17,7 @@ func init() { }) Common.RegisterPlugin("ssh", Common.ScanPlugin{ - Name: "SSH", + Name: "SSH", Ports: []int{22, 2222}, ScanFunc: Plugins.SshScan, }) @@ -25,6 +28,7 @@ func init() { ScanFunc: Plugins.TelnetScan, }) + // Windows网络服务 Common.RegisterPlugin("findnet", Common.ScanPlugin{ Name: "FindNet", Ports: []int{135}, @@ -43,39 +47,41 @@ func init() { ScanFunc: Plugins.SmbScan, }) + // 数据库服务 Common.RegisterPlugin("mssql", Common.ScanPlugin{ Name: "MSSQL", - Ports: []int{1433, 1434}, // 支持多个端口 + Ports: []int{1433, 1434}, ScanFunc: Plugins.MssqlScan, }) Common.RegisterPlugin("oracle", Common.ScanPlugin{ Name: "Oracle", - Ports: []int{1521, 1522, 1526}, // Oracle 可能的多个端口 + Ports: []int{1521, 1522, 1526}, ScanFunc: Plugins.OracleScan, }) Common.RegisterPlugin("mysql", Common.ScanPlugin{ Name: "MySQL", - Ports: []int{3306, 3307, 13306, 33306}, // MySQL 可能的端口 + Ports: []int{3306, 3307, 13306, 33306}, ScanFunc: Plugins.MysqlScan, }) + // 中间件和消息队列服务 Common.RegisterPlugin("elasticsearch", Common.ScanPlugin{ Name: "Elasticsearch", - Ports: []int{9200, 9300}, // Elasticsearch 默认HTTP和Transport端口 + Ports: []int{9200, 9300}, ScanFunc: Plugins.ElasticScan, }) Common.RegisterPlugin("rabbitmq", Common.ScanPlugin{ Name: "RabbitMQ", - Ports: []int{5672, 5671, 15672, 15671}, // AMQP和管理端口 + Ports: []int{5672, 5671, 15672, 15671}, ScanFunc: Plugins.RabbitMQScan, }) Common.RegisterPlugin("kafka", Common.ScanPlugin{ Name: "Kafka", - Ports: []int{9092, 9093}, // Kafka默认端口和SSL端口 + Ports: []int{9092, 9093}, ScanFunc: Plugins.KafkaScan, }) @@ -85,12 +91,14 @@ func init() { ScanFunc: Plugins.ActiveMQScan, }) + // 目录和认证服务 Common.RegisterPlugin("ldap", Common.ScanPlugin{ Name: "LDAP", - Ports: []int{389, 636}, // LDAP标准端口和LDAPS端口 + Ports: []int{389, 636}, ScanFunc: Plugins.LDAPScan, }) + // 邮件服务 Common.RegisterPlugin("smtp", Common.ScanPlugin{ Name: "SMTP", Ports: []int{25, 465, 587}, @@ -99,34 +107,37 @@ func init() { Common.RegisterPlugin("imap", Common.ScanPlugin{ Name: "IMAP", - Ports: []int{143, 993}, // 143是标准端口,993是SSL端口 + Ports: []int{143, 993}, ScanFunc: Plugins.IMAPScan, }) Common.RegisterPlugin("pop3", Common.ScanPlugin{ Name: "POP3", - Ports: []int{110, 995}, // POP3和POP3S端口 + Ports: []int{110, 995}, ScanFunc: Plugins.POP3Scan, }) + // 网络管理和监控服务 Common.RegisterPlugin("snmp", Common.ScanPlugin{ Name: "SNMP", - Ports: []int{161, 162}, // SNMP默认端口 + Ports: []int{161, 162}, ScanFunc: Plugins.SNMPScan, }) Common.RegisterPlugin("modbus", Common.ScanPlugin{ Name: "Modbus", - Ports: []int{502, 5020}, // Modbus 默认端口 + Ports: []int{502, 5020}, ScanFunc: Plugins.ModbusScan, }) + // 数据同步和备份服务 Common.RegisterPlugin("rsync", Common.ScanPlugin{ Name: "Rsync", Ports: []int{873}, ScanFunc: Plugins.RsyncScan, }) + // NoSQL数据库 Common.RegisterPlugin("cassandra", Common.ScanPlugin{ Name: "Cassandra", Ports: []int{9042}, @@ -139,6 +150,7 @@ func init() { ScanFunc: Plugins.Neo4jScan, }) + // 远程桌面和显示服务 Common.RegisterPlugin("rdp", Common.ScanPlugin{ Name: "RDP", Ports: []int{3389, 13389, 33389}, @@ -147,19 +159,20 @@ func init() { Common.RegisterPlugin("postgres", Common.ScanPlugin{ Name: "PostgreSQL", - Ports: []int{5432, 5433}, // PostgreSQL 可能的端口 + Ports: []int{5432, 5433}, ScanFunc: Plugins.PostgresScan, }) Common.RegisterPlugin("vnc", Common.ScanPlugin{ Name: "VNC", - Ports: []int{5900, 5901, 5902}, // VNC 可能的端口 + Ports: []int{5900, 5901, 5902}, ScanFunc: Plugins.VncScan, }) + // 缓存和键值存储服务 Common.RegisterPlugin("redis", Common.ScanPlugin{ Name: "Redis", - Ports: []int{6379, 6380, 16379}, // Redis 可能的端口 + Ports: []int{6379, 6380, 16379}, ScanFunc: Plugins.RedisScan, }) @@ -177,11 +190,11 @@ func init() { Common.RegisterPlugin("mongodb", Common.ScanPlugin{ Name: "MongoDB", - Ports: []int{27017, 27018}, // MongoDB 可能的端口 + Ports: []int{27017, 27018}, ScanFunc: Plugins.MongodbScan, }) - // 注册特殊扫描类型 + // 2. 特殊漏洞扫描插件 Common.RegisterPlugin("ms17010", Common.ScanPlugin{ Name: "MS17010", Ports: []int{445}, @@ -194,19 +207,20 @@ func init() { ScanFunc: Plugins.SmbGhost, }) - // web 相关插件添加 WebPorts 配置 + // 3. Web应用扫描插件 Common.RegisterPlugin("webtitle", Common.ScanPlugin{ Name: "WebTitle", - Ports: Common.ParsePortsFromString(Common.WebPorts), // 将 WebPorts 字符串解析为端口数组 + Ports: Common.ParsePortsFromString(Common.WebPorts), ScanFunc: Plugins.WebTitle, }) Common.RegisterPlugin("webpoc", Common.ScanPlugin{ Name: "WebPoc", - Ports: Common.ParsePortsFromString(Common.WebPorts), // 将 WebPorts 字符串解析为端口数组 + Ports: Common.ParsePortsFromString(Common.WebPorts), ScanFunc: Plugins.WebPoc, }) + // 4. Windows系统专用插件 Common.RegisterPlugin("smb2", Common.ScanPlugin{ Name: "SMBScan2", Ports: []int{445}, @@ -219,21 +233,22 @@ func init() { ScanFunc: Plugins.WmiExec, }) + // 5. 本地信息收集插件 Common.RegisterPlugin("localinfo", Common.ScanPlugin{ Name: "LocalInfo", - Ports: []int{}, // 本地信息收集不需要端口 + Ports: []int{}, ScanFunc: Plugins.LocalInfoScan, }) Common.RegisterPlugin("dcinfo", Common.ScanPlugin{ Name: "DCInfo", - Ports: []int{}, // 本地信息收集不需要端口 + Ports: []int{}, ScanFunc: Plugins.DCInfoScan, }) Common.RegisterPlugin("minidump", Common.ScanPlugin{ Name: "MiniDump", - Ports: []int{}, // 本地信息收集不需要端口 + Ports: []int{}, ScanFunc: Plugins.MiniDump, }) } diff --git a/Core/Scanner.go b/Core/Scanner.go index 17d15ca..8720867 100644 --- a/Core/Scanner.go +++ b/Core/Scanner.go @@ -13,76 +13,89 @@ import ( "time" ) -// 定义在文件开头 +// 全局变量定义 var ( LocalScan bool // 本地扫描模式标识 WebScan bool // Web扫描模式标识 ) // Scan 执行扫描主流程 +// info: 主机信息结构体,包含扫描目标的基本信息 func Scan(info Common.HostInfo) { Common.LogInfo("开始信息扫描") - // 初始化HTTP客户端 + // 初始化HTTP客户端配置 lib.Inithttp() + // 初始化并发控制 ch := make(chan struct{}, Common.ThreadNum) wg := sync.WaitGroup{} - // 执行扫描逻辑 + // 根据扫描模式执行不同的扫描策略 switch { case Common.LocalMode: + // 本地信息收集模式 executeLocalScan(info, &ch, &wg) case len(Common.URLs) > 0: + // Web扫描模式 executeWebScan(info, &ch, &wg) default: + // 主机扫描模式 executeHostScan(info, &ch, &wg) } - // 等待扫描完成 + // 等待所有扫描任务完成 finishScan(&wg) } -// 执行本地扫描 +// executeLocalScan 执行本地扫描 +// info: 主机信息 +// ch: 并发控制通道 +// wg: 等待组 func executeLocalScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { Common.LogInfo("执行本地信息收集") - // 定义本地模式允许的插件 + // 获取本地模式支持的插件列表 validLocalPlugins := getValidPlugins(Common.ModeLocal) - // 校验扫描模式 + // 验证扫描模式的合法性 if err := validateScanMode(validLocalPlugins, Common.ModeLocal); err != nil { Common.LogError(err.Error()) return } + // 输出使用的插件信息 if Common.ScanMode == Common.ModeLocal { Common.LogInfo("使用全部本地插件") } else { Common.LogInfo(fmt.Sprintf("使用插件: %s", Common.ScanMode)) } - // 执行扫描 + // 执行扫描任务 executeScans([]Common.HostInfo{info}, ch, wg) } -// 执行Web扫描 +// executeWebScan 执行Web扫描 +// info: 主机信息 +// ch: 并发控制通道 +// wg: 等待组 func executeWebScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { Common.LogInfo("开始Web扫描") - // 从 pluginGroups 获取Web模式允许的插件 + // 获取Web模式支持的插件列表 validWebPlugins := getValidPlugins(Common.ModeWeb) - // 校验扫描模式 + // 验证扫描模式的合法性 if err := validateScanMode(validWebPlugins, Common.ModeWeb); err != nil { Common.LogError(err.Error()) return } - // 创建目标URL信息 + // 处理目标URL列表 var targetInfos []Common.HostInfo for _, url := range Common.URLs { urlInfo := info + // 确保URL包含协议头 if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") { url = "http://" + url } @@ -90,23 +103,29 @@ func executeWebScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) targetInfos = append(targetInfos, urlInfo) } + // 输出使用的插件信息 if Common.ScanMode == Common.ModeWeb { Common.LogInfo("使用全部Web插件") } else { Common.LogInfo(fmt.Sprintf("使用插件: %s", Common.ScanMode)) } - // 执行扫描 + // 执行扫描任务 executeScans(targetInfos, ch, wg) } -// 执行主机扫描 +// executeHostScan 执行主机扫描 +// info: 主机信息 +// ch: 并发控制通道 +// wg: 等待组 func executeHostScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { + // 验证扫描目标 if info.Host == "" { Common.LogError("未指定扫描目标") return } + // 解析目标主机 hosts, err := Common.ParseIP(info.Host, Common.HostsFile, Common.ExcludeHosts) if err != nil { Common.LogError(fmt.Sprintf("解析主机错误: %v", err)) @@ -117,7 +136,9 @@ func executeHostScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup executeScan(hosts, info, ch, wg) } -// 获取合法的插件列表 +// getValidPlugins 获取指定模式下的有效插件列表 +// mode: 扫描模式 +// 返回: 有效插件映射表 func getValidPlugins(mode string) map[string]bool { validPlugins := make(map[string]bool) for _, plugin := range Common.PluginGroups[mode] { @@ -126,7 +147,10 @@ func getValidPlugins(mode string) map[string]bool { return validPlugins } -// 校验扫描模式是否有效 +// validateScanMode 验证扫描模式的合法性 +// validPlugins: 有效插件列表 +// mode: 扫描模式 +// 返回: 错误信息 func validateScanMode(validPlugins map[string]bool, mode string) error { if Common.ScanMode == "" || Common.ScanMode == "All" { Common.ScanMode = mode @@ -137,12 +161,16 @@ func validateScanMode(validPlugins map[string]bool, mode string) error { } // executeScan 执行主扫描流程 +// hosts: 目标主机列表 +// info: 主机信息 +// ch: 并发控制通道 +// wg: 等待组 func executeScan(hosts []string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { var targetInfos []Common.HostInfo - // 扫描主机和端口 + // 处理主机和端口扫描 if len(hosts) > 0 || len(Common.HostPort) > 0 { - // 处理活跃主机 + // 检查主机存活性 if shouldPingScan(hosts) { hosts = CheckLive(hosts, Common.UsePing) Common.LogInfo(fmt.Sprintf("存活主机数量: %d", len(hosts))) @@ -151,42 +179,48 @@ func executeScan(hosts []string, info Common.HostInfo, ch *chan struct{}, wg *sy } } - // 处理活跃端口 + // 获取存活端口 alivePorts := getAlivePorts(hosts) if len(alivePorts) > 0 { targetInfos = prepareTargetInfos(alivePorts, info) } } - // 添加 URL 扫描目标 + // 添加URL扫描目标 targetInfos = appendURLTargets(targetInfos, info) - // 如果有扫描目标,执行漏洞扫描 + // 执行漏洞扫描 if len(targetInfos) > 0 { Common.LogInfo("开始漏洞扫描") executeScans(targetInfos, ch, wg) } } -// shouldPingScan 判断是否需要进行 ping 扫描 +// shouldPingScan 判断是否需要执行ping扫描 +// hosts: 目标主机列表 +// 返回: 是否需要ping扫描 func shouldPingScan(hosts []string) bool { return (Common.DisablePing == false && len(hosts) > 1) || Common.IsICMPScan() } -// getAlivePorts 获取存活端口 +// getAlivePorts 获取存活端口列表 +// hosts: 目标主机列表 +// 返回: 存活端口列表 func getAlivePorts(hosts []string) []string { var alivePorts []string + + // 根据扫描模式选择端口扫描方式 if Common.IsWebScan() { alivePorts = NoPortScan(hosts, Common.Ports) } else if len(hosts) > 0 { alivePorts = PortScan(hosts, Common.Ports, Common.Timeout) Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts))) if Common.IsPortScan() { - return nil // 结束扫描 + return nil } } - // 合并传入的端口信息 + // 合并额外指定的端口 if len(Common.HostPort) > 0 { alivePorts = append(alivePorts, Common.HostPort...) alivePorts = Common.RemoveDuplicate(alivePorts) @@ -197,7 +231,10 @@ func getAlivePorts(hosts []string) []string { return alivePorts } -// appendURLTargets 添加 URL 扫描目标 +// appendURLTargets 添加URL扫描目标 +// targetInfos: 现有目标列表 +// baseInfo: 基础主机信息 +// 返回: 更新后的目标列表 func appendURLTargets(targetInfos []Common.HostInfo, baseInfo Common.HostInfo) []Common.HostInfo { for _, url := range Common.URLs { urlInfo := baseInfo @@ -208,6 +245,9 @@ func appendURLTargets(targetInfos []Common.HostInfo, baseInfo Common.HostInfo) [ } // prepareTargetInfos 准备扫描目标信息 +// alivePorts: 存活端口列表 +// baseInfo: 基础主机信息 +// 返回: 目标信息列表 func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common.HostInfo { var infos []Common.HostInfo for _, targetIP := range alivePorts { @@ -224,24 +264,27 @@ func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common. return infos } -// 扫描任务结构体定义 +// ScanTask 扫描任务结构体 type ScanTask struct { - pluginName string - target Common.HostInfo + pluginName string // 插件名称 + target Common.HostInfo // 目标信息 } // executeScans 执行扫描任务 +// targets: 目标列表 +// ch: 并发控制通道 +// wg: 等待组 func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { mode := Common.GetScanMode() - // 获取待执行的插件列表 + // 获取要执行的插件列表 pluginsToRun, isSinglePlugin := getPluginsToRun(mode) var tasks []ScanTask actualTasks := 0 loadedPlugins := make([]string, 0) - // 遍历目标,收集任务 + // 收集扫描任务 for _, target := range targets { targetPort, _ := strconv.Atoi(target.Ports) for _, pluginName := range pluginsToRun { @@ -259,22 +302,22 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro } } - // 去重并排序插件 + // 处理插件列表 finalPlugins := getUniquePlugins(loadedPlugins) - - // 输出加载的插件信息 Common.LogInfo(fmt.Sprintf("加载的插件: %s", strings.Join(finalPlugins, ", "))) // 初始化进度条 initializeProgressBar(actualTasks) - // 执行收集的任务 + // 执行扫描任务 for _, task := range tasks { AddScan(task.pluginName, task.target, ch, wg) } } -// 获取待执行插件列表 +// getPluginsToRun 获取要执行的插件列表 +// mode: 扫描模式 +// 返回: 插件列表和是否为单插件模式 func getPluginsToRun(mode string) ([]string, bool) { var pluginsToRun []string isSinglePlugin := false @@ -289,12 +332,17 @@ func getPluginsToRun(mode string) ([]string, bool) { return pluginsToRun, isSinglePlugin } -// 收集扫描任务 +// collectScanTasks 收集扫描任务 +// plugin: 插件信息 +// target: 目标信息 +// targetPort: 目标端口 +// pluginName: 插件名称 +// isSinglePlugin: 是否为单插件模式 +// 返回: 是否添加任务和任务列表 func collectScanTasks(plugin Common.ScanPlugin, target Common.HostInfo, targetPort int, pluginName string, isSinglePlugin bool) (bool, []ScanTask) { var tasks []ScanTask taskAdded := false - // Web模式特殊处理 if WebScan || LocalScan || isSinglePlugin || len(plugin.Ports) == 0 || plugin.HasPort(targetPort) { taskAdded = true tasks = append(tasks, ScanTask{ @@ -306,7 +354,9 @@ func collectScanTasks(plugin Common.ScanPlugin, target Common.HostInfo, targetPo return taskAdded, tasks } -// 获取去重后的插件列表 +// getUniquePlugins 获取去重后的插件列表 +// loadedPlugins: 已加载的插件列表 +// 返回: 去重并排序后的插件列表 func getUniquePlugins(loadedPlugins []string) []string { uniquePlugins := make(map[string]struct{}) for _, p := range loadedPlugins { @@ -322,7 +372,8 @@ func getUniquePlugins(loadedPlugins []string) []string { return finalPlugins } -// 初始化进度条 +// initializeProgressBar 初始化进度条 +// actualTasks: 实际任务数量 func initializeProgressBar(actualTasks int) { if Common.ShowProgress { Common.ProgressBar = progressbar.NewOptions(actualTasks, @@ -345,20 +396,24 @@ func initializeProgressBar(actualTasks int) { } // finishScan 完成扫描任务 +// wg: 等待组 func finishScan(wg *sync.WaitGroup) { wg.Wait() - // 确保进度条完成,只在存在进度条时调用 if Common.ProgressBar != nil { Common.ProgressBar.Finish() - fmt.Println() // 添加一个换行 + fmt.Println() } Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num)) } -// Mutex用于保护共享资源的并发访问 +// Mutex 用于保护共享资源的并发访问 var Mutex = &sync.Mutex{} // AddScan 添加扫描任务并启动扫描 +// plugin: 插件名称 +// info: 目标信息 +// ch: 并发控制通道 +// wg: 等待组 func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) { *ch <- struct{}{} wg.Add(1) @@ -369,18 +424,15 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa <-*ch }() - // 使用原子操作更新扫描计数 atomic.AddInt64(&Common.Num, 1) - - // 执行扫描插件 ScanFunc(&plugin, &info) - - // 更新扫描结束后的状态 updateScanProgress(&info) }() } // ScanFunc 执行扫描插件 +// name: 插件名称 +// info: 目标信息 func ScanFunc(name *string, info *Common.HostInfo) { defer func() { if err := recover(); err != nil { @@ -400,12 +452,11 @@ func ScanFunc(name *string, info *Common.HostInfo) { } // updateScanProgress 更新扫描进度 +// info: 目标信息 func updateScanProgress(info *Common.HostInfo) { - // 输出互斥锁更新进度条 Common.OutputMutex.Lock() atomic.AddInt64(&Common.End, 1) if Common.ProgressBar != nil { - // 清除当前行并更新进度条 fmt.Print("\033[2K\r") Common.ProgressBar.Add(1) }