package services import ( "context" "fmt" "net" "strings" "time" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/plugins" ) type ActiveMQPlugin struct { plugins.BasePlugin } func NewActiveMQPlugin() *ActiveMQPlugin { return &ActiveMQPlugin{ BasePlugin: plugins.NewBasePlugin("activemq"), } } func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 如果禁用暴力破解,只做服务识别 if common.DisableBrute { return p.identifyService(info) } credentials := GenerateCredentials("activemq") if len(credentials) == 0 { return &ScanResult{ Success: false, Service: "activemq", Error: fmt.Errorf("没有可用的测试凭据"), } } for _, cred := range credentials { if p.testCredential(ctx, info, cred) { common.LogSuccess(fmt.Sprintf("ActiveMQ %s %s:%s", target, cred.Username, cred.Password)) return &ScanResult{ Success: true, Service: "activemq", Username: cred.Username, Password: cred.Password, } } } return &ScanResult{ Success: false, Service: "activemq", Error: fmt.Errorf("未发现弱密码"), } } func (p *ActiveMQPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) timeout := time.Duration(common.Timeout) * time.Second conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) if err != nil { return false } defer conn.Close() return p.authenticateSTOMP(conn, cred.Username, cred.Password) } func (p *ActiveMQPlugin) authenticateSTOMP(conn net.Conn, username, password string) bool { timeout := time.Duration(common.Timeout) * time.Second stompConnect := fmt.Sprintf("CONNECT\naccept-version:1.0,1.1,1.2\nhost:/\nlogin:%s\npasscode:%s\n\n\x00", username, password) conn.SetWriteDeadline(time.Now().Add(timeout)) if _, err := conn.Write([]byte(stompConnect)); err != nil { return false } conn.SetReadDeadline(time.Now().Add(timeout)) response := make([]byte, 1024) n, err := conn.Read(response) if err != nil || n == 0 { return false } responseStr := string(response[:n]) if strings.Contains(responseStr, "CONNECTED") { return true } else if strings.Contains(responseStr, "ERROR") { return false } return false } func (p *ActiveMQPlugin) identifyService(info *common.HostInfo) *ScanResult { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) timeout := time.Duration(common.Timeout) * time.Second conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) if err != nil { return &ScanResult{ Success: false, Service: "activemq", Error: err, } } defer conn.Close() stompConnect := "CONNECT\naccept-version:1.0,1.1,1.2\nhost:/\n\n\x00" conn.SetWriteDeadline(time.Now().Add(timeout)) if _, err := conn.Write([]byte(stompConnect)); err != nil { return &ScanResult{ Success: false, Service: "activemq", Error: fmt.Errorf("无法发送STOMP请求: %v", err), } } conn.SetReadDeadline(time.Now().Add(timeout)) response := make([]byte, 512) n, err := conn.Read(response) if err != nil || n == 0 { return &ScanResult{ Success: false, Service: "activemq", Error: fmt.Errorf("无法读取响应"), } } responseStr := string(response[:n]) if strings.Contains(responseStr, "CONNECTED") || strings.Contains(responseStr, "ERROR") { banner := "ActiveMQ STOMP" common.LogSuccess(fmt.Sprintf("ActiveMQ %s %s", target, banner)) return &ScanResult{ Success: true, Service: "activemq", Banner: banner, } } return &ScanResult{ Success: false, Service: "activemq", Error: fmt.Errorf("无法识别为ActiveMQ STOMP服务"), } } func init() { // 使用高效注册方式:直接传递端口信息,避免实例创建 RegisterPluginWithPorts("activemq", func() Plugin { return NewActiveMQPlugin() }, []int{61616, 61617, 61618, 8161}) }