github.com/chainreactors/fingers@v1.2.1/cmd/engine/example.go (about)

     1  package main
     2  
     3  import (
     4  	"crypto/tls"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/chainreactors/fingers"
    14  	"github.com/chainreactors/fingers/common"
    15  	"github.com/chainreactors/fingers/resources"
    16  	"github.com/chainreactors/utils/encode"
    17  	"github.com/chainreactors/utils/httputils"
    18  	"github.com/jessevdk/go-flags"
    19  	"gopkg.in/yaml.v3"
    20  )
    21  
    22  var opts struct {
    23  	// 指定要使用的引擎,多个引擎用逗号分隔
    24  	Engines string `short:"e" long:"engines" description:"Specify engines to use (comma separated)" default:"fingers,fingerprinthub,wappalyzer,ehole,goby"`
    25  
    26  	// 是否忽略SSL证书验证
    27  	InsecureSSL bool `short:"k" long:"insecure" description:"Skip SSL certificate verification"`
    28  
    29  	// 目标URL
    30  	URL string `short:"u" long:"url" description:"Target URL to fingerprint" required:"true"`
    31  
    32  	// 是否显示详细信息
    33  	Verbose bool `short:"v" long:"verbose" description:"Show verbose debug information"`
    34  
    35  	// 是否只检测favicon
    36  	FaviconOnly bool `short:"f" long:"favicon" description:"Only detect favicon"`
    37  
    38  	// 资源文件覆盖
    39  	GobyFile                  string `long:"goby" description:"Override goby.json.gz with custom file"`
    40  	FingerprintHubWebFile     string `long:"fingerprinthub-web" description:"Override fingerprinthub_web.json.gz with custom file"`
    41  	FingerprintHubServiceFile string `long:"fingerprinthub-service" description:"Override fingerprinthub_service.json.gz with custom file"`
    42  	EholeFile                 string `long:"ehole" description:"Override ehole.json.gz with custom file"`
    43  	FingersFile               string `long:"fingers" description:"Override fingers_http.json.gz with custom file"`
    44  	WappalyzerFile            string `long:"wappalyzer" description:"Override wappalyzer.json.gz with custom file"`
    45  	AliasesFile               string `long:"aliases" description:"Override aliases.yaml with custom file"`
    46  }
    47  
    48  // 处理资源文件覆盖
    49  func processResourceFile(filePath string) ([]byte, error) {
    50  	if filePath == "" {
    51  		return nil, nil
    52  	}
    53  
    54  	data, err := ioutil.ReadFile(filePath)
    55  	if err != nil {
    56  		return nil, fmt.Errorf("failed to read file %s: %v", filePath, err)
    57  	}
    58  
    59  	ext := strings.ToLower(filepath.Ext(filePath))
    60  
    61  	// 如果是JSON文件,转换为YAML
    62  	if ext == ".json" {
    63  		var jsonData interface{}
    64  		if err := json.Unmarshal(data, &jsonData); err != nil {
    65  			return nil, fmt.Errorf("failed to parse JSON file %s: %v", filePath, err)
    66  		}
    67  
    68  		data, err = yaml.Marshal(jsonData)
    69  		if err != nil {
    70  			return nil, fmt.Errorf("failed to convert JSON to YAML for file %s: %v", filePath, err)
    71  		}
    72  	}
    73  
    74  	// 如果文件不是.gz结尾,进行gzip压缩
    75  	if !strings.HasSuffix(filePath, ".gz") {
    76  		compressedData, err := encode.GzipCompress(data)
    77  		if err != nil {
    78  			return nil, fmt.Errorf("failed to compress file %s: %v", filePath, err)
    79  		}
    80  		data = compressedData
    81  	}
    82  
    83  	return data, nil
    84  }
    85  
    86  func main() {
    87  	// 解析命令行参数
    88  	_, err := flags.Parse(&opts)
    89  	if err != nil {
    90  		os.Exit(1)
    91  	}
    92  
    93  	// 处理资源文件覆盖
    94  	if opts.GobyFile != "" {
    95  		if data, err := processResourceFile(opts.GobyFile); err != nil {
    96  			fmt.Println(err)
    97  			os.Exit(1)
    98  		} else {
    99  			resources.GobyData = data
   100  		}
   101  	}
   102  
   103  	if opts.FingerprintHubWebFile != "" {
   104  		if data, err := processResourceFile(opts.FingerprintHubWebFile); err != nil {
   105  			fmt.Println(err)
   106  			os.Exit(1)
   107  		} else {
   108  			resources.FingerprinthubWebData = data
   109  		}
   110  	}
   111  
   112  	if opts.FingerprintHubServiceFile != "" {
   113  		if data, err := processResourceFile(opts.FingerprintHubServiceFile); err != nil {
   114  			fmt.Println(err)
   115  			os.Exit(1)
   116  		} else {
   117  			resources.FingerprinthubServiceData = data
   118  		}
   119  	}
   120  
   121  	if opts.EholeFile != "" {
   122  		if data, err := processResourceFile(opts.EholeFile); err != nil {
   123  			fmt.Println(err)
   124  			os.Exit(1)
   125  		} else {
   126  			resources.EholeData = data
   127  		}
   128  	}
   129  
   130  	if opts.FingersFile != "" {
   131  		if data, err := processResourceFile(opts.FingersFile); err != nil {
   132  			fmt.Println(err)
   133  			os.Exit(1)
   134  		} else {
   135  			resources.FingersHTTPData = data
   136  		}
   137  	}
   138  
   139  	if opts.WappalyzerFile != "" {
   140  		if data, err := processResourceFile(opts.WappalyzerFile); err != nil {
   141  			fmt.Println(err)
   142  			os.Exit(1)
   143  		} else {
   144  			resources.WappalyzerData = data
   145  		}
   146  	}
   147  
   148  	if opts.AliasesFile != "" {
   149  		if data, err := processResourceFile(opts.AliasesFile); err != nil {
   150  			fmt.Println(err)
   151  			os.Exit(1)
   152  		} else {
   153  			resources.AliasesData = data
   154  		}
   155  	}
   156  
   157  	// 创建HTTP客户端
   158  	client := &http.Client{
   159  		Transport: &http.Transport{
   160  			TLSClientConfig: &tls.Config{
   161  				InsecureSkipVerify: opts.InsecureSSL,
   162  			},
   163  		},
   164  	}
   165  
   166  	// 创建引擎实例
   167  	var engineNames []string
   168  	if opts.Engines != "" {
   169  		engineNames = strings.Split(opts.Engines, ",")
   170  	}
   171  
   172  	engine, err := fingers.NewEngine(engineNames...)
   173  	if err != nil {
   174  		fmt.Printf("Failed to create engine: %v\n", err)
   175  		os.Exit(1)
   176  	}
   177  
   178  	if opts.Verbose {
   179  		fmt.Printf("Loaded engines: %s\n", engine.String())
   180  	}
   181  
   182  	// 发送HTTP请求
   183  	resp, err := client.Get(opts.URL)
   184  	if err != nil {
   185  		fmt.Printf("Failed to request URL %s: %v\n", opts.URL, err)
   186  		os.Exit(1)
   187  	}
   188  	defer resp.Body.Close()
   189  
   190  	// 检测指纹
   191  	var frames common.Frameworks
   192  	if opts.FaviconOnly {
   193  		content := httputils.ReadBody(resp)
   194  		frame := engine.DetectFavicon(content)
   195  		if frame != nil {
   196  			frames.Add(frame)
   197  		}
   198  	} else {
   199  		frames = engine.Match(resp)
   200  	}
   201  
   202  	// 输出结果
   203  	if opts.Verbose {
   204  		fmt.Printf("\nDetected frameworks for %s:\n", opts.URL)
   205  		for _, frame := range frames {
   206  			fmt.Printf("Name: %s\n", frame.Name)
   207  			fmt.Printf("Vendor: %s\n", frame.Vendor)
   208  			fmt.Printf("Product: %s\n", frame.Product)
   209  			fmt.Printf("Version: %s\n", frame.Version)
   210  			fmt.Printf("CPE: %s\n", frame.CPE())
   211  			fmt.Printf("---\n")
   212  		}
   213  	} else {
   214  		fmt.Println(frames.String())
   215  	}
   216  }