mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-26 21:21:53 +08:00
fix: 修复 socks5proxy/cleaner/minidump 三个插件问题
- socks5proxy: 监听地址从 127.0.0.1 改为 0.0.0.0,允许外部连接 - cleaner: 重写清理逻辑,精准匹配 fscan 产物,修复 glob 遍历大目录卡死问题, history 清理改为真正删除 fscan 相关行 - minidump: SeDebugPrivilege 提升失败时直接退出,不再卡 120 秒超时
This commit is contained in:
+75
-203
@@ -15,260 +15,132 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/plugins"
|
"github.com/shadow1ng/fscan/plugins"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CleanerPlugin 痕迹清理插件
|
|
||||||
// 设计哲学:保持原有功能,删除过度设计
|
|
||||||
// - 删除复杂的继承体系和配置选项
|
|
||||||
// - 直接实现清理功能
|
|
||||||
|
|
||||||
type CleanerPlugin struct {
|
type CleanerPlugin struct {
|
||||||
plugins.BasePlugin
|
plugins.BasePlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCleanerPlugin 创建系统痕迹清理插件
|
|
||||||
func NewCleanerPlugin() *CleanerPlugin {
|
func NewCleanerPlugin() *CleanerPlugin {
|
||||||
return &CleanerPlugin{
|
return &CleanerPlugin{BasePlugin: plugins.NewBasePlugin("cleaner")}
|
||||||
BasePlugin: plugins.NewBasePlugin("cleaner"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan 执行系统痕迹清理 - 直接、简单
|
|
||||||
func (p *CleanerPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
|
func (p *CleanerPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
|
||||||
var output strings.Builder
|
var output strings.Builder
|
||||||
var filesCleared, dirsCleared, sysCleared int
|
var cleaned int
|
||||||
|
|
||||||
output.WriteString("=== 系统痕迹清理 ===\n")
|
// 清理工作目录下的 fscan 产物
|
||||||
|
|
||||||
// 清理当前目录fscan相关文件
|
|
||||||
workDir, _ := os.Getwd()
|
workDir, _ := os.Getwd()
|
||||||
files := p.findFscanFiles(workDir)
|
cleaned += p.cleanFiles(&output, workDir, []string{
|
||||||
for _, file := range files {
|
"result.txt", "result.json", "result.csv",
|
||||||
if p.removeFile(file) {
|
"fscan_debug.log",
|
||||||
filesCleared++
|
})
|
||||||
_, _ = fmt.Fprintf(&output, "清理文件: %s\n", file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理临时目录fscan相关文件
|
// 清理临时目录
|
||||||
tempFiles := p.findTempFiles()
|
cleaned += p.cleanGlob(&output, os.TempDir(), "fscan_*")
|
||||||
for _, file := range tempFiles {
|
|
||||||
if p.removeFile(file) {
|
|
||||||
filesCleared++
|
|
||||||
_, _ = fmt.Fprintf(&output, "清理临时文件: %s\n", file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理日志和输出文件
|
// 清理自身可执行文件(如果在工作目录)
|
||||||
logFiles := p.findLogFiles(workDir)
|
if exe, err := os.Executable(); err == nil {
|
||||||
for _, file := range logFiles {
|
base := filepath.Base(exe)
|
||||||
if p.removeFile(file) {
|
if strings.Contains(strings.ToLower(base), "fscan") && filepath.Dir(exe) == workDir {
|
||||||
filesCleared++
|
cleaned += p.cleanFiles(&output, workDir, []string{base})
|
||||||
output.WriteString(fmt.Sprintf("清理日志: %s\n", file))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 平台特定清理
|
// 平台特定清理
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "windows":
|
case "windows":
|
||||||
sysCleared += p.clearWindowsTraces()
|
cleaned += p.cleanWindows(&output)
|
||||||
case "linux", "darwin":
|
case "linux", "darwin":
|
||||||
sysCleared += p.clearUnixTraces()
|
cleaned += p.cleanUnix(&output)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 输出统计
|
common.LogSuccess(i18n.Tr("cleaner_success", cleaned, 0))
|
||||||
output.WriteString(fmt.Sprintf("\n清理完成: 文件(%d) 目录(%d) 系统条目(%d)\n",
|
|
||||||
filesCleared, dirsCleared, sysCleared))
|
|
||||||
|
|
||||||
common.LogSuccess(i18n.Tr("cleaner_success", filesCleared, sysCleared))
|
|
||||||
|
|
||||||
return &plugins.Result{
|
return &plugins.Result{
|
||||||
Success: filesCleared > 0 || sysCleared > 0,
|
Success: cleaned > 0,
|
||||||
|
Type: plugins.ResultTypeService,
|
||||||
Output: output.String(),
|
Output: output.String(),
|
||||||
Error: nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// findFscanFiles 查找fscan相关文件 - 简化搜索逻辑
|
func (p *CleanerPlugin) cleanFiles(output *strings.Builder, dir string, names []string) int {
|
||||||
func (p *CleanerPlugin) findFscanFiles(dir string) []string {
|
cleaned := 0
|
||||||
var files []string
|
for _, name := range names {
|
||||||
|
path := filepath.Join(dir, name)
|
||||||
// fscan相关文件模式 - 直接硬编码
|
if err := os.Remove(path); err == nil {
|
||||||
patterns := []string{
|
output.WriteString(fmt.Sprintf("[清理] %s\n", path))
|
||||||
"fscan*.exe", "fscan*.log", "result*.txt", "result*.json",
|
cleaned++
|
||||||
"fscan_*", "*fscan*", "scan_result*", "vulnerability*",
|
}
|
||||||
|
}
|
||||||
|
return cleaned
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pattern := range patterns {
|
func (p *CleanerPlugin) cleanGlob(output *strings.Builder, dir, pattern string) int {
|
||||||
matches, _ := filepath.Glob(filepath.Join(dir, pattern))
|
matches, _ := filepath.Glob(filepath.Join(dir, pattern))
|
||||||
files = append(files, matches...)
|
cleaned := 0
|
||||||
|
for _, f := range matches {
|
||||||
|
if err := os.Remove(f); err == nil {
|
||||||
|
output.WriteString(fmt.Sprintf("[清理] %s\n", f))
|
||||||
|
cleaned++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cleaned
|
||||||
}
|
}
|
||||||
|
|
||||||
return files
|
func (p *CleanerPlugin) cleanWindows(output *strings.Builder) int {
|
||||||
|
cleaned := 0
|
||||||
|
// Prefetch 中的 fscan 记录
|
||||||
|
cleaned += p.cleanGlob(output, `C:\Windows\Prefetch`, "FSCAN*.pf")
|
||||||
|
// Recent 中的 fscan 快捷方式
|
||||||
|
if profile := os.Getenv("USERPROFILE"); profile != "" {
|
||||||
|
cleaned += p.cleanGlob(output, filepath.Join(profile, "Recent"), "fscan*.lnk")
|
||||||
|
}
|
||||||
|
return cleaned
|
||||||
}
|
}
|
||||||
|
|
||||||
// findTempFiles 查找临时文件
|
func (p *CleanerPlugin) cleanUnix(output *strings.Builder) int {
|
||||||
func (p *CleanerPlugin) findTempFiles() []string {
|
cleaned := 0
|
||||||
var files []string
|
|
||||||
tempDir := os.TempDir()
|
|
||||||
|
|
||||||
// 临时文件模式
|
|
||||||
patterns := []string{
|
|
||||||
"fscan_*", "scan_*", "tmp_scan*", "vulnerability_*",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
matches, _ := filepath.Glob(filepath.Join(tempDir, pattern))
|
|
||||||
files = append(files, matches...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
// findLogFiles 查找日志文件
|
|
||||||
func (p *CleanerPlugin) findLogFiles(dir string) []string {
|
|
||||||
var files []string
|
|
||||||
|
|
||||||
// 日志文件模式
|
|
||||||
logPatterns := []string{
|
|
||||||
"*.log", "scan*.txt", "error*.txt", "debug*.txt",
|
|
||||||
"output*.txt", "report*.txt", "*.out",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pattern := range logPatterns {
|
|
||||||
matches, _ := filepath.Glob(filepath.Join(dir, pattern))
|
|
||||||
for _, match := range matches {
|
|
||||||
// 只清理可能是扫描相关的日志
|
|
||||||
filename := strings.ToLower(filepath.Base(match))
|
|
||||||
if p.isScanRelatedLog(filename) {
|
|
||||||
files = append(files, match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
// isScanRelatedLog 判断是否为扫描相关日志
|
|
||||||
func (p *CleanerPlugin) isScanRelatedLog(filename string) bool {
|
|
||||||
scanKeywords := []string{
|
|
||||||
"scan", "fscan", "vulnerability", "result", "report",
|
|
||||||
"exploit", "brute", "port", "service", "web",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, keyword := range scanKeywords {
|
|
||||||
if strings.Contains(filename, keyword) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearWindowsTraces 清理Windows系统痕迹
|
|
||||||
func (p *CleanerPlugin) clearWindowsTraces() int {
|
|
||||||
cleared := 0
|
|
||||||
|
|
||||||
// 清理预读文件
|
|
||||||
prefetchDir := "C:\\Windows\\Prefetch"
|
|
||||||
if prefetchFiles := p.findPrefetchFiles(prefetchDir); len(prefetchFiles) > 0 {
|
|
||||||
for _, file := range prefetchFiles {
|
|
||||||
if p.removeFile(file) {
|
|
||||||
cleared++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理最近文档记录(注册表方式复杂,这里简化处理)
|
|
||||||
// 可以通过删除Recent文件夹的快捷方式
|
|
||||||
if recentDir := os.Getenv("USERPROFILE") + "\\Recent"; p.dirExists(recentDir) {
|
|
||||||
recentFiles, _ := filepath.Glob(filepath.Join(recentDir, "fscan*.lnk"))
|
|
||||||
for _, file := range recentFiles {
|
|
||||||
if p.removeFile(file) {
|
|
||||||
cleared++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cleared
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearUnixTraces 清理Unix系统痕迹
|
|
||||||
func (p *CleanerPlugin) clearUnixTraces() int {
|
|
||||||
cleared := 0
|
|
||||||
|
|
||||||
// 清理bash历史记录相关
|
|
||||||
homeDir, _ := os.UserHomeDir()
|
homeDir, _ := os.UserHomeDir()
|
||||||
historyFiles := []string{
|
|
||||||
|
// 从 history 文件中删除 fscan 相关行
|
||||||
|
histFiles := []string{
|
||||||
filepath.Join(homeDir, ".bash_history"),
|
filepath.Join(homeDir, ".bash_history"),
|
||||||
filepath.Join(homeDir, ".zsh_history"),
|
filepath.Join(homeDir, ".zsh_history"),
|
||||||
}
|
}
|
||||||
|
for _, hf := range histFiles {
|
||||||
for _, histFile := range historyFiles {
|
if p.scrubHistory(hf) {
|
||||||
if p.clearHistoryEntries(histFile) {
|
output.WriteString(fmt.Sprintf("[清理] %s 中的 fscan 记录\n", hf))
|
||||||
cleared++
|
cleaned++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清理/var/log中的相关日志(需要权限)
|
// /tmp 下的 fscan 残留
|
||||||
logDirs := []string{"/var/log", "/tmp"}
|
cleaned += p.cleanGlob(output, "/tmp", "fscan_*")
|
||||||
for _, logDir := range logDirs {
|
cleaned += p.cleanGlob(output, "/tmp", ".fscan*")
|
||||||
if p.dirExists(logDir) {
|
|
||||||
logFiles, _ := filepath.Glob(filepath.Join(logDir, "*fscan*"))
|
return cleaned
|
||||||
for _, file := range logFiles {
|
|
||||||
if p.removeFile(file) {
|
|
||||||
cleared++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cleared
|
func (p *CleanerPlugin) scrubHistory(path string) bool {
|
||||||
}
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
// findPrefetchFiles 查找预读文件
|
|
||||||
func (p *CleanerPlugin) findPrefetchFiles(dir string) []string {
|
|
||||||
var files []string
|
|
||||||
if !p.dirExists(dir) {
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
matches, _ := filepath.Glob(filepath.Join(dir, "FSCAN*.pf"))
|
|
||||||
files = append(files, matches...)
|
|
||||||
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearHistoryEntries 清理历史记录条目(简化实现)
|
|
||||||
func (p *CleanerPlugin) clearHistoryEntries(histFile string) bool {
|
|
||||||
// 这里简化实现:不修改历史文件内容
|
|
||||||
// 实际应该是读取文件,删除包含fscan的行,然后写回
|
|
||||||
// 为简化,这里只记录找到相关历史文件
|
|
||||||
if p.fileExists(histFile) {
|
|
||||||
common.LogInfo(i18n.Tr("cleaner_history_found", histFile))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
lines := strings.Split(string(data), "\n")
|
||||||
// removeFile 删除文件
|
var kept []string
|
||||||
func (p *CleanerPlugin) removeFile(path string) bool {
|
removed := false
|
||||||
if err := os.Remove(path); err == nil {
|
for _, line := range lines {
|
||||||
return true
|
if strings.Contains(strings.ToLower(line), "fscan") {
|
||||||
|
removed = true
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
kept = append(kept, line)
|
||||||
|
}
|
||||||
|
if !removed {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
return os.WriteFile(path, []byte(strings.Join(kept, "\n")), 0600) == nil
|
||||||
// fileExists 检查文件是否存在
|
|
||||||
func (p *CleanerPlugin) fileExists(path string) bool {
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
return err == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dirExists 检查目录是否存在
|
|
||||||
func (p *CleanerPlugin) dirExists(path string) bool {
|
|
||||||
info, err := os.Stat(path)
|
|
||||||
return err == nil && info.IsDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册插件
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterLocalPlugin("cleaner", func() Plugin {
|
RegisterLocalPlugin("cleaner", func() Plugin {
|
||||||
return NewCleanerPlugin()
|
return NewCleanerPlugin()
|
||||||
|
|||||||
@@ -143,10 +143,14 @@ func (p *MiniDumpPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
|
|||||||
// 提升权限
|
// 提升权限
|
||||||
output.WriteString("正在提升SeDebugPrivilege权限...\n")
|
output.WriteString("正在提升SeDebugPrivilege权限...\n")
|
||||||
if privErr := pm.elevatePrivileges(); privErr != nil {
|
if privErr := pm.elevatePrivileges(); privErr != nil {
|
||||||
output.WriteString(fmt.Sprintf("权限提升失败: %v (尝试继续执行)\n", privErr))
|
output.WriteString(fmt.Sprintf("权限提升失败: %v\n", privErr))
|
||||||
} else {
|
return &plugins.Result{
|
||||||
output.WriteString("✓ 权限提升成功\n")
|
Success: false,
|
||||||
|
Output: output.String(),
|
||||||
|
Error: fmt.Errorf("SeDebugPrivilege 提升失败: %w", privErr),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
output.WriteString("✓ 权限提升成功\n")
|
||||||
|
|
||||||
// 创建转储文件
|
// 创建转储文件
|
||||||
outputPath := filepath.Join(".", fmt.Sprintf("lsass-%d.dmp", pid))
|
outputPath := filepath.Join(".", fmt.Sprintf("lsass-%d.dmp", pid))
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func (p *Socks5ProxyPlugin) Scan(ctx context.Context, info *common.HostInfo, ses
|
|||||||
// startSocks5Server 启动SOCKS5代理服务器 - 核心实现
|
// startSocks5Server 启动SOCKS5代理服务器 - 核心实现
|
||||||
func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, state *common.State) error {
|
func (p *Socks5ProxyPlugin) startSocks5Server(ctx context.Context, port int, state *common.State) error {
|
||||||
// 监听指定端口
|
// 监听指定端口
|
||||||
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("监听端口失败: %w", err)
|
return fmt.Errorf("监听端口失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user