refactor: 清理Cassandra插件exploiter.go为最小实现

- 移除所有利用功能代码,简化为最小版本
- 移除gocql依赖和复杂的数据提取逻辑
- 保持与其他插件一致的最小化实现模式
This commit is contained in:
ZacharyZcR 2025-08-08 10:26:00 +08:00
parent ab8834a602
commit a70df9bc3c

View File

@ -2,29 +2,23 @@ package cassandra
import ( import (
"context" "context"
"fmt"
"strings"
"github.com/gocql/gocql"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/plugins/base" "github.com/shadow1ng/fscan/plugins/base"
) )
// CassandraExploiter Cassandra利用器 // CassandraExploiter Cassandra利用器实现 - 最小化版本,不提供利用功能
type CassandraExploiter struct { type CassandraExploiter struct {
*base.BaseExploiter *base.BaseExploiter
connector *CassandraConnector
} }
// NewCassandraExploiter 创建Cassandra利用器 // NewCassandraExploiter 创建Cassandra利用器
func NewCassandraExploiter() *CassandraExploiter { func NewCassandraExploiter() *CassandraExploiter {
exploiter := &CassandraExploiter{ exploiter := &CassandraExploiter{
BaseExploiter: base.NewBaseExploiter("cassandra"), BaseExploiter: base.NewBaseExploiter("cassandra"),
connector: NewCassandraConnector(),
} }
// 添加利用方法 // Cassandra插件不提供利用功能
exploiter.setupExploitMethods() exploiter.setupExploitMethods()
return exploiter return exploiter
@ -32,302 +26,12 @@ func NewCassandraExploiter() *CassandraExploiter {
// setupExploitMethods 设置利用方法 // setupExploitMethods 设置利用方法
func (e *CassandraExploiter) setupExploitMethods() { func (e *CassandraExploiter) setupExploitMethods() {
// 1. 信息收集 // Cassandra插件不提供利用功能仅进行弱密码扫描
infoMethod := base.NewExploitMethod(base.ExploitDataExtraction, "information_gathering").
WithDescription(i18n.GetText("exploit_method_name_information_gathering")).
WithPriority(8).
WithConditions("has_credentials").
WithHandler(e.exploitInformationGathering).
Build()
e.AddExploitMethod(infoMethod)
// 2. Keyspace枚举
enumMethod := base.NewExploitMethod(base.ExploitDataExtraction, "keyspace_enumeration").
WithDescription(i18n.GetText("exploit_method_name_database_enumeration")).
WithPriority(9).
WithConditions("has_credentials").
WithHandler(e.exploitKeyspaceEnumeration).
Build()
e.AddExploitMethod(enumMethod)
// 3. 数据提取
dataMethod := base.NewExploitMethod(base.ExploitDataExtraction, "data_extraction").
WithDescription(i18n.GetText("exploit_method_name_data_extraction")).
WithPriority(7).
WithConditions("has_credentials").
WithHandler(e.exploitDataExtraction).
Build()
e.AddExploitMethod(dataMethod)
} }
// exploitInformationGathering 信息收集 // Exploit 利用接口实现 - 空实现
func (e *CassandraExploiter) exploitInformationGathering(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { func (e *CassandraExploiter) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
return e.executeWithSession(ctx, info, creds, "information_gathering", e.informationGathering) // Cassandra插件不提供利用功能
} return nil, nil
// exploitKeyspaceEnumeration keyspace枚举
func (e *CassandraExploiter) exploitKeyspaceEnumeration(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
return e.executeWithSession(ctx, info, creds, "keyspace_enumeration", e.keyspaceEnumeration)
}
// exploitDataExtraction 数据提取
func (e *CassandraExploiter) exploitDataExtraction(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
return e.executeWithSession(ctx, info, creds, "data_extraction", e.dataExtraction)
}
// executeWithSession 使用Cassandra会话执行利用方法
func (e *CassandraExploiter) executeWithSession(ctx context.Context, info *common.HostInfo, creds *base.Credential, methodName string, method func(context.Context, interface{}, string) ([]string, error)) (*base.ExploitResult, error) {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 建立连接
conn, err := e.connector.Connect(ctx, info)
if err != nil {
return nil, fmt.Errorf("连接失败: %v", err)
}
// 认证
err = e.connector.Authenticate(ctx, conn, creds)
if err != nil {
return nil, fmt.Errorf("认证失败: %v", err)
}
// 创建会话用于利用
cluster := conn.(*gocql.ClusterConfig)
if creds.Username != "" || creds.Password != "" {
cluster.Authenticator = gocql.PasswordAuthenticator{
Username: creds.Username,
Password: creds.Password,
}
}
session, err := cluster.CreateSession()
if err != nil {
return nil, fmt.Errorf("创建会话失败: %v", err)
}
defer session.Close()
// 执行方法
output, err := method(ctx, session, target)
if err != nil {
return &base.ExploitResult{
Success: false,
Error: err,
Type: base.ExploitDataExtraction,
Method: methodName,
Output: fmt.Sprintf("执行失败: %v", err),
}, nil
}
return &base.ExploitResult{
Success: true,
Type: base.ExploitDataExtraction,
Method: methodName,
Output: strings.Join(output, "\n"),
}, nil
}
// informationGathering 信息收集
func (e *CassandraExploiter) informationGathering(ctx context.Context, session interface{}, target string) ([]string, error) {
cassandraSession := session.(*gocql.Session)
var output []string
// 获取Cassandra版本信息
var releaseVersion string
err := cassandraSession.Query("SELECT release_version FROM system.local").WithContext(ctx).Scan(&releaseVersion)
if err == nil {
output = append(output, fmt.Sprintf("Cassandra版本: %s", releaseVersion))
}
// 获取集群名称
var clusterName string
err = cassandraSession.Query("SELECT cluster_name FROM system.local").WithContext(ctx).Scan(&clusterName)
if err == nil {
output = append(output, fmt.Sprintf("集群名称: %s", clusterName))
}
// 获取数据中心信息
var datacenter string
err = cassandraSession.Query("SELECT data_center FROM system.local").WithContext(ctx).Scan(&datacenter)
if err == nil {
output = append(output, fmt.Sprintf("数据中心: %s", datacenter))
}
// 获取机架信息
var rack string
err = cassandraSession.Query("SELECT rack FROM system.local").WithContext(ctx).Scan(&rack)
if err == nil {
output = append(output, fmt.Sprintf("机架: %s", rack))
}
// 获取节点ID
var hostId string
err = cassandraSession.Query("SELECT host_id FROM system.local").WithContext(ctx).Scan(&hostId)
if err == nil {
output = append(output, fmt.Sprintf("节点ID: %s", hostId))
}
if len(output) == 0 {
return nil, fmt.Errorf("无法获取Cassandra信息")
}
return output, nil
}
// keyspaceEnumeration keyspace枚举
func (e *CassandraExploiter) keyspaceEnumeration(ctx context.Context, session interface{}, target string) ([]string, error) {
cassandraSession := session.(*gocql.Session)
var output []string
// 查询所有keyspace
iter := cassandraSession.Query("SELECT keyspace_name FROM system_schema.keyspaces").WithContext(ctx).Iter()
defer iter.Close()
var keyspaceName string
var keyspaces []string
for iter.Scan(&keyspaceName) {
keyspaces = append(keyspaces, keyspaceName)
}
if err := iter.Close(); err != nil {
return nil, fmt.Errorf("查询keyspace失败: %v", err)
}
if len(keyspaces) > 0 {
output = append(output, fmt.Sprintf("发现Keyspaces: %s", strings.Join(keyspaces, ", ")))
// 对每个非系统keyspace获取表信息
for _, ks := range keyspaces {
if !strings.HasPrefix(ks, "system") {
tables := e.getTablesInKeyspace(ctx, cassandraSession, ks)
if len(tables) > 0 {
output = append(output, fmt.Sprintf("Keyspace '%s' 中的表: %s", ks, strings.Join(tables, ", ")))
}
}
}
} else {
return nil, fmt.Errorf("未发现任何keyspace")
}
return output, nil
}
// getTablesInKeyspace 获取keyspace中的表
func (e *CassandraExploiter) getTablesInKeyspace(ctx context.Context, session *gocql.Session, keyspace string) []string {
iter := session.Query("SELECT table_name FROM system_schema.tables WHERE keyspace_name = ?", keyspace).WithContext(ctx).Iter()
defer iter.Close()
var tableName string
var tables []string
for iter.Scan(&tableName) {
tables = append(tables, tableName)
}
return tables
}
// dataExtraction 数据提取
func (e *CassandraExploiter) dataExtraction(ctx context.Context, session interface{}, target string) ([]string, error) {
cassandraSession := session.(*gocql.Session)
var output []string
// 尝试读取一些系统表中的敏感信息
// 获取所有用户角色信息(如果存在)
if roles := e.extractRoles(ctx, cassandraSession); len(roles) > 0 {
output = append(output, roles...)
}
// 获取peer节点信息
if peers := e.extractPeers(ctx, cassandraSession); len(peers) > 0 {
output = append(output, peers...)
}
// 尝试获取一些配置信息
if configs := e.extractConfigs(ctx, cassandraSession); len(configs) > 0 {
output = append(output, configs...)
}
if len(output) == 0 {
return []string{"未能提取到敏感数据"}, nil
}
return output, nil
}
// extractRoles 提取角色信息
func (e *CassandraExploiter) extractRoles(ctx context.Context, session *gocql.Session) []string {
var output []string
// 尝试查询角色表Cassandra 2.2+
iter := session.Query("SELECT role FROM system_auth.roles").WithContext(ctx).Iter()
defer iter.Close()
var role string
var roles []string
for iter.Scan(&role) {
roles = append(roles, role)
}
if len(roles) > 0 {
output = append(output, fmt.Sprintf("发现角色: %s", strings.Join(roles, ", ")))
}
return output
}
// extractPeers 提取peer节点信息
func (e *CassandraExploiter) extractPeers(ctx context.Context, session *gocql.Session) []string {
var output []string
iter := session.Query("SELECT peer, data_center, rack, release_version FROM system.peers").WithContext(ctx).Iter()
defer iter.Close()
var peer, datacenter, rack, version string
var peerCount int
for iter.Scan(&peer, &datacenter, &rack, &version) {
peerCount++
output = append(output, fmt.Sprintf("Peer节点 %d: %s (数据中心: %s, 机架: %s, 版本: %s)",
peerCount, peer, datacenter, rack, version))
}
if peerCount == 0 {
output = append(output, "未发现其他peer节点单节点集群")
}
return output
}
// extractConfigs 提取配置信息
func (e *CassandraExploiter) extractConfigs(ctx context.Context, session *gocql.Session) []string {
var output []string
// 获取token信息
var tokens string
err := session.Query("SELECT tokens FROM system.local").WithContext(ctx).Scan(&tokens)
if err == nil && tokens != "" {
// 只显示token数量不显示完整token太长
tokenList := strings.Split(strings.Trim(tokens, "{}"), ",")
output = append(output, fmt.Sprintf("节点tokens数量: %d", len(tokenList)))
}
// 获取监听地址
var listenAddress string
err = session.Query("SELECT listen_address FROM system.local").WithContext(ctx).Scan(&listenAddress)
if err == nil && listenAddress != "" {
output = append(output, fmt.Sprintf("监听地址: %s", listenAddress))
}
// 获取广播地址
var broadcastAddress string
err = session.Query("SELECT broadcast_address FROM system.local").WithContext(ctx).Scan(&broadcastAddress)
if err == nil && broadcastAddress != "" {
output = append(output, fmt.Sprintf("广播地址: %s", broadcastAddress))
}
return output
} }