github.com/chainreactors/fingers@v1.2.1/fingers/README.md (about) 1 # Fingers Engine SDK 文档 2 3 ## 概述 4 5 `FingersEngine` 是 Fingers 库的核心引擎,提供丰富的 Web 应用和网络服务指纹识别能力。它支持 HTTP/HTTPS 协议的 Web 指纹匹配以及 TCP/UDP 协议的服务指纹匹配,包含被动检测和主动检测两种模式。 6 7 ## 基本使用 8 9 ### 1. 创建 FingersEngine 实例 10 11 ```go 12 package main 13 14 import ( 15 "fmt" 16 "github.com/chainreactors/fingers/fingers" 17 ) 18 19 func main() { 20 // 使用默认配置创建引擎 21 engine, err := fingers.NewFingersEngine() 22 if err != nil { 23 panic(err) 24 } 25 26 fmt.Printf("FingersEngine 加载完成,包含 %d 个指纹\n", engine.Len()) 27 } 28 ``` 29 30 ### 2. Web 指纹检测 31 32 #### 从 HTTP 响应进行检测 33 34 ```go 35 package main 36 37 import ( 38 "crypto/tls" 39 "fmt" 40 "net/http" 41 42 "github.com/chainreactors/fingers/fingers" 43 "github.com/chainreactors/utils/httputils" 44 ) 45 46 func main() { 47 // 创建引擎 48 engine, err := fingers.NewFingersEngine() 49 if err != nil { 50 panic(err) 51 } 52 53 // 创建 HTTP 客户端 54 client := &http.Client{ 55 Transport: &http.Transport{ 56 TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 57 }, 58 } 59 60 // 发送 HTTP 请求 61 resp, err := client.Get("https://example.com") 62 if err != nil { 63 panic(err) 64 } 65 defer resp.Body.Close() 66 67 // 读取原始响应内容 68 content := httputils.ReadRaw(resp) 69 70 // 进行 Web 指纹匹配 71 frameworks := engine.WebMatch(content) 72 73 // 输出检测结果 74 for _, framework := range frameworks { 75 fmt.Printf("检测到: %s (来源: %s)\n", framework.Name, framework.From) 76 if framework.Version != "" { 77 fmt.Printf("版本: %s\n", framework.Version) 78 } 79 if len(framework.Tags) > 0 { 80 fmt.Printf("标签: %v\n", framework.Tags) 81 } 82 fmt.Printf("CPE: %s\n", framework.CPE()) 83 fmt.Println("---") 84 } 85 } 86 ``` 87 88 #### 从文件内容进行检测 89 90 ```go 91 package main 92 93 import ( 94 "fmt" 95 "os" 96 97 "github.com/chainreactors/fingers/fingers" 98 ) 99 100 func main() { 101 // 创建引擎 102 engine, err := fingers.NewFingersEngine() 103 if err != nil { 104 panic(err) 105 } 106 107 // 从文件读取 HTTP 响应内容 108 content, err := os.ReadFile("response.raw") 109 if err != nil { 110 panic(err) 111 } 112 113 // 进行指纹匹配 114 frameworks := engine.WebMatch(content) 115 116 // 输出结果 117 for _, framework := range frameworks { 118 fmt.Printf("检测结果: %s\n", framework.String()) 119 } 120 } 121 ``` 122 123 ### 3. 服务指纹检测 124 125 ```go 126 package main 127 128 import ( 129 "fmt" 130 "time" 131 132 "github.com/chainreactors/fingers/fingers" 133 "github.com/chainreactors/fingers/common" 134 ) 135 136 func main() { 137 // 创建引擎 138 engine, err := fingers.NewFingersEngine() 139 if err != nil { 140 panic(err) 141 } 142 143 // 创建服务发送器 144 sender := common.NewServiceSender(5 * time.Second) 145 146 // 定义回调函数处理检测结果 147 callback := func(result *common.ServiceResult) { 148 if result.Framework != nil { 149 fmt.Printf("检测到服务: %s\n", result.Framework.String()) 150 } 151 if result.Vuln != nil { 152 fmt.Printf("发现漏洞: %s\n", result.Vuln.Name) 153 } 154 } 155 156 // 进行服务指纹检测 157 result := engine.ServiceMatch("127.0.0.1", "80", 1, sender, callback) 158 159 if result != nil && result.Framework != nil { 160 fmt.Printf("最终结果: %s\n", result.Framework.String()) 161 } 162 } 163 ``` 164 165 ## 高级功能 166 167 ### 1. 使用自定义指纹库 168 169 `NewFingersEngineWithCustom` 函数允许您使用自定义的指纹库配置: 170 171 ```go 172 package main 173 174 import ( 175 "fmt" 176 "os" 177 178 "github.com/chainreactors/fingers/fingers" 179 ) 180 181 func main() { 182 // 加载自定义 HTTP 指纹库 183 httpConfig, err := os.ReadFile("custom_http_fingers.json") 184 if err != nil { 185 panic(err) 186 } 187 188 // 加载自定义 Socket 指纹库(可选) 189 socketConfig, err := os.ReadFile("custom_socket_fingers.json") 190 if err != nil { 191 // Socket 配置是可选的 192 socketConfig = nil 193 } 194 195 // 使用自定义配置创建引擎 196 engine, err := fingers.NewFingersEngineWithCustom(httpConfig, socketConfig) 197 if err != nil { 198 panic(err) 199 } 200 201 fmt.Printf("使用自定义指纹库创建引擎成功,包含 %d 个指纹\n", engine.Len()) 202 203 // 正常使用引擎进行检测 204 // ... 205 } 206 ``` 207 208 #### 自定义指纹库格式说明 209 210 - `httpConfig`: HTTP 指纹库配置,JSON 格式 211 - `socketConfig`: Socket 指纹库配置,JSON 格式(可以为 nil) 212 213 指纹库配置格式参考现有的指纹库文件结构。 214 215 ### 2. 主动指纹检测 216 217 FingersEngine 支持主动指纹检测,会主动发送特定的探测包来获取更准确的指纹信息: 218 219 ```go 220 package main 221 222 import ( 223 "fmt" 224 "net/http" 225 "time" 226 227 "github.com/chainreactors/fingers/fingers" 228 ) 229 230 func main() { 231 engine, err := fingers.NewFingersEngine() 232 if err != nil { 233 panic(err) 234 } 235 236 // 定义发送器函数,用于主动探测 237 sender := fingers.Sender(func(data []byte) ([]byte, bool) { 238 // 根据探测数据构造 HTTP 请求 239 client := &http.Client{Timeout: 5 * time.Second} 240 241 // 这里是简化示例,实际实现需要根据 data 内容构造请求 242 resp, err := client.Get("http://example.com/probe") 243 if err != nil { 244 return nil, false 245 } 246 defer resp.Body.Close() 247 248 // 返回响应数据 249 response := make([]byte, 1024) 250 n, _ := resp.Body.Read(response) 251 return response[:n], true 252 }) 253 254 // 定义回调函数 255 callback := fingers.Callback(func(framework *common.Framework, vuln *common.Vuln) { 256 fmt.Printf("主动检测结果: %s\n", framework.String()) 257 if vuln != nil { 258 fmt.Printf("发现漏洞: %s\n", vuln.Name) 259 } 260 }) 261 262 // 执行主动指纹检测 263 frameworks, vulns := engine.HTTPActiveMatch(1, sender, callback) 264 265 fmt.Printf("检测到 %d 个框架,%d 个漏洞\n", len(frameworks), len(vulns)) 266 } 267 ``` 268 269 ## 单个指纹测试 270 271 ### Finger.Match 函数使用 272 273 `Finger.Match` 函数用于测试单个指纹规则的匹配情况。以下示例展示如何从 JSON/YAML 配置创建并测试单个指纹: 274 275 ```go 276 package main 277 278 import ( 279 "encoding/json" 280 "fmt" 281 282 "github.com/chainreactors/fingers/fingers" 283 ) 284 285 func main() { 286 // 定义单个指纹的 JSON 配置 287 fingerJSON := `{ 288 "name": "nginx", 289 "rule": [ 290 { 291 "method": "keyword", 292 "keyword": ["nginx"] 293 } 294 ] 295 }` 296 297 // 反序列化创建指纹 298 var finger fingers.Finger 299 err := json.Unmarshal([]byte(fingerJSON), &finger) 300 if err != nil { 301 panic(err) 302 } 303 304 // 编译指纹规则 305 err = finger.Compile(false) 306 if err != nil { 307 panic(err) 308 } 309 310 // 准备测试内容 311 testContent := []byte(`HTTP/1.1 200 OK 312 Server: nginx/1.18.0 313 Content-Type: text/html 314 315 <html><body>Hello World</body></html>`) 316 317 // 创建内容对象 318 content := fingers.NewContent(testContent, "", true) 319 320 // 测试指纹匹配(被动检测) 321 framework, vuln, matched := finger.Match(content, 0, nil) 322 323 if matched { 324 fmt.Printf("✓ 指纹匹配成功: %s\n", framework.String()) 325 if framework.Version != "" { 326 fmt.Printf(" 版本: %s\n", framework.Version) 327 } 328 } else { 329 fmt.Printf("✗ 指纹不匹配\n") 330 } 331 } 332 ``` 333 334 ### 使用 YAML 格式指纹 335 336 ```go 337 package main 338 339 import ( 340 "fmt" 341 342 "gopkg.in/yaml.v3" 343 "github.com/chainreactors/fingers/fingers" 344 ) 345 346 func main() { 347 // YAML 格式的指纹配置 348 fingerYAML := ` 349 name: apache 350 rule: 351 - method: keyword 352 keyword: ["Apache"] 353 - method: regex 354 regex: "Apache/([\\d\\.]+)" 355 version: "\\1" 356 ` 357 358 // 反序列化创建指纹 359 var finger fingers.Finger 360 err := yaml.Unmarshal([]byte(fingerYAML), &finger) 361 if err != nil { 362 panic(err) 363 } 364 365 // 编译指纹规则 366 err = finger.Compile(false) 367 if err != nil { 368 panic(err) 369 } 370 371 // 测试内容 372 testContent := []byte(`HTTP/1.1 200 OK 373 Server: Apache/2.4.41 374 Content-Type: text/html 375 376 <html><body>Apache Server</body></html>`) 377 378 content := fingers.NewContent(testContent, "", true) 379 380 // 执行匹配 381 framework, vuln, matched := finger.Match(content, 0, nil) 382 383 if matched { 384 fmt.Printf("✓ 匹配成功: %s\n", framework.String()) 385 if framework.Version != "" { 386 fmt.Printf(" 版本: %s\n", framework.Version) 387 } 388 } 389 } 390 ``` 391 392 ### 主动探测指纹测试 393 394 ```go 395 package main 396 397 import ( 398 "encoding/json" 399 "fmt" 400 401 "github.com/chainreactors/fingers/fingers" 402 ) 403 404 func main() { 405 // 包含主动探测规则的指纹 406 fingerJSON := `{ 407 "name": "custom-service", 408 "rule": [ 409 { 410 "method": "keyword", 411 "keyword": ["custom"], 412 "level": 1, 413 "senddata": "GET /admin HTTP/1.1\r\nHost: example.com\r\n\r\n" 414 } 415 ] 416 }` 417 418 var finger fingers.Finger 419 json.Unmarshal([]byte(fingerJSON), &finger) 420 finger.Compile(false) 421 422 // 定义简单的发送器 423 sender := fingers.Sender(func(data []byte) ([]byte, bool) { 424 // 模拟主动探测返回的响应 425 response := []byte(`HTTP/1.1 200 OK 426 Server: custom-server 427 428 <html><body>Custom Admin Panel</body></html>`) 429 return response, true 430 }) 431 432 // 执行主动匹配(level=1 触发主动探测) 433 framework, vuln, matched := finger.Match(nil, 1, sender) 434 435 if matched { 436 fmt.Printf("✓ 主动探测成功: %s\n", framework.String()) 437 } 438 } 439 ``` 440 441 ## 引擎能力说明 442 443 FingersEngine 实现了 `EngineImpl` 接口,提供以下能力: 444 445 - **Web 指纹识别**: 支持 HTTP/HTTPS 协议的 Web 应用指纹识别 446 - **服务指纹识别**: 支持 TCP/UDP 协议的网络服务指纹识别 447 - **被动检测**: 基于现有响应内容进行指纹匹配 448 - **主动检测**: 发送特定探测包获取指纹信息 449 - **漏洞检测**: 在指纹匹配过程中发现潜在的安全问题 450 - **多协议支持**: HTTP, TCP, UDP 协议支持 451 - **版本识别**: 识别应用程序和服务的具体版本 452 453 ## 指纹验证 454 455 ### 命令行验证 456 457 使用 `validate` 命令可以快速验证指纹文件格式: 458 459 ```bash 460 # 验证指纹文件 461 cd cmd/validate 462 go run main.go -engine fingers fingerprints.yaml 463 464 # 验证单个指纹 465 go run main.go -engine fingers single_finger.json 466 ``` 467 468 ### 代码验证示例 469 470 在代码中验证 fingers 格式指纹: 471 472 ```go 473 package main 474 475 import ( 476 "encoding/json" 477 "fmt" 478 "os" 479 480 "github.com/chainreactors/fingers/fingers" 481 "gopkg.in/yaml.v3" 482 ) 483 484 func validateFingerprintFile(filename string) error { 485 // 读取文件 486 content, err := os.ReadFile(filename) 487 if err != nil { 488 return fmt.Errorf("读取文件失败: %w", err) 489 } 490 491 // 尝试解析为单个指纹 492 var singleFinger fingers.Finger 493 if err := json.Unmarshal(content, &singleFinger); err == nil { 494 return validateSingleFingerprint(singleFinger) 495 } 496 497 // 尝试解析为指纹数组 (YAML) 498 var fingerArray []fingers.Finger 499 if err := yaml.Unmarshal(content, &fingerArray); err == nil { 500 return validateFingerprintArray(fingerArray) 501 } 502 503 return fmt.Errorf("无法解析为有效的指纹格式") 504 } 505 506 func validateSingleFingerprint(finger fingers.Finger) error { 507 // 验证必填字段 508 if finger.Name == "" { 509 return fmt.Errorf("指纹名称不能为空") 510 } 511 512 if len(finger.Rules) == 0 { 513 return fmt.Errorf("指纹必须包含至少一个规则") 514 } 515 516 // 编译指纹以验证语法 517 if err := finger.Compile(false); err != nil { 518 return fmt.Errorf("指纹编译失败: %w", err) 519 } 520 521 fmt.Printf("✓ 指纹 '%s' 验证通过\n", finger.Name) 522 return nil 523 } 524 525 func validateFingerprintArray(fingerprints []fingers.Finger) error { 526 if len(fingerprints) == 0 { 527 return fmt.Errorf("指纹数组不能为空") 528 } 529 530 validCount := 0 531 for i, finger := range fingerprints { 532 if err := validateSingleFingerprint(finger); err != nil { 533 fmt.Printf("✗ 指纹[%d] '%s' 验证失败: %v\n", i, finger.Name, err) 534 } else { 535 validCount++ 536 } 537 } 538 539 fmt.Printf("验证完成: %d/%d 个指纹有效\n", validCount, len(fingerprints)) 540 return nil 541 } 542 543 func main() { 544 if len(os.Args) < 2 { 545 fmt.Println("用法: go run main.go <指纹文件>") 546 return 547 } 548 549 filename := os.Args[1] 550 if err := validateFingerprintFile(filename); err != nil { 551 fmt.Printf("验证失败: %v\n", err) 552 os.Exit(1) 553 } 554 } 555 ``` 556 557 ### 批量加载和验证 558 559 ```go 560 package main 561 562 import ( 563 "fmt" 564 565 "github.com/chainreactors/fingers/fingers" 566 ) 567 568 func main() { 569 // 直接使用 LoadFingers 加载和验证 570 content := []byte(`[ 571 { 572 "name": "nginx", 573 "rule": [ 574 { 575 "regexps": { 576 "header": ["Server: nginx"] 577 }, 578 "level": 0 579 } 580 ] 581 } 582 ]`) 583 584 // LoadFingers 会自动验证格式 585 fingerprintList, err := fingers.LoadFingers(content) 586 if err != nil { 587 fmt.Printf("加载失败: %v\n", err) 588 return 589 } 590 591 // 编译验证每个指纹 592 for _, finger := range fingerprintList { 593 if err := finger.Compile(false); err != nil { 594 fmt.Printf("指纹 '%s' 编译失败: %v\n", finger.Name, err) 595 } else { 596 fmt.Printf("指纹 '%s' 验证通过\n", finger.Name) 597 } 598 } 599 } 600 ``` 601 602 ## 最佳实践 603 604 1. **引擎复用**: 创建引擎实例开销较大,建议在应用中复用引擎实例 605 2. **超时控制**: 在进行主动检测时,务必设置合适的超时时间 606 3. **错误处理**: 妥善处理网络请求和指纹匹配过程中的错误 607 4. **结果过滤**: 根据实际需求过滤和处理检测结果 608 5. **性能优化**: 对于大量目标的批量检测,考虑使用并发控制 609 610 ## 注意事项 611 612 - 主动指纹检测可能会对目标系统产生影响,使用时需要谨慎 613 - 自定义指纹库需要遵循正确的格式规范 614 - 在生产环境中使用时,建议进行充分的测试 615 - 某些指纹可能存在误报,需要结合实际情况进行判断