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  }