mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-11-05 18:57:10 +00:00
**核心架构重构** - 重构目录结构:Common/ -> common/, Core/ -> core/, Plugins/ -> plugins/, WebScan/ -> webscan/ - 模块化设计:拆分common/为parsers/, logging/, i18n/, output/, proxy/等子模块 - 统一插件系统:消除Plugin/Scanner/LocalPlugin等重复接口 - 配置解析器重写:新增parsers包处理所有配置解析逻辑 - 国际化支持:完整的中英文i18n系统 **服务插件重构** (59个插件) - 所有服务插件采用统一接口设计 - 新增服务插件:ActiveMQ, Cassandra, Kafka, Neo4j, RabbitMQ, Rsync等 - 增强现有插件:SSH, MySQL, Redis, SMB, FTP, PostgreSQL等 - 本地功能插件:AVDetect, Cleaner, CronTask, KeyLogger, SystemInfo等26个 - 智能错误分类和重试机制 - 并发暴力破解优化 **核心扫描引擎** - 端口扫描重构:支持SYN/Connect/ICMP多种模式 - 服务识别增强:集成nmap-service-probes指纹库 - Web扫描优化:title抓取、POC检测、指纹识别 - 进度条系统:实时显示扫描进度、发包统计、内存使用 - 发包频率控制:支持-rate和-maxpkts限制 **新增功能** - user:pass格式字典支持 (-upf参数) #179 - fscan-lite C语言版本:轻量级无依赖版本 - 本地扫描模式:26个本地安全检测插件 - API模式:支持远程调用 - Docker测试环境:13个服务的docker-compose配置 **Bug修复** - 修复并发输出混乱问题 - 修复包计数双重统计 - 修复进度条显示不准确 - 修复-no参数被忽略 - 修复SMB/SSH认证问题 - 修复Oracle TNS服务识别错误 - 修复SafeDialTimeout缺失TCP计数 **性能优化** - 删除大量死代码和冗余函数 - 简化过度工程设计 - 优化端口扫描性能 - 减少内存占用 - 清理重复代码 **测试和CI/CD** - 新增核心模块单元测试 (2000+ loc) - GitHub Actions优化:统一构建发布流程 - 支持fscan和fscan-lite统一发布 - 中文化工作流配置 **文档** - 更新README文档 - 新增插件开发文档 - 完善国际化文档 **依赖更新** - 更新go.mod依赖 - 清理无用依赖 - 升级核心库版本 统计: - 删除文件:61个旧架构文件 - 新增文件:500+个模块化文件 - 代码行数:~50000 lines - Commits压缩:289 -> 1
206 lines
5.1 KiB
Go
206 lines
5.1 KiB
Go
package local
|
||
|
||
import (
|
||
_ "embed"
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"os/exec"
|
||
"runtime"
|
||
"strings"
|
||
|
||
"github.com/shadow1ng/fscan/common"
|
||
"github.com/shadow1ng/fscan/plugins"
|
||
)
|
||
|
||
//go:embed auto.json
|
||
var avDatabase []byte
|
||
|
||
// AVProduct AV产品信息结构
|
||
type AVProduct struct {
|
||
Processes []string `json:"processes"`
|
||
URL string `json:"url"`
|
||
}
|
||
|
||
// AVDetectPlugin AV/EDR检测插件 - Linus式简化版本
|
||
//
|
||
// 设计哲学:"做一件事并做好" - 专注AV检测
|
||
// - 使用JSON数据库加载AV信息
|
||
// - 删除复杂的结果结构体
|
||
// - 跨平台支持,运行时适配
|
||
type AVDetectPlugin struct {
|
||
plugins.BasePlugin
|
||
avProducts map[string]AVProduct
|
||
}
|
||
|
||
// NewAVDetectPlugin 创建AV检测插件
|
||
func NewAVDetectPlugin() *AVDetectPlugin {
|
||
plugin := &AVDetectPlugin{
|
||
BasePlugin: plugins.NewBasePlugin("avdetect"),
|
||
avProducts: make(map[string]AVProduct),
|
||
}
|
||
|
||
// 加载AV数据库
|
||
if err := json.Unmarshal(avDatabase, &plugin.avProducts); err != nil {
|
||
common.LogError(fmt.Sprintf("加载AV数据库失败: %v", err))
|
||
} else {
|
||
common.LogInfo(fmt.Sprintf("加载了 %d 个AV产品信息", len(plugin.avProducts)))
|
||
}
|
||
|
||
return plugin
|
||
}
|
||
|
||
|
||
|
||
// Scan 执行AV/EDR检测 - 直接、有效
|
||
func (p *AVDetectPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult {
|
||
var output strings.Builder
|
||
var detectedAVs []string
|
||
|
||
output.WriteString("=== AV/EDR检测 ===\n")
|
||
|
||
// 获取运行进程
|
||
processes := p.getRunningProcesses()
|
||
if len(processes) == 0 {
|
||
return &ScanResult{
|
||
Success: false,
|
||
Output: "无法获取进程列表",
|
||
Error: fmt.Errorf("进程列表获取失败"),
|
||
}
|
||
}
|
||
|
||
output.WriteString(fmt.Sprintf("扫描进程数: %d\n\n", len(processes)))
|
||
|
||
// 检测AV产品 - 使用JSON数据库
|
||
for avName, avProduct := range p.avProducts {
|
||
var foundProcesses []string
|
||
|
||
for _, avProcess := range avProduct.Processes {
|
||
for _, runningProcess := range processes {
|
||
// 提取进程名部分进行匹配(去除PID信息)
|
||
processName := runningProcess
|
||
if strings.Contains(runningProcess, " (PID: ") {
|
||
processName = strings.Split(runningProcess, " (PID: ")[0]
|
||
}
|
||
|
||
// 简单字符串匹配,忽略大小写
|
||
if strings.Contains(strings.ToLower(processName), strings.ToLower(avProcess)) {
|
||
foundProcesses = append(foundProcesses, runningProcess)
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(foundProcesses) > 0 {
|
||
detectedAVs = append(detectedAVs, avName)
|
||
output.WriteString(fmt.Sprintf("✓ 检测到 %s:\n", avName))
|
||
|
||
common.LogSuccess(fmt.Sprintf("检测到AV: %s (%d个进程)", avName, len(foundProcesses)))
|
||
|
||
// 输出详细进程信息到控制台
|
||
for _, proc := range foundProcesses {
|
||
output.WriteString(fmt.Sprintf(" - %s\n", proc))
|
||
common.LogInfo(fmt.Sprintf(" - %s", proc))
|
||
}
|
||
output.WriteString("\n")
|
||
}
|
||
}
|
||
|
||
// 统计结果
|
||
output.WriteString("=== 检测结果 ===\n")
|
||
output.WriteString(fmt.Sprintf("检测到的AV产品: %d个\n", len(detectedAVs)))
|
||
|
||
if len(detectedAVs) > 0 {
|
||
output.WriteString("检测到的产品: " + strings.Join(detectedAVs, ", ") + "\n")
|
||
} else {
|
||
output.WriteString("未检测到已知的AV/EDR产品\n")
|
||
}
|
||
|
||
return &ScanResult{
|
||
Success: len(detectedAVs) > 0,
|
||
Output: output.String(),
|
||
Error: nil,
|
||
}
|
||
}
|
||
|
||
// getRunningProcesses 获取运行进程列表 - 跨平台适配
|
||
func (p *AVDetectPlugin) getRunningProcesses() []string {
|
||
var processes []string
|
||
|
||
switch runtime.GOOS {
|
||
case "windows":
|
||
processes = p.getWindowsProcesses()
|
||
case "linux", "darwin":
|
||
processes = p.getUnixProcesses()
|
||
default:
|
||
// 不支持的平台,返回空列表
|
||
return processes
|
||
}
|
||
|
||
return processes
|
||
}
|
||
|
||
// getWindowsProcesses 获取Windows进程 - 包含PID和进程名
|
||
func (p *AVDetectPlugin) getWindowsProcesses() []string {
|
||
var processes []string
|
||
|
||
// 使用tasklist命令
|
||
cmd := exec.Command("tasklist", "/fo", "csv", "/nh")
|
||
output, err := cmd.Output()
|
||
if err != nil {
|
||
return processes
|
||
}
|
||
|
||
lines := strings.Split(string(output), "\n")
|
||
for _, line := range lines {
|
||
line = strings.TrimSpace(line)
|
||
if line == "" {
|
||
continue
|
||
}
|
||
|
||
// 解析CSV格式:进程名,PID,会话名,会话号,内存
|
||
if strings.HasPrefix(line, "\"") {
|
||
parts := strings.Split(line, "\",\"")
|
||
if len(parts) >= 2 {
|
||
processName := strings.Trim(parts[0], "\"")
|
||
pid := strings.Trim(parts[1], "\"")
|
||
if processName != "" && pid != "" {
|
||
// 格式:进程名 (PID: xxxx)
|
||
processInfo := fmt.Sprintf("%s (PID: %s)", processName, pid)
|
||
processes = append(processes, processInfo)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return processes
|
||
}
|
||
|
||
// getUnixProcesses 获取Unix进程 - 简化实现
|
||
func (p *AVDetectPlugin) getUnixProcesses() []string {
|
||
var processes []string
|
||
|
||
// 使用ps命令
|
||
cmd := exec.Command("ps", "-eo", "comm")
|
||
output, err := cmd.Output()
|
||
if err != nil {
|
||
return processes
|
||
}
|
||
|
||
lines := strings.Split(string(output), "\n")
|
||
for _, line := range lines {
|
||
line = strings.TrimSpace(line)
|
||
if line != "" && line != "COMMAND" {
|
||
processes = append(processes, line)
|
||
}
|
||
}
|
||
|
||
return processes
|
||
}
|
||
|
||
|
||
// 注册插件
|
||
func init() {
|
||
RegisterLocalPlugin("avdetect", func() Plugin {
|
||
return NewAVDetectPlugin()
|
||
})
|
||
} |