fscan/plugins/local/avdetect/plugin.go
ZacharyZcR 4a3f281b6b refactor: 统一Plugins目录大小写为小写
- 将所有Plugins路径重命名为plugins
- 修复Git索引与实际文件系统大小写不一致问题
- 确保跨平台兼容性和路径一致性
2025-08-12 13:08:06 +08:00

608 lines
17 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 avdetect
import (
"bufio"
"context"
_ "embed"
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strings"
"time"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/plugins/base"
"github.com/shadow1ng/fscan/plugins/local"
)
//go:embed auto.json
var embeddedAVDatabase []byte
// AVDetectPlugin AV/EDR检测插件 - 使用简化架构
type AVDetectPlugin struct {
*local.BaseLocalPlugin
avDatabase map[string]AVProduct
}
// AVProduct AV/EDR产品信息
type AVProduct struct {
Processes []string `json:"processes"`
URL string `json:"url"`
}
// ProcessInfo 进程信息
type ProcessInfo struct {
Name string
PID string
SessionName string
SessionID string
MemUsage string
Services []string // 服务信息
}
// DetectionResult 检测结果
type DetectionResult struct {
ProductName string `json:"product_name"`
DetectedProcesses []ProcessInfo `json:"detected_processes"`
URL string `json:"url"`
RiskLevel string `json:"risk_level"`
Category string `json:"category"`
}
// NewAVDetectPlugin 创建AV/EDR检测插件 - 简化版本
func NewAVDetectPlugin() *AVDetectPlugin {
metadata := &base.PluginMetadata{
Name: "avdetect",
Version: "1.0.0",
Author: "fscan-team",
Description: "自动化AV/EDR检测插件基于嵌入式规则库识别安全软件",
Category: "local",
Tags: []string{"local", "av", "edr", "detection", "security"},
Protocols: []string{"local"},
}
plugin := &AVDetectPlugin{
BaseLocalPlugin: local.NewBaseLocalPlugin(metadata),
avDatabase: make(map[string]AVProduct),
}
// 设置支持的平台 (仅Windows)
plugin.SetPlatformSupport([]string{"windows"})
// 不需要特殊权限
plugin.SetRequiresPrivileges(false)
return plugin
}
// Initialize 初始化插件
func (p *AVDetectPlugin) Initialize() error {
// 先调用基类初始化
if err := p.BaseLocalPlugin.Initialize(); err != nil {
return err
}
// 加载AV数据库
return p.loadAVDatabase()
}
// getRunningProcesses 获取运行中的进程列表
func (p *AVDetectPlugin) getRunningProcesses() ([]ProcessInfo, error) {
var processes []ProcessInfo
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
// Windows使用PowerShell获取进程信息以避免编码问题
cmd = exec.Command("powershell", "-Command", "Get-Process | Select-Object Name,Id,ProcessName | ConvertTo-Csv -NoTypeInformation")
case "linux", "darwin":
// Unix-like系统使用ps命令
cmd = exec.Command("ps", "aux")
default:
return nil, fmt.Errorf("不支持的操作系统: %s", runtime.GOOS)
}
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("执行命令失败: %v", err)
}
// 解析命令输出
processes, err = p.parseProcessOutput(string(output))
if err != nil {
return nil, fmt.Errorf("解析进程信息失败: %v", err)
}
return processes, nil
}
// parseProcessOutput 解析进程命令输出
func (p *AVDetectPlugin) parseProcessOutput(output string) ([]ProcessInfo, error) {
var processes []ProcessInfo
scanner := bufio.NewScanner(strings.NewReader(output))
switch runtime.GOOS {
case "windows":
// 跳过CSV标题行
if scanner.Scan() {
// 标题行,跳过
}
for scanner.Scan() {
line := scanner.Text()
if line == "" {
continue
}
// 解析PowerShell CSV格式Name,Id,ProcessName
fields := p.parseCSVLine(line)
if len(fields) >= 3 {
processName := strings.Trim(fields[0], "\"")
// 如果进程名不包含.exe则添加
if !strings.HasSuffix(strings.ToLower(processName), ".exe") {
processName += ".exe"
}
process := ProcessInfo{
Name: processName,
PID: strings.Trim(fields[1], "\""),
}
processes = append(processes, process)
}
}
case "linux", "darwin":
// 跳过ps命令的标题行
if scanner.Scan() {
// 标题行,跳过
}
for scanner.Scan() {
line := scanner.Text()
if line == "" {
continue
}
// 解析ps aux输出
fields := strings.Fields(line)
if len(fields) >= 11 {
process := ProcessInfo{
Name: fields[10], // 命令名
PID: fields[1], // PID
MemUsage: fields[5], // 内存使用
}
processes = append(processes, process)
}
}
}
return processes, scanner.Err()
}
// parseCSVLine 解析CSV行处理引号内的逗号
func (p *AVDetectPlugin) parseCSVLine(line string) []string {
var fields []string
var current strings.Builder
inQuotes := false
for i, char := range line {
switch char {
case '"':
inQuotes = !inQuotes
current.WriteRune(char)
case ',':
if inQuotes {
current.WriteRune(char)
} else {
fields = append(fields, current.String())
current.Reset()
}
default:
current.WriteRune(char)
}
// 处理行尾
if i == len(line)-1 {
fields = append(fields, current.String())
}
}
return fields
}
// Scan 重写扫描方法以确保调用正确的ScanLocal实现
func (p *AVDetectPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
return p.ScanLocal(ctx, info)
}
// ScanLocal 执行AV/EDR检测扫描 - 简化版本
func (p *AVDetectPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
common.LogInfo("开始AV/EDR安全软件检测...")
// 获取运行进程
processes, err := p.getRunningProcesses()
if err != nil {
common.LogError(fmt.Sprintf("获取进程列表失败: %v", err))
// 不返回错误,继续执行但结果可能不完整
processes = []ProcessInfo{}
}
common.LogDebug(fmt.Sprintf("获取到 %d 个运行进程", len(processes)))
// 检测AV/EDR产品
detectionResults := p.detectAVEDR(processes)
// 获取系统信息
systemInfo := p.GetSystemInfo()
// 生成检测报告
report := p.generateDetectionReport(detectionResults, systemInfo)
if len(detectionResults) == 0 {
common.LogInfo("未检测到已知的AV/EDR安全产品")
return &base.ScanResult{
Success: true,
Service: "AVDetect",
Banner: "未检测到已知的AV/EDR安全产品",
Extra: map[string]interface{}{
"detected_products": detectionResults,
"total_processes": len(processes),
"detection_report": report,
"platform": runtime.GOOS,
"database_products": len(p.avDatabase),
},
}, nil
}
// 输出检测结果
common.LogInfo(fmt.Sprintf("[+] AV/EDR检测完成: 发现 %d 个安全产品", len(detectionResults)))
for _, result := range detectionResults {
common.LogInfo(fmt.Sprintf("[+] 检测到: %s (%d个进程)", result.ProductName, len(result.DetectedProcesses)))
}
result := &base.ScanResult{
Success: true,
Service: "AVDetect",
Banner: fmt.Sprintf("检测完成: 发现 %d 个安全产品", len(detectionResults)),
Extra: map[string]interface{}{
"detected_products": detectionResults,
"total_processes": len(processes),
"detection_report": report,
"platform": runtime.GOOS,
"database_products": len(p.avDatabase),
},
}
if len(detectionResults) > 0 {
common.LogSuccess(fmt.Sprintf("AV/EDR检测完成: 发现 %d 个安全产品", len(detectionResults)))
for _, detection := range detectionResults {
common.LogSuccess(fmt.Sprintf("检测到: %s (%d个进程)", detection.ProductName, len(detection.DetectedProcesses)))
}
} else {
common.LogBase("未检测到已知的AV/EDR安全产品")
}
return result, nil
}
// loadAVDatabase 加载AV/EDR数据库
func (p *AVDetectPlugin) loadAVDatabase() error {
// 首先尝试使用嵌入的数据库
common.LogDebug("使用嵌入的AV/EDR规则数据库")
err := json.Unmarshal(embeddedAVDatabase, &p.avDatabase)
if err != nil {
return fmt.Errorf("解析嵌入的AV数据库失败: %v", err)
}
if len(p.avDatabase) == 0 {
return fmt.Errorf("嵌入的AV数据库为空或格式错误")
}
return nil
}
// detectAVEDR 检测AV/EDR产品
func (p *AVDetectPlugin) detectAVEDR(processes []ProcessInfo) []DetectionResult {
var results []DetectionResult
processMap := make(map[string][]ProcessInfo)
// 构建进程名称映射,忽略大小写
for _, process := range processes {
processName := strings.ToLower(process.Name)
processMap[processName] = append(processMap[processName], process)
}
// 遍历AV数据库进行匹配
for productName, avProduct := range p.avDatabase {
var detectedProcesses []ProcessInfo
// 检查每个已知进程
for _, targetProcess := range avProduct.Processes {
targetProcessLower := strings.ToLower(targetProcess)
// 精确匹配
if matchedProcesses, exists := processMap[targetProcessLower]; exists {
detectedProcesses = append(detectedProcesses, matchedProcesses...)
} else {
// 模糊匹配(去除扩展名)
targetWithoutExt := strings.TrimSuffix(targetProcessLower, filepath.Ext(targetProcessLower))
for processName, matchedProcesses := range processMap {
processWithoutExt := strings.TrimSuffix(processName, filepath.Ext(processName))
if processWithoutExt == targetWithoutExt {
detectedProcesses = append(detectedProcesses, matchedProcesses...)
break
}
}
}
}
// 如果检测到进程,添加到结果中
if len(detectedProcesses) > 0 {
// 去重
detectedProcesses = p.deduplicateProcesses(detectedProcesses)
result := DetectionResult{
ProductName: productName,
DetectedProcesses: detectedProcesses,
URL: avProduct.URL,
RiskLevel: p.assessRiskLevel(productName, detectedProcesses),
Category: p.categorizeProduct(productName),
}
results = append(results, result)
}
}
// 按检测到的进程数量排序
sort.Slice(results, func(i, j int) bool {
return len(results[i].DetectedProcesses) > len(results[j].DetectedProcesses)
})
return results
}
// deduplicateProcesses 去重进程列表
func (p *AVDetectPlugin) deduplicateProcesses(processes []ProcessInfo) []ProcessInfo {
seen := make(map[string]bool)
var result []ProcessInfo
for _, process := range processes {
key := fmt.Sprintf("%s-%s", process.Name, process.PID)
if !seen[key] {
seen[key] = true
result = append(result, process)
}
}
return result
}
// assessRiskLevel 评估风险等级
func (p *AVDetectPlugin) assessRiskLevel(productName string, processes []ProcessInfo) string {
// 基于产品名称和进程数量评估风险等级
productLower := strings.ToLower(productName)
// 高风险EDR产品
highRiskKeywords := []string{"crowdstrike", "sentinelone", "cybereason", "endgame",
"fireeye", "trellix", "elastic security", "深信服", "奇安信", "天擎"}
for _, keyword := range highRiskKeywords {
if strings.Contains(productLower, strings.ToLower(keyword)) {
return "HIGH"
}
}
// 中等风险企业级AV
mediumRiskKeywords := []string{"kaspersky", "symantec", "mcafee", "趋势科技",
"bitdefender", "eset", "sophos", "火绒", "360"}
for _, keyword := range mediumRiskKeywords {
if strings.Contains(productLower, strings.ToLower(keyword)) {
return "MEDIUM"
}
}
// 根据进程数量判断
if len(processes) >= 3 {
return "MEDIUM"
}
return "LOW"
}
// categorizeProduct 产品分类
func (p *AVDetectPlugin) categorizeProduct(productName string) string {
productLower := strings.ToLower(productName)
// EDR产品
edrKeywords := []string{"edr", "endpoint", "crowdstrike", "sentinelone",
"cybereason", "深信服edr", "天擎", "elastic security"}
for _, keyword := range edrKeywords {
if strings.Contains(productLower, strings.ToLower(keyword)) {
return "EDR"
}
}
// 企业级防病毒
enterpriseKeywords := []string{"enterprise", "business", "server",
"corporate", "管理版", "企业版"}
for _, keyword := range enterpriseKeywords {
if strings.Contains(productLower, strings.ToLower(keyword)) {
return "Enterprise AV"
}
}
// 云安全
cloudKeywords := []string{"cloud", "阿里云", "腾讯云", "云锁", "云安全"}
for _, keyword := range cloudKeywords {
if strings.Contains(productLower, strings.ToLower(keyword)) {
return "Cloud Security"
}
}
// 主机防护
hostKeywords := []string{"host", "hips", "主机", "防护", "卫士"}
for _, keyword := range hostKeywords {
if strings.Contains(productLower, strings.ToLower(keyword)) {
return "Host Protection"
}
}
return "Traditional AV"
}
// generateDetectionReport 生成检测报告
func (p *AVDetectPlugin) generateDetectionReport(results []DetectionResult, systemInfo map[string]string) string {
var report strings.Builder
report.WriteString("=== AV/EDR 检测报告 ===\n")
report.WriteString(fmt.Sprintf("扫描时间: %s\n", time.Now().Format("2006-01-02 15:04:05")))
report.WriteString(fmt.Sprintf("系统平台: %s/%s\n", systemInfo["os"], systemInfo["arch"]))
report.WriteString(fmt.Sprintf("检测产品: %d 个\n\n", len(results)))
if len(results) == 0 {
report.WriteString("未检测到已知的AV/EDR产品\n")
report.WriteString("注意: 可能存在未知安全软件或进程伪装\n")
return report.String()
}
// 按风险等级分组
riskGroups := map[string][]DetectionResult{
"HIGH": {},
"MEDIUM": {},
"LOW": {},
}
for _, result := range results {
riskGroups[result.RiskLevel] = append(riskGroups[result.RiskLevel], result)
}
// 高风险产品
if len(riskGroups["HIGH"]) > 0 {
report.WriteString("🔴 高风险安全产品:\n")
for _, result := range riskGroups["HIGH"] {
report.WriteString(fmt.Sprintf(" • %s [%s] - %d 个进程\n",
result.ProductName, result.Category, len(result.DetectedProcesses)))
for _, process := range result.DetectedProcesses {
report.WriteString(fmt.Sprintf(" - %s (PID: %s)\n", process.Name, process.PID))
}
}
report.WriteString("\n")
}
// 中等风险产品
if len(riskGroups["MEDIUM"]) > 0 {
report.WriteString("🟡 中等风险安全产品:\n")
for _, result := range riskGroups["MEDIUM"] {
report.WriteString(fmt.Sprintf(" • %s [%s] - %d 个进程\n",
result.ProductName, result.Category, len(result.DetectedProcesses)))
}
report.WriteString("\n")
}
// 低风险产品
if len(riskGroups["LOW"]) > 0 {
report.WriteString("🟢 低风险安全产品:\n")
for _, result := range riskGroups["LOW"] {
report.WriteString(fmt.Sprintf(" • %s [%s] - %d 个进程\n",
result.ProductName, result.Category, len(result.DetectedProcesses)))
}
report.WriteString("\n")
}
// 建议
report.WriteString("=== 渗透测试建议 ===\n")
if len(riskGroups["HIGH"]) > 0 {
report.WriteString("⚠️ 检测到高级EDR产品建议:\n")
report.WriteString(" - 使用内存加载技术\n")
report.WriteString(" - 避免落地文件\n")
report.WriteString(" - 使用白名单绕过技术\n")
report.WriteString(" - 考虑Living off the Land技术\n\n")
}
if len(results) > 1 {
report.WriteString("📊 检测到多个安全产品,环境复杂度较高\n")
}
return report.String()
}
// GetLocalData 获取AV/EDR检测本地数据
func (p *AVDetectPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) {
data := make(map[string]interface{})
// 获取系统信息
data["plugin_type"] = "avdetect"
data["platform"] = runtime.GOOS
data["arch"] = runtime.GOARCH
data["database_size"] = len(p.avDatabase)
if homeDir, err := os.UserHomeDir(); err == nil {
data["home_dir"] = homeDir
}
if workDir, err := os.Getwd(); err == nil {
data["work_dir"] = workDir
}
return data, nil
}
// ExtractData 提取AV/EDR检测数据
func (p *AVDetectPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) {
return &base.ExploitResult{
Success: true,
Output: "AV/EDR检测完成",
Data: data,
Extra: map[string]interface{}{
"detection_type": "automated",
"database_version": "auto.json",
},
}, nil
}
// GetInfo 获取插件信息
func (p *AVDetectPlugin) GetInfo() string {
var info strings.Builder
info.WriteString(fmt.Sprintf("AV/EDR自动检测插件 - 规则库: %d 个产品\n", len(p.avDatabase)))
info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", ")))
info.WriteString("检测方式: tasklist/ps + JSON规则匹配\n")
info.WriteString("功能: 自动识别常见AV/EDR产品并评估风险等级\n")
return info.String()
}
// RegisterAVDetectPlugin 注册AV/EDR检测插件
func RegisterAVDetectPlugin() {
factory := base.NewSimplePluginFactory(
&base.PluginMetadata{
Name: "avdetect",
Version: "1.0.0",
Author: "fscan-team",
Description: "自动化AV/EDR检测插件基于auto.json规则库识别安全软件",
Category: "local",
Tags: []string{"avdetect", "local", "av", "edr", "security"},
Protocols: []string{"local"},
},
func() base.Plugin {
return NewAVDetectPlugin()
},
)
base.GlobalPluginRegistry.Register("avdetect", factory)
}
// init 插件注册函数
func init() {
RegisterAVDetectPlugin()
}