github.com/chainreactors/fingers@v1.2.1/cmd/nmap/nmap.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "log" 7 "strings" 8 "sync" 9 "sync/atomic" 10 "time" 11 12 "github.com/chainreactors/fingers" 13 "github.com/chainreactors/fingers/common" 14 "github.com/chainreactors/fingers/resources" 15 "github.com/chainreactors/utils" 16 ) 17 18 // 扫描统计信息 19 type ScanStats struct { 20 TotalTargets int64 21 ScannedTargets int64 22 OpenPorts int64 23 IdentifiedPorts int64 24 StartTime time.Time 25 } 26 27 // 扫描结果 28 type ScanResult struct { 29 Host string 30 Port string 31 Open bool 32 Framework *common.Framework 33 Error error 34 } 35 36 func main() { 37 // 命令行参数 38 var ( 39 cidrFlag = flag.String("cidr", "127.0.0.1/32", "目标CIDR范围,例如: 192.168.1.0/24") 40 portFlag = flag.String("port", "1000-2000", "端口范围,例如: 80,443,1000-2000") 41 threadsFlag = flag.Int("threads", 100, "并发线程数") 42 timeoutFlag = flag.Int("timeout", 3, "扫描超时时间(秒)") 43 levelFlag = flag.Int("level", 1, "扫描深度级别(1-9)") 44 verboseFlag = flag.Bool("v", false, "详细输出模式") 45 outputFlag = flag.String("o", "", "输出文件路径") 46 ) 47 flag.Parse() 48 49 if *cidrFlag == "" || *portFlag == "" { 50 fmt.Println("使用方法:") 51 fmt.Println(" nmap -cidr 192.168.1.0/24 -port 22,80,443,1000-2000") 52 fmt.Println(" nmap -cidr 10.0.0.1 -port 80 -threads 200 -timeout 5") 53 flag.PrintDefaults() 54 return 55 } 56 57 fmt.Printf("🚀 启动nmap指纹扫描器\n") 58 fmt.Printf("目标: %s\n", *cidrFlag) 59 fmt.Printf("端口: %s\n", *portFlag) 60 fmt.Printf("线程: %d\n", *threadsFlag) 61 fmt.Printf("超时: %ds\n", *timeoutFlag) 62 fmt.Printf("级别: %d\n", *levelFlag) 63 64 // 解析CIDR和端口 65 ips, err := parseCIDR(*cidrFlag) 66 if err != nil { 67 log.Fatalf("解析CIDR失败: %v", err) 68 } 69 70 // 使用utils包解析端口 71 utils.PrePort, err = resources.LoadPorts() 72 if err != nil { 73 log.Fatalf("加载端口资源失败: %v", err) 74 } 75 var portList []string 76 portList = utils.ParsePortsString(*portFlag) 77 78 fmt.Printf("📊 目标统计: %d个IP, %d个端口, 共%d个扫描目标\n", 79 ips.Len(), len(portList), ips.Len()*len(portList)) 80 81 // 创建fingers引擎(只使用nmap引擎) 82 engine, err := fingers.NewEngine(fingers.NmapEngine) 83 if err != nil { 84 log.Fatalf("创建引擎失败: %v", err) 85 } 86 87 // 创建网络发送器 88 sender := common.NewServiceSender(time.Duration(*timeoutFlag) * time.Second) 89 90 // 初始化统计信息 91 stats := &ScanStats{ 92 TotalTargets: int64(ips.Len() * len(portList)), 93 StartTime: time.Now(), 94 } 95 96 // 创建任务通道和结果通道 97 taskChan := make(chan scanTask, *threadsFlag*2) 98 resultChan := make(chan ScanResult, *threadsFlag) 99 100 // 启动工作协程 101 var wg sync.WaitGroup 102 for i := 0; i < *threadsFlag; i++ { 103 wg.Add(1) 104 go worker(engine, sender, taskChan, resultChan, &wg, *levelFlag) 105 } 106 107 // 启动结果处理协程 108 go resultHandler(resultChan, stats, *verboseFlag, *outputFlag) 109 110 // 生成扫描任务 111 go func() { 112 defer close(taskChan) 113 for ip := range ips.Range() { 114 for _, port := range portList { 115 portStr := strings.TrimSpace(port) 116 taskChan <- scanTask{Host: ip.String(), Port: portStr} 117 } 118 } 119 }() 120 121 // 等待所有工作协程完成 122 wg.Wait() 123 close(resultChan) 124 125 // 输出最终统计 126 duration := time.Since(stats.StartTime) 127 fmt.Printf("\n✅ 扫描完成!\n") 128 fmt.Printf("总耗时: %v\n", duration) 129 fmt.Printf("扫描目标: %d\n", atomic.LoadInt64(&stats.ScannedTargets)) 130 fmt.Printf("开放端口: %d\n", atomic.LoadInt64(&stats.OpenPorts)) 131 fmt.Printf("识别服务: %d\n", atomic.LoadInt64(&stats.IdentifiedPorts)) 132 fmt.Printf("扫描速度: %.2f targets/sec\n", 133 float64(atomic.LoadInt64(&stats.ScannedTargets))/duration.Seconds()) 134 } 135 136 // 扫描任务 137 type scanTask struct { 138 Host string 139 Port string 140 } 141 142 // 工作协程 143 func worker(engine *fingers.Engine, sender common.ServiceSender, taskChan <-chan scanTask, resultChan chan<- ScanResult, wg *sync.WaitGroup, level int) { 144 defer wg.Done() 145 146 for task := range taskChan { 147 // 使用DetectService进行扫描 148 serviceResults, err := engine.DetectService(task.Host, task.Port, level, sender, nil) 149 150 result := ScanResult{ 151 Host: task.Host, 152 Port: task.Port, 153 Open: len(serviceResults) > 0, 154 Framework: nil, 155 Error: err, 156 } 157 158 // 如果有识别到的服务,取第一个 159 if len(serviceResults) > 0 && serviceResults[0].Framework != nil { 160 result.Framework = serviceResults[0].Framework 161 } 162 163 select { 164 case resultChan <- result: 165 default: 166 // 结果通道已满,丢弃结果(避免阻塞) 167 } 168 } 169 } 170 171 // 结果处理协程 172 func resultHandler(resultChan <-chan ScanResult, stats *ScanStats, verbose bool, outputFile string) { 173 var results []ScanResult 174 175 for result := range resultChan { 176 atomic.AddInt64(&stats.ScannedTargets, 1) 177 178 // 统计开放端口 179 if result.Open { 180 atomic.AddInt64(&stats.OpenPorts, 1) 181 } 182 183 // 统计识别的服务 184 if result.Framework != nil { 185 atomic.AddInt64(&stats.IdentifiedPorts, 1) 186 } 187 188 // 输出结果 189 if result.Open { 190 if verbose || result.Framework != nil { 191 printResult(result) 192 } 193 results = append(results, result) 194 } 195 } 196 197 // 保存到文件 198 if outputFile != "" { 199 saveResults(results, outputFile) 200 } 201 } 202 203 // 打印扫描结果 204 func printResult(result ScanResult) { 205 target := fmt.Sprintf("%s:%s", result.Host, result.Port) 206 207 if result.Framework != nil { 208 // 使用Framework.String()方法进行输出 209 frameworkStr := result.Framework.String() 210 211 // 添加guess标识 212 guessIndicator := "" 213 if result.Framework.IsGuess() { 214 guessIndicator = " [guess]" 215 } 216 217 // 输出基本信息 218 fmt.Printf("✅ %s -> %s%s", target, frameworkStr, guessIndicator) 219 220 // 输出CPE信息(如果有的话) 221 if result.Framework.Attributes != nil && result.Framework.Attributes.String() != "" { 222 fmt.Printf(" | CPE: %s", result.Framework.CPE()) 223 } 224 225 fmt.Printf("\n") 226 } else if result.Open { 227 // 只是端口开放,无法识别服务 228 fmt.Printf("🔓 %s -> 端口开放\n", target) 229 } 230 } 231 232 // 保存结果到文件 233 func saveResults(results []ScanResult, filename string) { 234 // TODO: 实现结果保存功能 235 fmt.Printf("📝 结果已保存到: %s (%d条记录)\n", filename, len(results)) 236 } 237 238 // parseCIDR 解析CIDR网段,返回IP地址列表 239 func parseCIDR(cidr string) (*utils.CIDR, error) { 240 241 // 解析CIDR 242 ipnet := utils.ParseCIDR(cidr) 243 if ipnet == nil { 244 return nil, fmt.Errorf("无效的CIDR: %s", cidr) 245 } 246 247 return ipnet, nil 248 }