package activemq import ( "context" "fmt" "net" "strings" "time" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common/i18n" "github.com/shadow1ng/fscan/plugins/base" ) // ActiveMQ插件:基于新一代插件架构的完整实现 // 支持STOMP协议的弱密码检测、信息收集、队列管理等功能 // 展示了消息队列服务插件的标准实现模式 // ActiveMQPlugin ActiveMQ消息队列扫描和利用插件 // 集成了弱密码检测、自动利用、信息收集等完整功能 type ActiveMQPlugin struct { *base.ServicePlugin // 继承基础服务插件功能 exploiter *ActiveMQExploiter // ActiveMQ专用利用模块 } // NewActiveMQPlugin 创建新的ActiveMQ插件实例 // 这是标准的插件工厂函数,展示了新架构的完整初始化流程 func NewActiveMQPlugin() *ActiveMQPlugin { // 定义插件元数据 - 这些信息用于插件注册和管理 metadata := &base.PluginMetadata{ Name: "activemq", // 插件唯一标识符 Version: "2.0.0", // 插件版本(新架构版本) Author: "fscan-team", // 开发团队 Description: "ActiveMQ消息队列扫描和利用插件", // 功能描述 Category: "service", // 插件类别 Ports: []int{61613, 61614}, // ActiveMQ STOMP端口:标准端口, SSL端口 Protocols: []string{"tcp", "stomp"}, // 支持的协议 Tags: []string{"message-queue", "activemq", "stomp", "bruteforce", "exploit"}, // 功能标签 } // 创建ActiveMQ专用连接器 connector := NewActiveMQConnector() // 基于连接器创建基础服务插件 servicePlugin := base.NewServicePlugin(metadata, connector) // 组装完整的ActiveMQ插件 plugin := &ActiveMQPlugin{ ServicePlugin: servicePlugin, exploiter: NewActiveMQExploiter(), // 集成利用模块 } // 声明插件具备的安全测试能力 plugin.SetCapabilities([]base.Capability{ base.CapWeakPassword, // 弱密码检测 base.CapDataExtraction, // 数据提取 base.CapInformationLeak, // 信息泄露 base.CapPrivilegeEsc, // 权限提升 }) return plugin } // Scan 执行ActiveMQ服务的完整安全扫描 // 重写基础扫描方法,集成弱密码检测和自动利用功能 func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 如果禁用暴力破解,则进行基础服务识别 if common.DisableBrute { return p.performServiceIdentification(ctx, info) } // 调用基础服务插件进行弱密码扫描 result, err := p.ServicePlugin.Scan(ctx, info) if err != nil || !result.Success { return result, err // 扫描失败,直接返回 } // 记录成功的弱密码发现(使用i18n,根据端口显示不同协议) cred := result.Credentials[0] // 专注于STOMP协议的成功消息 common.LogSuccess(i18n.GetText("activemq_stomp_scan_success", target, cred.Username, cred.Password)) // 自动利用功能(可通过-ne参数禁用) if result.Success && len(result.Credentials) > 0 && !common.DisableExploit { // 同步执行利用攻击,确保显示结果 p.autoExploit(context.Background(), info, result.Credentials[0]) } return result, nil } // autoExploit 自动利用 func (p *ActiveMQPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) common.LogDebug(i18n.GetText("plugin_exploit_start", "ActiveMQ", target)) // 执行利用 result, err := p.exploiter.Exploit(ctx, info, creds) if err != nil { common.LogDebug(i18n.GetText("plugin_exploit_failed", "ActiveMQ", err)) return } if result != nil && result.Success { // 使用利用结果中的Method字段作为方法名称 methodName := result.Method if methodName == "" { methodName = p.getExploitMethodName(result.Type) } // 只显示一次完整的利用结果 if result.Output != "" { common.LogSuccess(fmt.Sprintf("ActiveMQ %s %s 利用成功 输出: %s", target, methodName, result.Output)) } else { common.LogSuccess(fmt.Sprintf("ActiveMQ %s %s 利用成功", target, methodName)) } // 保存利用结果(不显示额外日志) // base.SaveExploitResult(info, result, "ActiveMQ") } } // getExploitMethodName 获取利用方法的中文名称 func (p *ActiveMQPlugin) getExploitMethodName(method base.ExploitType) string { switch method { case base.ExploitDataExtraction: return i18n.GetText("exploit_method_name_data_extraction") case base.ExploitPrivilegeEsc: return i18n.GetText("exploit_method_name_activemq_queue_mgmt") default: return "未知利用" } } // Exploit 手动利用接口 func (p *ActiveMQPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { return p.exploiter.Exploit(ctx, info, creds) } // GetExploitMethods 获取利用方法 func (p *ActiveMQPlugin) GetExploitMethods() []base.ExploitMethod { return p.exploiter.GetExploitMethods() } // IsExploitSupported 检查利用支持 func (p *ActiveMQPlugin) IsExploitSupported(method base.ExploitType) bool { return p.exploiter.IsExploitSupported(method) } // 已移除未使用的 generateCredentials 方法 // performServiceIdentification 执行服务识别(-nobr模式) func (p *ActiveMQPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 尝试连接到ActiveMQ服务进行基础识别 conn, err := common.WrapperTcpWithTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) if err != nil { return &base.ScanResult{ Success: false, Error: err, }, nil } defer conn.Close() // 尝试STOMP协议识别 stompInfo, isActiveMQ := p.identifySTOMPService(conn) if isActiveMQ { // 记录服务识别成功 common.LogSuccess(i18n.GetText("activemq_service_identified", target, "STOMP", stompInfo)) return &base.ScanResult{ Success: true, Service: "ActiveMQ", Banner: stompInfo, Extra: map[string]interface{}{ "service": "ActiveMQ", "protocol": "STOMP", "port": info.Ports, "info": stompInfo, }, }, nil } // 如果无法识别为ActiveMQ,返回一般服务信息 return &base.ScanResult{ Success: false, Error: fmt.Errorf("无法识别为ActiveMQ服务"), }, nil } // identifySTOMPService 识别STOMP协议服务 func (p *ActiveMQPlugin) identifySTOMPService(conn net.Conn) (string, bool) { // 发送STOMP CONNECT帧进行协议识别(不提供凭据) connectFrame := "CONNECT\naccept-version:1.0,1.1,1.2\nhost:localhost\n\n\x00" conn.SetWriteDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) if _, err := conn.Write([]byte(connectFrame)); err != nil { return "", false } // 读取响应 conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) response := make([]byte, 1024) n, err := conn.Read(response) if err != nil { return "", false } responseStr := string(response[:n]) // 检查是否为STOMP协议响应 if strings.Contains(responseStr, "CONNECTED") { // 提取版本信息 version := "unknown" if strings.Contains(responseStr, "version:") { lines := strings.Split(responseStr, "\n") for _, line := range lines { if strings.HasPrefix(line, "version:") { version = strings.TrimPrefix(line, "version:") break } } } return fmt.Sprintf("STOMP协议版本: %s", version), true } else if strings.Contains(responseStr, "ERROR") { // 即使返回错误,但能识别STOMP协议格式 return "STOMP协议(需要认证)", true } return "", false } // GetServiceName 获取服务名称 func (p *ActiveMQPlugin) GetServiceName() string { return "ActiveMQ" } // GetServiceDescription 获取服务描述 func (p *ActiveMQPlugin) GetServiceDescription() string { return "Apache ActiveMQ消息队列中间件" } // GetDefaultPorts 获取默认端口 func (p *ActiveMQPlugin) GetDefaultPorts() []int { return []int{61613, 61614} } // SupportsBruteforce 支持暴力破解 func (p *ActiveMQPlugin) SupportsBruteforce() bool { return true } // SupportsExploit 支持利用 func (p *ActiveMQPlugin) SupportsExploit() bool { return true } // GetProtocols 获取支持的协议 func (p *ActiveMQPlugin) GetProtocols() []string { return []string{"tcp", "stomp"} } // ValidateTarget 验证目标是否适用 func (p *ActiveMQPlugin) ValidateTarget(info *common.HostInfo) error { // 基本验证 if info.Host == "" { return fmt.Errorf("主机地址不能为空") } if info.Ports == "" { return fmt.Errorf("端口不能为空") } return nil } // ============================================================================= // 插件注册 // ============================================================================= // RegisterActiveMQPlugin 注册ActiveMQ插件 func RegisterActiveMQPlugin() { factory := base.NewSimplePluginFactory( &base.PluginMetadata{ Name: "activemq", Version: "2.0.0", Author: "fscan-team", Description: "ActiveMQ消息队列扫描和利用插件", Category: "service", Ports: []int{61613, 61614}, Protocols: []string{"tcp", "stomp"}, Tags: []string{"message-queue", "activemq", "stomp", "bruteforce", "exploit"}, }, func() base.Plugin { return NewActiveMQPlugin() }, ) // 注册到全局插件注册表 base.GlobalPluginRegistry.Register("activemq", factory) // 记录注册信息 common.LogDebug("ActiveMQ插件已注册") } // 自动注册 func init() { RegisterActiveMQPlugin() }