mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
608 lines
17 KiB
Go
608 lines
17 KiB
Go
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()
|
||
} |