mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00

经Linus式架构审计,发现并修复插件系统中的具体问题: ## 核心修复 ### 1. 消除local插件GetPorts()方法冗余 - 删除21个local插件中无意义的GetPorts()方法 - 简化local.Plugin接口:移除端口概念 - 理由:本地插件不涉及网络,端口概念完全多余 ### 2. 消除web插件GetPorts()方法冗余 - 删除2个web插件中无用的GetPorts()方法 - 简化web.WebPlugin接口:专注智能HTTP检测 - 理由:Web插件使用动态HTTP检测,预定义端口无价值 ### 3. 统一插件命名规范 - 统一所有插件接口使用Name()方法(符合Go惯例) - 消除GetName()与Name()不一致问题 - 简化适配器:不再需要方法名转换 ## 技术改进 接口精简: - local插件:GetName() + GetPorts() → Name() - web插件:GetName() + GetPorts() → Name() - services插件:GetName() → Name()(保留GetPorts(),业务必需) 代码减少: - 删除23个无用GetPorts()方法 - 重命名52个Name()方法 - 简化3个插件接口定义 ## 影响范围 修改文件:55个插件文件 代码变更:-155行 +61行(净减少94行) 功能影响:零破坏性,保持所有业务逻辑不变 这是基于业务需求分析的精准重构,消除真正多余的部分, 保持系统架构合理性和向后兼容性。
185 lines
4.4 KiB
Go
185 lines
4.4 KiB
Go
package local
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/shadow1ng/fscan/common"
|
|
)
|
|
|
|
// FileInfoPlugin 文件信息收集插件 - Linus式简化版本
|
|
//
|
|
// 设计哲学:删除所有不必要的复杂性
|
|
// - 没有继承体系
|
|
// - 没有权限检查(让系统告诉我们)
|
|
// - 没有平台检查(运行时错误更清晰)
|
|
// - 没有复杂配置(直接硬编码关键路径)
|
|
type FileInfoPlugin struct {
|
|
name string
|
|
}
|
|
|
|
// NewFileInfoPlugin 创建文件信息插件
|
|
func NewFileInfoPlugin() *FileInfoPlugin {
|
|
return &FileInfoPlugin{
|
|
name: "fileinfo",
|
|
}
|
|
}
|
|
|
|
// GetName 实现Plugin接口
|
|
func (p *FileInfoPlugin) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
|
|
// Scan 执行本地文件扫描 - 直接、简单、有效
|
|
func (p *FileInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult {
|
|
var foundFiles []string
|
|
|
|
// 扫描关键敏感文件位置 - 删除复杂的配置系统
|
|
sensitiveFiles := p.getSensitiveFiles()
|
|
for _, file := range sensitiveFiles {
|
|
if p.fileExists(file) {
|
|
foundFiles = append(foundFiles, file)
|
|
common.LogSuccess(fmt.Sprintf("发现敏感文件: %s", file))
|
|
}
|
|
}
|
|
|
|
// 搜索用户目录下的敏感文件 - 简化搜索逻辑
|
|
userFiles := p.searchUserFiles()
|
|
foundFiles = append(foundFiles, userFiles...)
|
|
|
|
// 构建结果
|
|
output := fmt.Sprintf("文件扫描完成 - 发现 %d 个敏感文件", len(foundFiles))
|
|
if len(foundFiles) > 0 {
|
|
output += "\n发现的文件:"
|
|
for _, file := range foundFiles {
|
|
output += "\n " + file
|
|
}
|
|
}
|
|
|
|
return &ScanResult{
|
|
Success: len(foundFiles) > 0,
|
|
Output: output,
|
|
Error: nil,
|
|
}
|
|
}
|
|
|
|
// getSensitiveFiles 获取关键敏感文件列表 - 删除复杂的初始化逻辑
|
|
func (p *FileInfoPlugin) getSensitiveFiles() []string {
|
|
var files []string
|
|
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
files = []string{
|
|
"C:\\boot.ini",
|
|
"C:\\Windows\\System32\\config\\SAM",
|
|
"C:\\Windows\\repair\\sam",
|
|
}
|
|
|
|
// 添加用户相关路径
|
|
if homeDir, err := os.UserHomeDir(); err == nil {
|
|
files = append(files, []string{
|
|
filepath.Join(homeDir, ".ssh", "id_rsa"),
|
|
filepath.Join(homeDir, ".aws", "credentials"),
|
|
filepath.Join(homeDir, ".azure", "accessTokens.json"),
|
|
}...)
|
|
}
|
|
|
|
case "linux", "darwin":
|
|
files = []string{
|
|
"/etc/passwd",
|
|
"/etc/shadow",
|
|
"/root/.ssh/id_rsa",
|
|
"/root/.ssh/authorized_keys",
|
|
"/root/.bash_history",
|
|
"/etc/nginx/nginx.conf",
|
|
"/etc/apache2/apache2.conf",
|
|
}
|
|
|
|
// 添加用户相关路径
|
|
if homeDir, err := os.UserHomeDir(); err == nil {
|
|
files = append(files, []string{
|
|
filepath.Join(homeDir, ".ssh", "id_rsa"),
|
|
filepath.Join(homeDir, ".aws", "credentials"),
|
|
filepath.Join(homeDir, ".bash_history"),
|
|
}...)
|
|
}
|
|
}
|
|
|
|
return files
|
|
}
|
|
|
|
// searchUserFiles 搜索用户目录敏感文件 - 简化搜索逻辑
|
|
func (p *FileInfoPlugin) searchUserFiles() []string {
|
|
var foundFiles []string
|
|
|
|
homeDir, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return foundFiles
|
|
}
|
|
|
|
// 关键目录 - 删除复杂的目录配置
|
|
searchDirs := []string{
|
|
filepath.Join(homeDir, "Desktop"),
|
|
filepath.Join(homeDir, "Documents"),
|
|
filepath.Join(homeDir, ".ssh"),
|
|
filepath.Join(homeDir, ".aws"),
|
|
}
|
|
|
|
// 敏感文件关键词 - 删除复杂的白名单系统
|
|
keywords := []string{"password", "key", "secret", "token", "credential", "passwd"}
|
|
|
|
for _, dir := range searchDirs {
|
|
if !p.dirExists(dir) {
|
|
continue
|
|
}
|
|
|
|
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
// 限制深度和大小 - 简单有效
|
|
if info.IsDir() || info.Size() > 1024*1024 { // 1MB
|
|
return nil
|
|
}
|
|
|
|
// 检查文件名是否包含敏感关键词
|
|
filename := strings.ToLower(filepath.Base(path))
|
|
for _, keyword := range keywords {
|
|
if strings.Contains(filename, keyword) {
|
|
foundFiles = append(foundFiles, path)
|
|
common.LogSuccess(fmt.Sprintf("发现潜在敏感文件: %s", path))
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
return foundFiles
|
|
}
|
|
|
|
// fileExists 检查文件是否存在
|
|
func (p *FileInfoPlugin) fileExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil
|
|
}
|
|
|
|
// dirExists 检查目录是否存在
|
|
func (p *FileInfoPlugin) dirExists(path string) bool {
|
|
info, err := os.Stat(path)
|
|
return err == nil && info.IsDir()
|
|
}
|
|
|
|
// 注册插件
|
|
func init() {
|
|
RegisterLocalPlugin("fileinfo", func() Plugin {
|
|
return NewFileInfoPlugin()
|
|
})
|
|
} |