mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
将 plugins/services、plugins/local、plugins/web、webscan 层的日志输出、 漏洞结果保存和 TCP 计数器从全局 common.Log*/GetGlobalState() 迁移到 session 实例方法,确保 SDK 并发扫描时各实例完全隔离。 - 50 个文件,所有插件日志走 session.Log* - DoRequest 加入 session 参数,计数器走 session.State - POC 执行器通过 POCContext.Session 传递 - 仅保留 init() 和 CEL runtime 等无 session 场景的全局回退
126 lines
2.8 KiB
Go
126 lines
2.8 KiB
Go
//go:build (plugin_cleaner || !plugin_selective) && !no_local
|
|
|
|
package local
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/shadow1ng/fscan/common"
|
|
"github.com/shadow1ng/fscan/common/i18n"
|
|
"github.com/shadow1ng/fscan/plugins"
|
|
)
|
|
|
|
type CleanerPlugin struct {
|
|
plugins.BasePlugin
|
|
}
|
|
|
|
func NewCleanerPlugin() *CleanerPlugin {
|
|
return &CleanerPlugin{BasePlugin: plugins.NewBasePlugin("cleaner")}
|
|
}
|
|
|
|
func (p *CleanerPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
|
|
var output strings.Builder
|
|
var cleaned int
|
|
|
|
// 清理 fscan 产物文件
|
|
workDir, _ := os.Getwd()
|
|
cleaned += p.cleanFiles(&output, workDir, []string{
|
|
"result.txt", "result.json", "result.csv",
|
|
"fscan_debug.log",
|
|
})
|
|
cleaned += p.cleanGlob(&output, os.TempDir(), "fscan_*")
|
|
|
|
// 清理持久化痕迹(平台特定)
|
|
cleaned += cleanPersistence(&output)
|
|
|
|
// 平台通用文件清理
|
|
switch runtime.GOOS {
|
|
case "linux", "darwin":
|
|
cleaned += p.cleanUnix(&output)
|
|
}
|
|
|
|
session.LogSuccess(i18n.Tr("cleaner_success", cleaned, 0))
|
|
|
|
return &plugins.Result{
|
|
Success: cleaned > 0,
|
|
Type: plugins.ResultTypeService,
|
|
Output: output.String(),
|
|
}
|
|
}
|
|
|
|
func (p *CleanerPlugin) cleanFiles(output *strings.Builder, dir string, names []string) int {
|
|
cleaned := 0
|
|
for _, name := range names {
|
|
path := filepath.Join(dir, name)
|
|
if err := os.Remove(path); err == nil {
|
|
fmt.Fprintln(output, i18n.Tr("cleaner_removed", path))
|
|
cleaned++
|
|
}
|
|
}
|
|
return cleaned
|
|
}
|
|
|
|
func (p *CleanerPlugin) cleanGlob(output *strings.Builder, dir, pattern string) int {
|
|
matches, _ := filepath.Glob(filepath.Join(dir, pattern))
|
|
cleaned := 0
|
|
for _, f := range matches {
|
|
if err := os.Remove(f); err == nil {
|
|
fmt.Fprintln(output, i18n.Tr("cleaner_removed", f))
|
|
cleaned++
|
|
}
|
|
}
|
|
return cleaned
|
|
}
|
|
|
|
func (p *CleanerPlugin) cleanUnix(output *strings.Builder) int {
|
|
cleaned := 0
|
|
homeDir, _ := os.UserHomeDir()
|
|
|
|
histFiles := []string{
|
|
filepath.Join(homeDir, ".bash_history"),
|
|
filepath.Join(homeDir, ".zsh_history"),
|
|
}
|
|
for _, hf := range histFiles {
|
|
if p.scrubHistory(hf) {
|
|
fmt.Fprintln(output, i18n.Tr("cleaner_history_removed", hf))
|
|
cleaned++
|
|
}
|
|
}
|
|
|
|
cleaned += p.cleanGlob(output, "/tmp", "fscan_*")
|
|
cleaned += p.cleanGlob(output, "/tmp", ".fscan*")
|
|
return cleaned
|
|
}
|
|
|
|
func (p *CleanerPlugin) scrubHistory(path string) bool {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
lines := strings.Split(string(data), "\n")
|
|
var kept []string
|
|
removed := false
|
|
for _, line := range lines {
|
|
if strings.Contains(strings.ToLower(line), "fscan") {
|
|
removed = true
|
|
continue
|
|
}
|
|
kept = append(kept, line)
|
|
}
|
|
if !removed {
|
|
return false
|
|
}
|
|
return os.WriteFile(path, []byte(strings.Join(kept, "\n")), 0600) == nil
|
|
}
|
|
|
|
func init() {
|
|
RegisterLocalPlugin("cleaner", func() Plugin {
|
|
return NewCleanerPlugin()
|
|
})
|
|
}
|