package fileinfo import ( "context" "fmt" "os" "path/filepath" "runtime" "strings" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/plugins/base" "github.com/shadow1ng/fscan/plugins/local" ) // FileInfoPlugin 文件信息收集插件 - 使用简化架构 type FileInfoPlugin struct { *local.BaseLocalPlugin // 配置选项 blacklist []string whitelist []string sensitiveFiles []string searchDirs []string } // NewFileInfoPlugin 创建文件信息收集插件 - 简化版本 func NewFileInfoPlugin() *FileInfoPlugin { metadata := &base.PluginMetadata{ Name: "fileinfo", Version: "1.0.0", Author: "fscan-team", Description: "本地敏感文件信息收集插件", Category: "local", Tags: []string{"local", "fileinfo", "sensitive"}, Protocols: []string{"local"}, } plugin := &FileInfoPlugin{ BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), blacklist: []string{ // 可执行文件和库 ".exe", ".dll", ".so", ".dylib", ".sys", ".msi", ".com", ".scr", // 图像和媒体文件 ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".tiff", ".svg", ".mp3", ".mp4", ".avi", ".mov", ".wmv", ".wav", ".flac", // 文档和归档文件(通常不含敏感信息) ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".zip", ".rar", ".7z", ".tar", ".gz", // 代码和项目文件 ".pyc", ".pyo", ".class", ".obj", ".o", ".lib", ".a", // 系统和临时文件 ".tmp", ".temp", ".log", ".cache", ".bak", ".swp", ".manifest", ".mui", ".nls", ".dat", ".bin", ".pdb", // 系统目录 "windows\\system32", "windows\\syswow64", "windows\\winsxs", "program files", "program files (x86)", "programdata", "appdata\\local\\temp", "appdata\\local\\microsoft\\windows", "locale", "winsxs", "windows\\sys", "node_modules", ".git", "__pycache__", ".vs", ".vscode\\extensions", "dist\\bundled", }, whitelist: []string{ // 中文关键词 - 更精确的匹配 "密码", "账号", "用户", "凭据", "证书", "私钥", "公钥", "令牌", "口令", "认证", "授权", "登录", // 英文关键词 - 敏感文件标识 "password", "passwd", "credential", "token", "auth", "login", "key", "secret", "cert", "certificate", "private", "public", "rsa", "ssh", "api_key", "access_key", "session", // 配置文件 - 但更具体 ".env", "database", "db_", "connection", "conn_", // 特定敏感文件名 "id_rsa", "id_dsa", "authorized_keys", "known_hosts", "shadow", "passwd", "credentials", "keystore", }, } // 设置平台支持 plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) // 不需要特殊权限 plugin.SetRequiresPrivileges(false) // 初始化敏感文件和搜索目录 plugin.initSensitiveFiles() return plugin } // Scan 重写扫描方法以确保调用正确的ScanLocal实现 func (p *FileInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { return p.ScanLocal(ctx, info) } // initSensitiveFiles 初始化敏感文件列表 func (p *FileInfoPlugin) initSensitiveFiles() { homeDir, _ := os.UserHomeDir() switch runtime.GOOS { case "windows": p.sensitiveFiles = []string{ "C:\\boot.ini", "C:\\windows\\system32\\inetsrv\\MetaBase.xml", "C:\\windows\\repair\\sam", "C:\\windows\\system32\\config\\sam", } if homeDir != "" { p.sensitiveFiles = append(p.sensitiveFiles, []string{ filepath.Join(homeDir, "AppData", "Local", "Google", "Chrome", "User Data", "Default", "Login Data"), filepath.Join(homeDir, "AppData", "Local", "Microsoft", "Edge", "User Data", "Default", "Login Data"), filepath.Join(homeDir, "AppData", "Roaming", "Mozilla", "Firefox", "Profiles"), }...) } case "linux", "darwin": p.sensitiveFiles = []string{ "/etc/apache/httpd.conf", "/etc/httpd/conf/httpd.conf", "/etc/nginx/nginx.conf", "/etc/hosts.deny", "/etc/ssh/ssh_config", "/etc/resolv.conf", "/root/.ssh/authorized_keys", "/root/.ssh/id_rsa", "/root/.bash_history", } } p.searchDirs = p.getOptimizedSearchDirs() } // getOptimizedSearchDirs 获取优化的搜索目录(避免扫描大型系统目录) func (p *FileInfoPlugin) getOptimizedSearchDirs() []string { var dirs []string homeDir, _ := os.UserHomeDir() switch runtime.GOOS { case "windows": dirs = []string{ // 用户目录的关键文件夹 homeDir, filepath.Join(homeDir, "Desktop"), filepath.Join(homeDir, "Documents"), filepath.Join(homeDir, "Downloads"), filepath.Join(homeDir, ".ssh"), filepath.Join(homeDir, ".aws"), filepath.Join(homeDir, ".azure"), filepath.Join(homeDir, ".kube"), // 公共目录的关键部分 "C:\\Users\\Public\\Documents", "C:\\Users\\Public\\Desktop", } case "linux", "darwin": dirs = []string{ homeDir, filepath.Join(homeDir, "Desktop"), filepath.Join(homeDir, "Documents"), filepath.Join(homeDir, "Downloads"), filepath.Join(homeDir, ".ssh"), filepath.Join(homeDir, ".aws"), filepath.Join(homeDir, ".azure"), filepath.Join(homeDir, ".kube"), "/opt", "/usr/local/bin", "/var/www", } } // 过滤存在的目录 var validDirs []string for _, dir := range dirs { if _, err := os.Stat(dir); err == nil { validDirs = append(validDirs, dir) } } return validDirs } // ScanLocal 执行本地文件扫描 - 简化版本 func (p *FileInfoPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { common.LogInfo("开始本地敏感文件扫描...") foundFiles := make([]string, 0) // 扫描固定位置的敏感文件 common.LogDebug("扫描固定敏感文件位置...") for _, file := range p.sensitiveFiles { if p.checkFile(file) { foundFiles = append(foundFiles, file) common.LogSuccess(fmt.Sprintf("发现敏感文件: %s", file)) } } // 根据规则搜索敏感文件 common.LogDebug("按规则搜索敏感文件...") searchFiles := p.searchSensitiveFiles() foundFiles = append(foundFiles, searchFiles...) // 获取系统信息 systemInfo := p.GetSystemInfo() result := &base.ScanResult{ Success: true, Service: "FileInfo", Banner: fmt.Sprintf("检测完成: 发现 %d 个敏感文件", len(foundFiles)), Extra: map[string]interface{}{ "files": foundFiles, "total_count": len(foundFiles), "platform": runtime.GOOS, "system_info": systemInfo, "search_dirs": len(p.searchDirs), }, } if len(foundFiles) > 0 { common.LogSuccess(fmt.Sprintf("本地文件扫描完成,共发现 %d 个敏感文件", len(foundFiles))) for _, file := range foundFiles { common.LogSuccess(fmt.Sprintf("发现: %s", file)) } } else { common.LogInfo("未发现敏感文件") } return result, nil } // GetLocalData 获取本地文件数据 func (p *FileInfoPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { data := make(map[string]interface{}) // 获取系统信息 data["platform"] = runtime.GOOS data["arch"] = runtime.GOARCH 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 提取敏感文件数据 func (p *FileInfoPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { // 文件信息收集插件主要是扫描,不进行深度利用 return &base.ExploitResult{ Success: true, Output: "文件信息收集完成", Data: data, }, nil } // checkFile 检查文件是否存在 func (p *FileInfoPlugin) checkFile(path string) bool { if _, err := os.Stat(path); err == nil { return true } return false } // searchSensitiveFiles 搜索敏感文件(限制深度和数量) func (p *FileInfoPlugin) searchSensitiveFiles() []string { var foundFiles []string maxFiles := 50 // 限制最多找到的文件数量 maxDepth := 4 // 限制递归深度 for _, searchPath := range p.searchDirs { if len(foundFiles) >= maxFiles { break } baseDepth := strings.Count(searchPath, string(filepath.Separator)) filepath.Walk(searchPath, func(path string, info os.FileInfo, err error) error { if err != nil { return nil } // 限制递归深度 currentDepth := strings.Count(path, string(filepath.Separator)) if currentDepth-baseDepth > maxDepth { if info.IsDir() { return filepath.SkipDir } return nil } // 跳过黑名单文件/目录 if p.isBlacklisted(path) { if info.IsDir() { return filepath.SkipDir } return nil } // 限制文件数量 if len(foundFiles) >= maxFiles { return filepath.SkipDir } // 跳过过大的文件(可能不是配置文件) if !info.IsDir() && info.Size() > 10*1024*1024 { // 10MB return nil } // 检查白名单关键词 if !info.IsDir() && p.isWhitelisted(info.Name()) { foundFiles = append(foundFiles, path) common.LogSuccess(fmt.Sprintf("发现潜在敏感文件: %s", path)) } return nil }) } return foundFiles } // isBlacklisted 检查是否在黑名单中 func (p *FileInfoPlugin) isBlacklisted(path string) bool { pathLower := strings.ToLower(path) for _, black := range p.blacklist { if strings.Contains(pathLower, black) { return true } } return false } // isWhitelisted 检查是否匹配白名单 func (p *FileInfoPlugin) isWhitelisted(filename string) bool { filenameLower := strings.ToLower(filename) for _, white := range p.whitelist { if strings.Contains(filenameLower, white) { return true } } return false } // RegisterFileInfoPlugin 注册文件信息收集插件 func RegisterFileInfoPlugin() { factory := base.NewSimplePluginFactory( &base.PluginMetadata{ Name: "fileinfo", Version: "1.0.0", Author: "fscan-team", Description: "本地敏感文件信息收集插件", Category: "local", Tags: []string{"local", "fileinfo", "sensitive"}, Protocols: []string{"local"}, }, func() base.Plugin { return NewFileInfoPlugin() }, ) base.GlobalPluginRegistry.Register("fileinfo", factory) } // GetInfo 获取插件信息 func (p *FileInfoPlugin) GetInfo() string { var info strings.Builder info.WriteString("本地敏感文件扫描插件\n") info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) info.WriteString(fmt.Sprintf("扫描目录: %d 个\n", len(p.searchDirs))) info.WriteString(fmt.Sprintf("固定文件: %d 个\n", len(p.sensitiveFiles))) info.WriteString("功能: 扫描系统敏感文件和配置信息\n") return info.String() } // 插件注册函数 func init() { RegisterFileInfoPlugin() }