package activemq import ( "context" "fmt" "net" "strconv" "strings" "time" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common/i18n" "github.com/shadow1ng/fscan/plugins/base" ) // ActiveMQConnector 实现ActiveMQ消息队列服务连接器 // 基于STOMP协议提供标准化的ActiveMQ连接和认证功能 // 遵循 base.ServiceConnector 接口规范,支持弱密码检测和自动利用 type ActiveMQConnector struct { host string // 目标主机地址 port int // 目标端口号 timeout time.Duration // 连接超时时间 } // NewActiveMQConnector 创建新的ActiveMQ连接器实例 func NewActiveMQConnector() *ActiveMQConnector { return &ActiveMQConnector{ timeout: time.Duration(common.Timeout) * time.Second, } } // Connect 建立到ActiveMQ服务的基础连接 // 实现 base.ServiceConnector 接口的 Connect 方法 // 返回原始TCP连接,供后续认证阶段使用 func (c *ActiveMQConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) { // 解析目标端口号 port, err := strconv.Atoi(info.Ports) if err != nil { return nil, fmt.Errorf("无效的端口号: %s", info.Ports) } // 缓存目标信息,供认证阶段使用 c.host = info.Host c.port = port target := fmt.Sprintf("%s:%d", info.Host, port) // 创建带超时的TCP连接 conn, err := c.connectWithTimeout(ctx, target) if err != nil { return nil, fmt.Errorf("连接失败: %v", err) } return conn, nil } // Authenticate 使用STOMP协议对ActiveMQ服务进行身份认证 func (c *ActiveMQConnector) Authenticate(ctx context.Context, conn interface{}, cred *base.Credential) error { // 从连接接口中获取TCP连接 tcpConn, ok := conn.(net.Conn) if !ok { return fmt.Errorf("无效的连接类型") } // 使用STOMP协议进行认证 err := c.authenticateSTOMP(ctx, tcpConn, cred.Username, cred.Password) if err == nil { common.LogDebug(i18n.GetText("activemq_stomp_auth_success", cred.Username, c.host, c.port)) } else { common.LogDebug(i18n.GetText("activemq_stomp_auth_failed", err)) } return err } // Close 关闭ActiveMQ连接 // 实现 base.ServiceConnector 接口的 Close 方法 // 发送STOMP DISCONNECT帧进行优雅断开 func (c *ActiveMQConnector) Close(conn interface{}) error { if conn == nil { return nil } tcpConn, ok := conn.(net.Conn) if !ok { return fmt.Errorf("无效的连接类型") } // 发送DISCONNECT帧 disconnectFrame := "DISCONNECT\n\n\x00" tcpConn.Write([]byte(disconnectFrame)) // 关闭连接 return tcpConn.Close() } // connectWithTimeout 创建带超时的TCP连接 func (c *ActiveMQConnector) connectWithTimeout(ctx context.Context, target string) (net.Conn, error) { // 使用现有的TCP包装器以保持兼容性 return common.WrapperTcpWithTimeout("tcp", target, c.timeout) } // authenticateSTOMP 使用STOMP协议进行身份验证 func (c *ActiveMQConnector) authenticateSTOMP(ctx context.Context, conn net.Conn, username, password string) error { // 构造STOMP CONNECT命令 // STOMP是一种简单的文本协议,用于与消息代理通信 stompConnect := fmt.Sprintf("CONNECT\naccept-version:1.0,1.1,1.2\nhost:/\nlogin:%s\npasscode:%s\n\n\x00", username, password) // 设置写超时并发送认证请求 if err := conn.SetWriteDeadline(time.Now().Add(c.timeout)); err != nil { return fmt.Errorf("设置写超时失败: %v", err) } if _, err := conn.Write([]byte(stompConnect)); err != nil { return fmt.Errorf("发送认证请求失败: %v", err) } // 设置读超时并读取响应 if err := conn.SetReadDeadline(time.Now().Add(c.timeout)); err != nil { return fmt.Errorf("设置读超时失败: %v", err) } // 读取服务器响应 response := make([]byte, 1024) n, err := conn.Read(response) if err != nil { return fmt.Errorf("读取响应失败: %v", err) } // 解析STOMP响应 success, parseErr := c.parseSTOMPResponse(string(response[:n])) if !success { return parseErr } return nil } // parseSTOMPResponse 解析STOMP协议响应 func (c *ActiveMQConnector) parseSTOMPResponse(response string) (bool, error) { // 检查成功的连接响应 if strings.Contains(response, "CONNECTED") { return true, nil } // 检查认证失败响应 if strings.Contains(response, "ERROR") { // 提取错误信息 lines := strings.Split(response, "\n") for _, line := range lines { if strings.HasPrefix(line, "message:") { errorMsg := strings.TrimPrefix(line, "message:") return false, fmt.Errorf("认证失败: %s", errorMsg) } } return false, fmt.Errorf("认证失败: 服务器返回ERROR") } // 检查其他可能的认证失败指示 if strings.Contains(response, "Authentication failed") || strings.Contains(response, "Access denied") || strings.Contains(response, "Invalid credentials") { return false, fmt.Errorf("认证失败: 无效凭据") } // 未知响应类型 return false, fmt.Errorf("未知响应格式: %s", response) } // 已移除未使用的 getProtocolByPort 方法 // GetDefaultCredentials 获取ActiveMQ默认凭据 func (c *ActiveMQConnector) GetDefaultCredentials() []*base.Credential { return []*base.Credential{ {Username: "admin", Password: "admin"}, {Username: "admin", Password: "Aa123456789"}, // 测试环境凭据 {Username: "test", Password: "test123"}, // 测试环境凭据 {Username: "root", Password: "root123"}, // 测试环境凭据 {Username: "system", Password: "admin123"}, // 测试环境凭据 {Username: "admin", Password: "password"}, {Username: "admin", Password: "123456"}, {Username: "user", Password: "user"}, {Username: "guest", Password: "guest"}, {Username: "activemq", Password: "activemq"}, {Username: "mqadmin", Password: "mqadmin"}, {Username: "broker", Password: "broker"}, } }