Files
fscan/webscan/fingerprint_scanner.go
T
ZacharyZcR 71b92d4408 feat: v2.1.0 核心重构与功能增强
## 架构重构
- 全局变量消除,迁移至 Config/State 对象
- SMB 插件融合(smb/smb2/smbghost/smbinfo)
- 服务探测重构,实现 Nmap 风格 fallback 机制
- 输出系统重构,TXT 实时刷盘 + 双写机制
- i18n 框架升级至 go-i18n

## 性能优化
- 正则表达式预编译
- 内存优化 map[string]struct{}
- 并发指纹匹配
- SOCKS5 连接复用
- 滑动窗口调度 + 自适应线程池

## 新功能
- Web 管理界面
- 多格式 POC 适配(xray/afrog)
- 增强指纹库(3139条)
- Favicon hash 指纹识别
- 插件选择性编译(Build Tags)
- fscan-lab 靶场环境
- 默认端口扩展(62→133)

## 构建系统
- 添加 no_local tag 支持排除本地插件
- 多版本构建:fscan/fscan-nolocal/fscan-web
- CI 添加 snapshot 模式支持仅测试构建

## Bug 修复
- 修复 120+ 个问题,包括 RDP panic、批量扫描漏报、
  JSON 输出格式、Redis 检测、Context 超时等

## 测试增强
- 单元测试覆盖率 74-100%
- 并发安全测试
- 集成测试(Web/端口/服务/SSH/ICMP)
2026-01-11 20:16:23 +08:00

108 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package WebScan
import (
"crypto/md5" //nolint:gosec // G501: MD5用于内容指纹识别,非加密用途
"fmt"
"github.com/shadow1ng/fscan/webscan/fingerprint"
)
// CheckDatas 存储HTTP响应的检查数据
type CheckDatas struct {
Body []byte // 响应体
Headers string // 响应头
Favicon fingerprint.FaviconHashes // Favicon hashmmh3 + MD5
}
// InfoCheck 检查URL的指纹信息
func InfoCheck(URL string, CheckData *[]CheckDatas) []string {
var matchedInfos []string
// 遍历检查数据
for _, data := range *CheckData {
// 基础指纹库:正则规则匹配 (272条)
matchedInfos = append(matchedInfos, matchByRegex(data)...)
// 基础指纹库:MD5指纹匹配 (30条)
if md5Name := matchByMd5(data.Body); md5Name != "" {
matchedInfos = append(matchedInfos, md5Name)
}
// 增强指纹库:FingerprintHub (3139条)
// 支持favicon hash、多种matcher类型、更丰富的匹配规则
enhanced := fingerprint.MatchEnhancedFingerprints(data.Body, data.Headers, data.Favicon)
matchedInfos = append(matchedInfos, enhanced...)
// 版本提取:从响应中提取软件版本信息
versions := fingerprint.ExtractVersions(string(data.Body), data.Headers)
for _, v := range versions {
matchedInfos = append(matchedInfos, fmt.Sprintf("%s/%s", v.Name, v.Version))
}
}
// 去重处理
matchedInfos = removeDuplicateElement(matchedInfos)
// 指纹信息已在 WebTitle 日志中统一输出,此处不再单独输出
return matchedInfos
}
// matchByRegex 使用正则规则匹配指纹
func matchByRegex(data CheckDatas) []string {
var matched []string
for _, rule := range fingerprint.RuleDatas {
// 跳过编译失败的规则
if rule.Compiled == nil {
continue
}
// 根据规则类型选择匹配内容
var isMatch bool
switch rule.Type {
case "code":
isMatch = rule.Compiled.MatchString(string(data.Body))
default:
isMatch = rule.Compiled.MatchString(data.Headers)
}
if isMatch {
matched = append(matched, rule.Name)
}
}
return matched
}
// matchByMd5 使用MD5指纹匹配
func matchByMd5(body []byte) string {
//nolint:gosec // G401: MD5用于内容指纹,非加密用途
contentMd5 := fmt.Sprintf("%x", md5.Sum(body))
for _, md5Info := range fingerprint.Md5Datas {
if contentMd5 == md5Info.Md5Str {
return md5Info.Name
}
}
return ""
}
// removeDuplicateElement 移除切片中的重复元素
func removeDuplicateElement(items []string) []string {
// 预分配空间
result := make([]string, 0, len(items))
seen := make(map[string]struct{}, len(items))
// 使用map去重
for _, item := range items {
if _, exists := seen[item]; !exists {
seen[item] = struct{}{}
result = append(result, item)
}
}
return result
}