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 }