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  - 某些指纹可能存在误报,需要结合实际情况进行判断