mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
229 lines
6.2 KiB
Go
229 lines
6.2 KiB
Go
package memcached
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"net"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/shadow1ng/fscan/common"
|
||
"github.com/shadow1ng/fscan/common/i18n"
|
||
"github.com/shadow1ng/fscan/plugins/base"
|
||
)
|
||
|
||
// MemcachedPlugin Memcached插件实现
|
||
type MemcachedPlugin struct {
|
||
*base.ServicePlugin
|
||
exploiter *MemcachedExploiter
|
||
}
|
||
|
||
// NewMemcachedPlugin 创建Memcached插件
|
||
func NewMemcachedPlugin() *MemcachedPlugin {
|
||
// 插件元数据
|
||
metadata := &base.PluginMetadata{
|
||
Name: "memcached",
|
||
Version: "2.0.0",
|
||
Author: "fscan-team",
|
||
Description: "Memcached分布式内存缓存系统扫描和利用插件",
|
||
Category: "service",
|
||
Ports: []int{11211}, // 默认Memcached端口
|
||
Protocols: []string{"tcp"},
|
||
Tags: []string{"memcached", "cache", "unauthorized"},
|
||
}
|
||
|
||
// 创建连接器和服务插件
|
||
connector := NewMemcachedConnector()
|
||
servicePlugin := base.NewServicePlugin(metadata, connector)
|
||
|
||
// 创建Memcached插件
|
||
plugin := &MemcachedPlugin{
|
||
ServicePlugin: servicePlugin,
|
||
exploiter: NewMemcachedExploiter(),
|
||
}
|
||
|
||
// 设置能力
|
||
plugin.SetCapabilities([]base.Capability{
|
||
base.CapUnauthorized,
|
||
base.CapDataExtraction,
|
||
})
|
||
|
||
return plugin
|
||
}
|
||
|
||
// Scan 重写扫描方法,检测未授权访问
|
||
func (p *MemcachedPlugin) 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)
|
||
|
||
// Memcached通常无认证,直接检查未授权访问
|
||
unauthCred := &base.Credential{Username: "", Password: ""}
|
||
result, err := p.ScanCredential(ctx, info, unauthCred)
|
||
if err == nil && result.Success {
|
||
// 未授权访问成功
|
||
common.LogSuccess(i18n.GetText("memcached_unauth_access", target))
|
||
|
||
return &base.ScanResult{
|
||
Success: true,
|
||
Service: "Memcached",
|
||
Credentials: []*base.Credential{unauthCred},
|
||
Extra: map[string]interface{}{
|
||
"service": "Memcached",
|
||
"port": info.Ports,
|
||
"unauthorized": true,
|
||
"access_type": "no_authentication",
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 如果未授权访问失败,返回失败结果
|
||
return &base.ScanResult{
|
||
Success: false,
|
||
Error: fmt.Errorf("Memcached服务不可访问或需要认证"),
|
||
}, nil
|
||
}
|
||
|
||
// generateCredentials Memcached通常无需凭据,返回空凭据
|
||
func (p *MemcachedPlugin) generateCredentials() []*base.Credential {
|
||
// Memcached通常无认证机制,只返回空凭据用于未授权访问检测
|
||
return []*base.Credential{
|
||
{Username: "", Password: ""},
|
||
}
|
||
}
|
||
|
||
// Exploit 使用exploiter执行利用
|
||
func (p *MemcachedPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
|
||
return p.exploiter.Exploit(ctx, info, creds)
|
||
}
|
||
|
||
// GetExploitMethods 获取利用方法
|
||
func (p *MemcachedPlugin) GetExploitMethods() []base.ExploitMethod {
|
||
return p.exploiter.GetExploitMethods()
|
||
}
|
||
|
||
// IsExploitSupported 检查利用支持
|
||
func (p *MemcachedPlugin) IsExploitSupported(method base.ExploitType) bool {
|
||
return p.exploiter.IsExploitSupported(method)
|
||
}
|
||
|
||
// performServiceIdentification 执行Memcached服务识别(-nobr模式)
|
||
func (p *MemcachedPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||
|
||
// 尝试连接Memcached服务获取基本信息
|
||
memcachedInfo, isMemcached := p.identifyMemcachedService(ctx, info)
|
||
if isMemcached {
|
||
// 记录服务识别成功
|
||
common.LogSuccess(i18n.GetText("memcached_service_identified", target, memcachedInfo))
|
||
|
||
return &base.ScanResult{
|
||
Success: true,
|
||
Service: "Memcached",
|
||
Banner: memcachedInfo,
|
||
Extra: map[string]interface{}{
|
||
"service": "Memcached",
|
||
"port": info.Ports,
|
||
"info": memcachedInfo,
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// 如果无法识别为Memcached,返回失败
|
||
return &base.ScanResult{
|
||
Success: false,
|
||
Error: fmt.Errorf("无法识别为Memcached服务"),
|
||
}, nil
|
||
}
|
||
|
||
// identifyMemcachedService 通过连接识别Memcached服务
|
||
func (p *MemcachedPlugin) identifyMemcachedService(ctx context.Context, info *common.HostInfo) (string, bool) {
|
||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||
timeout := time.Duration(common.Timeout) * time.Second
|
||
|
||
// 尝试建立TCP连接
|
||
conn, err := net.DialTimeout("tcp", target, timeout)
|
||
if err != nil {
|
||
return "", false
|
||
}
|
||
defer conn.Close()
|
||
|
||
// 设置操作超时
|
||
conn.SetDeadline(time.Now().Add(timeout))
|
||
|
||
// 发送version命令获取版本信息
|
||
if _, err := conn.Write([]byte("version\n")); err != nil {
|
||
return "", false
|
||
}
|
||
|
||
// 读取响应
|
||
buffer := make([]byte, 512)
|
||
n, err := conn.Read(buffer)
|
||
if err != nil {
|
||
return "", false
|
||
}
|
||
|
||
response := strings.TrimSpace(string(buffer[:n]))
|
||
|
||
// 检查是否是Memcached版本响应
|
||
if strings.HasPrefix(response, "VERSION") {
|
||
// 提取版本信息
|
||
parts := strings.Fields(response)
|
||
if len(parts) >= 2 {
|
||
return fmt.Sprintf("Memcached %s", parts[1]), true
|
||
}
|
||
return "Memcached服务", true
|
||
}
|
||
|
||
// 尝试stats命令进行二次确认
|
||
if _, err := conn.Write([]byte("stats\n")); err != nil {
|
||
return "", false
|
||
}
|
||
|
||
n, err = conn.Read(buffer)
|
||
if err != nil {
|
||
return "", false
|
||
}
|
||
|
||
response = string(buffer[:n])
|
||
|
||
// 检查是否包含STAT关键字
|
||
if strings.Contains(response, "STAT") {
|
||
return "Memcached服务", true
|
||
}
|
||
|
||
return "", false
|
||
}
|
||
|
||
// =============================================================================
|
||
// 插件注册
|
||
// =============================================================================
|
||
|
||
// RegisterMemcachedPlugin 注册Memcached插件
|
||
func RegisterMemcachedPlugin() {
|
||
factory := base.NewSimplePluginFactory(
|
||
&base.PluginMetadata{
|
||
Name: "memcached",
|
||
Version: "2.0.0",
|
||
Author: "fscan-team",
|
||
Description: "Memcached分布式内存缓存系统扫描和利用插件",
|
||
Category: "service",
|
||
Ports: []int{11211}, // 默认Memcached端口
|
||
Protocols: []string{"tcp"},
|
||
Tags: []string{"memcached", "cache", "unauthorized"},
|
||
},
|
||
func() base.Plugin {
|
||
return NewMemcachedPlugin()
|
||
},
|
||
)
|
||
|
||
base.GlobalPluginRegistry.Register("memcached", factory)
|
||
}
|
||
|
||
// 自动注册
|
||
func init() {
|
||
RegisterMemcachedPlugin()
|
||
} |