fscan/Plugins/services/rabbitmq/plugin.go
ZacharyZcR 3e71e7e4c9 feat: RabbitMQ消息队列服务插件迁移到新架构完成
- 实现AMQP协议连接器,支持RabbitMQ消息队列服务扫描
- 支持弱密码检测和服务识别功能
- 优先检测默认凭据admin/123456和guest/guest
- 服务识别使用TCP连接检测,避免AMQP协议复杂度
- 简化实现,不提供利用功能,专注于安全扫描
- 集成国际化消息系统
- 测试通过:服务识别和弱密码检测功能
2025-08-09 13:30:24 +08:00

230 lines
6.4 KiB
Go
Raw Permalink 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 rabbitmq
import (
"context"
"fmt"
"strings"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/plugins/base"
)
// RabbitMQPlugin RabbitMQ插件实现
type RabbitMQPlugin struct {
*base.ServicePlugin
exploiter *RabbitMQExploiter
}
// NewRabbitMQPlugin 创建RabbitMQ插件
func NewRabbitMQPlugin() *RabbitMQPlugin {
// 插件元数据
metadata := &base.PluginMetadata{
Name: "rabbitmq",
Version: "2.0.0",
Author: "fscan-team",
Description: "RabbitMQ消息队列服务扫描插件",
Category: "service",
Ports: []int{5672, 5671, 15672}, // AMQP端口、AMQPS端口、管理端口
Protocols: []string{"tcp"},
Tags: []string{"rabbitmq", "amqp", "message-queue", "weak-password"},
}
// 创建连接器和服务插件
connector := NewRabbitMQConnector()
servicePlugin := base.NewServicePlugin(metadata, connector)
// 创建RabbitMQ插件
plugin := &RabbitMQPlugin{
ServicePlugin: servicePlugin,
exploiter: NewRabbitMQExploiter(),
}
// 设置能力
plugin.SetCapabilities([]base.Capability{
base.CapWeakPassword,
})
return plugin
}
// Scan 重写扫描方法进行RabbitMQ服务扫描
func (p *RabbitMQPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
// 如果禁用了暴力破解,只进行服务识别
if common.DisableBrute {
return p.performServiceIdentification(ctx, info)
}
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 优先尝试默认凭据
defaultCredentials := []*base.Credential{
{Username: "admin", Password: "123456"},
{Username: "guest", Password: "guest"},
{Username: "admin", Password: "admin"},
}
// 先测试默认凭据
for _, cred := range defaultCredentials {
result, err := p.ScanCredential(ctx, info, cred)
if err == nil && result.Success {
// 认证成功
common.LogSuccess(i18n.GetText("rabbitmq_weak_pwd_success", target, cred.Username, cred.Password))
return &base.ScanResult{
Success: true,
Service: "RabbitMQ",
Credentials: []*base.Credential{cred},
Banner: result.Banner,
Extra: map[string]interface{}{
"service": "RabbitMQ",
"port": info.Ports,
"username": cred.Username,
"password": cred.Password,
"type": "default-credentials",
},
}, nil
}
}
// 生成其他凭据进行暴力破解
credentials := p.generateCredentials()
// 遍历凭据进行测试
for _, cred := range credentials {
result, err := p.ScanCredential(ctx, info, cred)
if err == nil && result.Success {
// 认证成功
common.LogSuccess(i18n.GetText("rabbitmq_weak_pwd_success", target, cred.Username, cred.Password))
return &base.ScanResult{
Success: true,
Service: "RabbitMQ",
Credentials: []*base.Credential{cred},
Banner: result.Banner,
Extra: map[string]interface{}{
"service": "RabbitMQ",
"port": info.Ports,
"username": cred.Username,
"password": cred.Password,
"type": "weak-password",
},
}, nil
}
}
// 所有凭据都失败但可能识别到了RabbitMQ服务
return p.performServiceIdentification(ctx, info)
}
// generateCredentials 生成RabbitMQ凭据
func (p *RabbitMQPlugin) generateCredentials() []*base.Credential {
var credentials []*base.Credential
// 获取RabbitMQ用户名字典
usernames := common.Userdict["rabbitmq"]
if len(usernames) == 0 {
usernames = []string{"admin", "root", "rabbitmq", "user", "test"}
}
// 获取密码字典
passwords := common.Passwords
if len(passwords) == 0 {
passwords = []string{"", "admin", "password", "123456", "rabbitmq", "root123", "admin123"}
}
// 生成用户名密码组合
for _, username := range usernames {
for _, password := range passwords {
// 替换密码中的用户名占位符
actualPassword := strings.Replace(password, "{user}", username, -1)
credentials = append(credentials, &base.Credential{
Username: username,
Password: actualPassword,
})
}
}
return credentials
}
// Exploit 使用exploiter执行利用
func (p *RabbitMQPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
return p.exploiter.Exploit(ctx, info, creds)
}
// GetExploitMethods 获取利用方法
func (p *RabbitMQPlugin) GetExploitMethods() []base.ExploitMethod {
return p.exploiter.GetExploitMethods()
}
// IsExploitSupported 检查利用支持
func (p *RabbitMQPlugin) IsExploitSupported(method base.ExploitType) bool {
return p.exploiter.IsExploitSupported(method)
}
// performServiceIdentification 执行RabbitMQ服务识别-nobr模式
func (p *RabbitMQPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 尝试识别RabbitMQ服务
connector := NewRabbitMQConnector()
conn, err := connector.Connect(ctx, info)
if err == nil && conn != nil {
if rabbitConn, ok := conn.(*RabbitMQConnection); ok {
// 记录服务识别成功
common.LogSuccess(i18n.GetText("rabbitmq_service_identified", target, rabbitConn.info))
connector.Close(conn)
return &base.ScanResult{
Success: true,
Service: "RabbitMQ",
Banner: rabbitConn.info,
Extra: map[string]interface{}{
"service": "RabbitMQ",
"port": info.Ports,
"info": rabbitConn.info,
"protocol": "AMQP",
},
}, nil
}
}
// 如果无法识别为RabbitMQ返回失败
return &base.ScanResult{
Success: false,
Error: fmt.Errorf("无法识别为RabbitMQ服务"),
}, nil
}
// =============================================================================
// 插件注册
// =============================================================================
// RegisterRabbitMQPlugin 注册RabbitMQ插件
func RegisterRabbitMQPlugin() {
factory := base.NewSimplePluginFactory(
&base.PluginMetadata{
Name: "rabbitmq",
Version: "2.0.0",
Author: "fscan-team",
Description: "RabbitMQ消息队列服务扫描插件",
Category: "service",
Ports: []int{5672, 5671, 15672}, // AMQP端口、AMQPS端口、管理端口
Protocols: []string{"tcp"},
Tags: []string{"rabbitmq", "amqp", "message-queue", "weak-password"},
},
func() base.Plugin {
return NewRabbitMQPlugin()
},
)
base.GlobalPluginRegistry.Register("rabbitmq", factory)
}
// 自动注册
func init() {
RegisterRabbitMQPlugin()
}