FingersEngine 是 Fingers 库的核心引擎,提供丰富的 Web 应用和网络服务指纹识别能力。它支持 HTTP/HTTPS 协议的 Web 指纹匹配以及 TCP/UDP 协议的服务指纹匹配,包含被动检测和主动检测两种模式。
package main
import (
"fmt"
"github.com/chainreactors/fingers/fingers"
)
func main() {
// 使用默认配置创建引擎
engine, err := fingers.NewFingersEngine()
if err != nil {
panic(err)
}
fmt.Printf("FingersEngine 加载完成,包含 %d 个指纹\n", engine.Len())
}package main
import (
"crypto/tls"
"fmt"
"net/http"
"github.com/chainreactors/fingers/fingers"
"github.com/chainreactors/utils/httputils"
)
func main() {
// 创建引擎
engine, err := fingers.NewFingersEngine()
if err != nil {
panic(err)
}
// 创建 HTTP 客户端
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
// 发送 HTTP 请求
resp, err := client.Get("https://example.com")
if err != nil {
panic(err)
}
defer resp.Body.Close()
// 读取原始响应内容
content := httputils.ReadRaw(resp)
// 进行 Web 指纹匹配
frameworks := engine.WebMatch(content)
// 输出检测结果
for _, framework := range frameworks {
fmt.Printf("检测到: %s (来源: %s)\n", framework.Name, framework.From)
if framework.Version != "" {
fmt.Printf("版本: %s\n", framework.Version)
}
if len(framework.Tags) > 0 {
fmt.Printf("标签: %v\n", framework.Tags)
}
fmt.Printf("CPE: %s\n", framework.CPE())
fmt.Println("---")
}
}package main
import (
"fmt"
"os"
"github.com/chainreactors/fingers/fingers"
)
func main() {
// 创建引擎
engine, err := fingers.NewFingersEngine()
if err != nil {
panic(err)
}
// 从文件读取 HTTP 响应内容
content, err := os.ReadFile("response.raw")
if err != nil {
panic(err)
}
// 进行指纹匹配
frameworks := engine.WebMatch(content)
// 输出结果
for _, framework := range frameworks {
fmt.Printf("检测结果: %s\n", framework.String())
}
}package main
import (
"fmt"
"time"
"github.com/chainreactors/fingers/fingers"
"github.com/chainreactors/fingers/common"
)
func main() {
// 创建引擎
engine, err := fingers.NewFingersEngine()
if err != nil {
panic(err)
}
// 创建服务发送器
sender := common.NewServiceSender(5 * time.Second)
// 定义回调函数处理检测结果
callback := func(result *common.ServiceResult) {
if result.Framework != nil {
fmt.Printf("检测到服务: %s\n", result.Framework.String())
}
if result.Vuln != nil {
fmt.Printf("发现漏洞: %s\n", result.Vuln.Name)
}
}
// 进行服务指纹检测
result := engine.ServiceMatch("127.0.0.1", "80", 1, sender, callback)
if result != nil && result.Framework != nil {
fmt.Printf("最终结果: %s\n", result.Framework.String())
}
}NewFingersEngineWithCustom 函数允许您使用自定义的指纹库配置:
package main
import (
"fmt"
"os"
"github.com/chainreactors/fingers/fingers"
)
func main() {
// 加载自定义 HTTP 指纹库
httpConfig, err := os.ReadFile("custom_http_fingers.json")
if err != nil {
panic(err)
}
// 加载自定义 Socket 指纹库(可选)
socketConfig, err := os.ReadFile("custom_socket_fingers.json")
if err != nil {
// Socket 配置是可选的
socketConfig = nil
}
// 使用自定义配置创建引擎
engine, err := fingers.NewFingersEngineWithCustom(httpConfig, socketConfig)
if err != nil {
panic(err)
}
fmt.Printf("使用自定义指纹库创建引擎成功,包含 %d 个指纹\n", engine.Len())
// 正常使用引擎进行检测
// ...
}httpConfig: HTTP 指纹库配置,JSON 格式socketConfig: Socket 指纹库配置,JSON 格式(可以为 nil)
指纹库配置格式参考现有的指纹库文件结构。
FingersEngine 支持主动指纹检测,会主动发送特定的探测包来获取更准确的指纹信息:
package main
import (
"fmt"
"net/http"
"time"
"github.com/chainreactors/fingers/fingers"
)
func main() {
engine, err := fingers.NewFingersEngine()
if err != nil {
panic(err)
}
// 定义发送器函数,用于主动探测
sender := fingers.Sender(func(data []byte) ([]byte, bool) {
// 根据探测数据构造 HTTP 请求
client := &http.Client{Timeout: 5 * time.Second}
// 这里是简化示例,实际实现需要根据 data 内容构造请求
resp, err := client.Get("http://example.com/probe")
if err != nil {
return nil, false
}
defer resp.Body.Close()
// 返回响应数据
response := make([]byte, 1024)
n, _ := resp.Body.Read(response)
return response[:n], true
})
// 定义回调函数
callback := fingers.Callback(func(framework *common.Framework, vuln *common.Vuln) {
fmt.Printf("主动检测结果: %s\n", framework.String())
if vuln != nil {
fmt.Printf("发现漏洞: %s\n", vuln.Name)
}
})
// 执行主动指纹检测
frameworks, vulns := engine.HTTPActiveMatch(1, sender, callback)
fmt.Printf("检测到 %d 个框架,%d 个漏洞\n", len(frameworks), len(vulns))
}Finger.Match 函数用于测试单个指纹规则的匹配情况。以下示例展示如何从 JSON/YAML 配置创建并测试单个指纹:
package main
import (
"encoding/json"
"fmt"
"github.com/chainreactors/fingers/fingers"
)
func main() {
// 定义单个指纹的 JSON 配置
fingerJSON := `{
"name": "nginx",
"rule": [
{
"method": "keyword",
"keyword": ["nginx"]
}
]
}`
// 反序列化创建指纹
var finger fingers.Finger
err := json.Unmarshal([]byte(fingerJSON), &finger)
if err != nil {
panic(err)
}
// 编译指纹规则
err = finger.Compile(false)
if err != nil {
panic(err)
}
// 准备测试内容
testContent := []byte(`HTTP/1.1 200 OK
Server: nginx/1.18.0
Content-Type: text/html
<html><body>Hello World</body></html>`)
// 创建内容对象
content := fingers.NewContent(testContent, "", true)
// 测试指纹匹配(被动检测)
framework, vuln, matched := finger.Match(content, 0, nil)
if matched {
fmt.Printf("✓ 指纹匹配成功: %s\n", framework.String())
if framework.Version != "" {
fmt.Printf(" 版本: %s\n", framework.Version)
}
} else {
fmt.Printf("✗ 指纹不匹配\n")
}
}package main
import (
"fmt"
"gopkg.in/yaml.v3"
"github.com/chainreactors/fingers/fingers"
)
func main() {
// YAML 格式的指纹配置
fingerYAML := `
name: apache
rule:
- method: keyword
keyword: ["Apache"]
- method: regex
regex: "Apache/([\\d\\.]+)"
version: "\\1"
`
// 反序列化创建指纹
var finger fingers.Finger
err := yaml.Unmarshal([]byte(fingerYAML), &finger)
if err != nil {
panic(err)
}
// 编译指纹规则
err = finger.Compile(false)
if err != nil {
panic(err)
}
// 测试内容
testContent := []byte(`HTTP/1.1 200 OK
Server: Apache/2.4.41
Content-Type: text/html
<html><body>Apache Server</body></html>`)
content := fingers.NewContent(testContent, "", true)
// 执行匹配
framework, vuln, matched := finger.Match(content, 0, nil)
if matched {
fmt.Printf("✓ 匹配成功: %s\n", framework.String())
if framework.Version != "" {
fmt.Printf(" 版本: %s\n", framework.Version)
}
}
}package main
import (
"encoding/json"
"fmt"
"github.com/chainreactors/fingers/fingers"
)
func main() {
// 包含主动探测规则的指纹
fingerJSON := `{
"name": "custom-service",
"rule": [
{
"method": "keyword",
"keyword": ["custom"],
"level": 1,
"senddata": "GET /admin HTTP/1.1\r\nHost: example.com\r\n\r\n"
}
]
}`
var finger fingers.Finger
json.Unmarshal([]byte(fingerJSON), &finger)
finger.Compile(false)
// 定义简单的发送器
sender := fingers.Sender(func(data []byte) ([]byte, bool) {
// 模拟主动探测返回的响应
response := []byte(`HTTP/1.1 200 OK
Server: custom-server
<html><body>Custom Admin Panel</body></html>`)
return response, true
})
// 执行主动匹配(level=1 触发主动探测)
framework, vuln, matched := finger.Match(nil, 1, sender)
if matched {
fmt.Printf("✓ 主动探测成功: %s\n", framework.String())
}
}FingersEngine 实现了 EngineImpl 接口,提供以下能力:
- Web 指纹识别: 支持 HTTP/HTTPS 协议的 Web 应用指纹识别
- 服务指纹识别: 支持 TCP/UDP 协议的网络服务指纹识别
- 被动检测: 基于现有响应内容进行指纹匹配
- 主动检测: 发送特定探测包获取指纹信息
- 漏洞检测: 在指纹匹配过程中发现潜在的安全问题
- 多协议支持: HTTP, TCP, UDP 协议支持
- 版本识别: 识别应用程序和服务的具体版本
使用 validate 命令可以快速验证指纹文件格式:
# 验证指纹文件
cd cmd/validate
go run main.go -engine fingers fingerprints.yaml
# 验证单个指纹
go run main.go -engine fingers single_finger.json在代码中验证 fingers 格式指纹:
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/chainreactors/fingers/fingers"
"gopkg.in/yaml.v3"
)
func validateFingerprintFile(filename string) error {
// 读取文件
content, err := os.ReadFile(filename)
if err != nil {
return fmt.Errorf("读取文件失败: %w", err)
}
// 尝试解析为单个指纹
var singleFinger fingers.Finger
if err := json.Unmarshal(content, &singleFinger); err == nil {
return validateSingleFingerprint(singleFinger)
}
// 尝试解析为指纹数组 (YAML)
var fingerArray []fingers.Finger
if err := yaml.Unmarshal(content, &fingerArray); err == nil {
return validateFingerprintArray(fingerArray)
}
return fmt.Errorf("无法解析为有效的指纹格式")
}
func validateSingleFingerprint(finger fingers.Finger) error {
// 验证必填字段
if finger.Name == "" {
return fmt.Errorf("指纹名称不能为空")
}
if len(finger.Rules) == 0 {
return fmt.Errorf("指纹必须包含至少一个规则")
}
// 编译指纹以验证语法
if err := finger.Compile(false); err != nil {
return fmt.Errorf("指纹编译失败: %w", err)
}
fmt.Printf("✓ 指纹 '%s' 验证通过\n", finger.Name)
return nil
}
func validateFingerprintArray(fingerprints []fingers.Finger) error {
if len(fingerprints) == 0 {
return fmt.Errorf("指纹数组不能为空")
}
validCount := 0
for i, finger := range fingerprints {
if err := validateSingleFingerprint(finger); err != nil {
fmt.Printf("✗ 指纹[%d] '%s' 验证失败: %v\n", i, finger.Name, err)
} else {
validCount++
}
}
fmt.Printf("验证完成: %d/%d 个指纹有效\n", validCount, len(fingerprints))
return nil
}
func main() {
if len(os.Args) < 2 {
fmt.Println("用法: go run main.go <指纹文件>")
return
}
filename := os.Args[1]
if err := validateFingerprintFile(filename); err != nil {
fmt.Printf("验证失败: %v\n", err)
os.Exit(1)
}
}package main
import (
"fmt"
"github.com/chainreactors/fingers/fingers"
)
func main() {
// 直接使用 LoadFingers 加载和验证
content := []byte(`[
{
"name": "nginx",
"rule": [
{
"regexps": {
"header": ["Server: nginx"]
},
"level": 0
}
]
}
]`)
// LoadFingers 会自动验证格式
fingerprintList, err := fingers.LoadFingers(content)
if err != nil {
fmt.Printf("加载失败: %v\n", err)
return
}
// 编译验证每个指纹
for _, finger := range fingerprintList {
if err := finger.Compile(false); err != nil {
fmt.Printf("指纹 '%s' 编译失败: %v\n", finger.Name, err)
} else {
fmt.Printf("指纹 '%s' 验证通过\n", finger.Name)
}
}
}- 引擎复用: 创建引擎实例开销较大,建议在应用中复用引擎实例
- 超时控制: 在进行主动检测时,务必设置合适的超时时间
- 错误处理: 妥善处理网络请求和指纹匹配过程中的错误
- 结果过滤: 根据实际需求过滤和处理检测结果
- 性能优化: 对于大量目标的批量检测,考虑使用并发控制
- 主动指纹检测可能会对目标系统产生影响,使用时需要谨慎
- 自定义指纹库需要遵循正确的格式规范
- 在生产环境中使用时,建议进行充分的测试
- 某些指纹可能存在误报,需要结合实际情况进行判断