refactor: 清理项目死代码和未使用函数

- 移除所有未使用的generateCredentials方法
- 删除插件适配器中的过时函数
- 清理MySQL连接器中的无用方法
- 移除Redis利用器中的未调用函数
- 删除遗留加密函数和基础扫描器无用方法
- 完全移除未注册的VNC插件
- 优化代码结构,提升项目可维护性

清理统计: 移除25+个死代码函数,减少400+行无用代码
This commit is contained in:
ZacharyZcR 2025-08-12 11:51:36 +08:00
parent b89bf4b0da
commit f097d2812a
21 changed files with 26 additions and 851 deletions

View File

@ -1,165 +1,7 @@
// Package adapters provides plugin compatibility layers.
// This package contains legacy adapter code that was part of a transition architecture.
// The adapter functions were not being used in the current codebase.
package adapters package adapters
import ( // Legacy plugin adapter functionality has been removed as it was unused.
"context" // This file is preserved for future compatibility needs if required.
"fmt"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/common/output"
"github.com/shadow1ng/fscan/plugins/base"
"time"
// 导入新插件以触发注册
_ "github.com/shadow1ng/fscan/plugins/services/mysql"
_ "github.com/shadow1ng/fscan/plugins/services/redis"
_ "github.com/shadow1ng/fscan/plugins/services/ssh"
)
// PluginAdapter 插件适配器,将新插件架构与旧系统集成
type PluginAdapter struct {
registry *base.PluginRegistry
}
// NewPluginAdapter 创建插件适配器
func NewPluginAdapter() *PluginAdapter {
return &PluginAdapter{
registry: base.GlobalPluginRegistry,
}
}
// AdaptPluginScan 适配插件扫描调用
// 将传统的插件扫描函数调用转换为新架构的插件调用
func (a *PluginAdapter) AdaptPluginScan(pluginName string, info *common.HostInfo) error {
// 创建插件实例
plugin, err := a.registry.Create(pluginName)
if err != nil {
// 如果新架构中没有该插件,返回错误让旧系统处理
return fmt.Errorf("plugin %s not found in new architecture: %v", pluginName, err)
}
// 初始化插件
if err := plugin.Initialize(); err != nil {
return fmt.Errorf("plugin %s initialization failed: %v", pluginName, err)
}
// 设置全局超时上下文
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(common.GlobalTimeout)*time.Second)
defer cancel()
// 执行扫描
result, err := plugin.Scan(ctx, info)
if err != nil {
common.LogError(fmt.Sprintf("Plugin %s scan failed: %v", pluginName, err))
return err
}
// 如果扫描成功,记录结果
if result != nil && result.Success {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 适配器层不输出扫描结果,由插件层负责输出
// 这避免了重复输出的问题
common.LogDebug(fmt.Sprintf("插件 %s 适配成功: %s", pluginName, target))
// 保存结果到文件
a.saveResult(info, result, pluginName)
// 如果有漏洞信息,也记录下来
for _, vuln := range result.Vulnerabilities {
common.LogError(fmt.Sprintf("%s vulnerability found: %s - %s",
pluginName, vuln.ID, vuln.Description))
}
}
return nil
}
// saveResult 保存扫描结果
func (a *PluginAdapter) saveResult(info *common.HostInfo, result *base.ScanResult, pluginName string) {
// 使用原有的结果保存机制
vulnResult := &output.ScanResult{
Time: time.Now(),
Type: output.TypeVuln,
Target: info.Host,
Status: "vulnerable",
Details: map[string]interface{}{
"plugin": pluginName,
"port": info.Ports,
"host": info.Host,
},
}
if len(result.Credentials) > 0 {
cred := result.Credentials[0]
if cred.Username != "" {
vulnResult.Details["username"] = cred.Username
vulnResult.Details["password"] = cred.Password
vulnResult.Details["credentials"] = fmt.Sprintf("%s:%s", cred.Username, cred.Password)
} else {
vulnResult.Details["password"] = cred.Password
vulnResult.Details["credentials"] = cred.Password
}
} else {
// 未授权访问
vulnResult.Details["type"] = "unauthorized"
}
// 保存结果
common.SaveResult(vulnResult)
}
// IsPluginSupported 检查插件是否在新架构中支持
func (a *PluginAdapter) IsPluginSupported(pluginName string) bool {
plugins := a.registry.GetAll()
for _, name := range plugins {
if name == pluginName {
return true
}
}
return false
}
// GetSupportedPlugins 获取新架构支持的插件列表
func (a *PluginAdapter) GetSupportedPlugins() []string {
return a.registry.GetAll()
}
// GetPluginMetadata 获取插件元数据
func (a *PluginAdapter) GetPluginMetadata(pluginName string) (*base.PluginMetadata, error) {
metadata := a.registry.GetMetadata(pluginName)
if metadata == nil {
return nil, fmt.Errorf("plugin %s not found", pluginName)
}
return metadata, nil
}
// =============================================================================
// 全局适配器实例
// =============================================================================
// GlobalAdapter 全局插件适配器实例
var GlobalAdapter = NewPluginAdapter()
// =============================================================================
// 便捷函数
// =============================================================================
// TryNewArchitecture 尝试使用新架构执行插件扫描
// 如果新架构支持该插件则使用新架构否则返回false让调用方使用旧插件
func TryNewArchitecture(pluginName string, info *common.HostInfo) bool {
if !GlobalAdapter.IsPluginSupported(pluginName) {
common.LogDebug(i18n.GetText("plugin_legacy_using", pluginName))
return false
}
common.LogDebug(i18n.GetText("plugin_new_arch_trying", pluginName))
err := GlobalAdapter.AdaptPluginScan(pluginName, info)
if err != nil {
common.LogError(i18n.GetText("plugin_new_arch_fallback", pluginName, err))
return false
}
common.LogDebug(i18n.GetText("plugin_new_arch_success", pluginName))
return true
}

View File

@ -264,46 +264,4 @@ func GenerateCredentials(usernames []string, passwords []string) []*Credential {
return credentials return credentials
} }
// GeneratePasswordOnlyCredentials 生成仅密码的凭据列表如Redis // 已移除未使用的 GeneratePasswordOnlyCredentials 方法
func GeneratePasswordOnlyCredentials(passwords []string) []*Credential {
var credentials []*Credential
for _, password := range passwords {
credentials = append(credentials, &Credential{
Password: password,
Extra: make(map[string]string),
})
}
return credentials
}
// =============================================================================
// 结果处理工具
// =============================================================================
// SaveScanResult 保存扫描结果到通用输出系统
func SaveScanResult(info *common.HostInfo, result *ScanResult, pluginName string) {
if result == nil || !result.Success {
return
}
target := fmt.Sprintf("%s:%d", info.Host, info.Ports)
// 保存成功的凭据
for _, cred := range result.Credentials {
var message string
if cred.Username != "" && cred.Password != "" {
message = fmt.Sprintf("%s %s %s %s", pluginName, target, cred.Username, cred.Password)
} else if cred.Password != "" {
message = fmt.Sprintf("%s %s [密码] %s", pluginName, target, cred.Password)
} else {
message = fmt.Sprintf("%s %s 未授权访问", pluginName, target)
}
common.LogSuccess(message)
// 保存到输出系统的详细实现...
// 这里可以调用common.SaveResult等函数
}
}

View File

@ -1,7 +1,6 @@
package Plugins package Plugins
import ( import (
"bytes"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"encoding/base64" "encoding/base64"
@ -44,32 +43,6 @@ func ReadBytes(conn net.Conn) ([]byte, error) {
// 默认AES加密密钥 // 默认AES加密密钥
var key = "0123456789abcdef" var key = "0123456789abcdef"
// AesEncrypt 使用AES-CBC模式加密字符串
func AesEncrypt(orig string, key string) (string, error) {
// 转为字节数组
origData := []byte(orig)
keyBytes := []byte(key)
// 创建加密块,要求密钥长度必须为16/24/32字节
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", fmt.Errorf("创建加密块失败: %v", err)
}
// 获取块大小并填充数据
blockSize := block.BlockSize()
origData = PKCS7Padding(origData, blockSize)
// 创建CBC加密模式
blockMode := cipher.NewCBCEncrypter(block, keyBytes[:blockSize])
// 加密数据
encrypted := make([]byte, len(origData))
blockMode.CryptBlocks(encrypted, origData)
// base64编码
return base64.StdEncoding.EncodeToString(encrypted), nil
}
// AesDecrypt 使用AES-CBC模式解密字符串 // AesDecrypt 使用AES-CBC模式解密字符串
func AesDecrypt(crypted string, key string) (string, error) { func AesDecrypt(crypted string, key string) (string, error) {
@ -104,12 +77,6 @@ func AesDecrypt(crypted string, key string) (string, error) {
return string(origData), nil return string(origData), nil
} }
// PKCS7Padding 对数据进行PKCS7填充
func PKCS7Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padtext...)
}
// PKCS7UnPadding 去除PKCS7填充 // PKCS7UnPadding 去除PKCS7填充
func PKCS7UnPadding(data []byte) ([]byte, error) { func PKCS7UnPadding(data []byte) ([]byte, error) {

View File

@ -172,15 +172,7 @@ func (c *ActiveMQConnector) parseSTOMPResponse(response string) (bool, error) {
// getProtocolByPort 根据端口获取协议类型 // 已移除未使用的 getProtocolByPort 方法
func (c *ActiveMQConnector) getProtocolByPort(port int) string {
switch port {
case 61613, 61614:
return "STOMP"
default:
return "STOMP" // 默认仅支持STOMP
}
}
// GetDefaultCredentials 获取ActiveMQ默认凭据 // GetDefaultCredentials 获取ActiveMQ默认凭据
func (c *ActiveMQConnector) GetDefaultCredentials() []*base.Credential { func (c *ActiveMQConnector) GetDefaultCredentials() []*base.Credential {

View File

@ -150,37 +150,7 @@ func (p *ActiveMQPlugin) IsExploitSupported(method base.ExploitType) bool {
return p.exploiter.IsExploitSupported(method) return p.exploiter.IsExploitSupported(method)
} }
// generateCredentials 重写凭据生成方法 // 已移除未使用的 generateCredentials 方法
func (p *ActiveMQPlugin) generateCredentials() []*base.Credential {
// 获取ActiveMQ专用的用户名字典
usernames := common.Userdict["activemq"]
if len(usernames) == 0 {
// 默认ActiveMQ用户名
usernames = []string{
"admin", "test", "root", "system", "user", "guest",
"manager", "activemq", "mqadmin", "broker",
}
}
// 生成基本凭据组合
credentials := base.GenerateCredentials(usernames, common.Passwords)
// 添加ActiveMQ专用的默认凭据
defaultCreds := p.ServicePlugin.GetServiceConnector().(*ActiveMQConnector).GetDefaultCredentials()
credentials = append(credentials, defaultCreds...)
// 去重处理(简化实现)
seen := make(map[string]bool)
var unique []*base.Credential
for _, cred := range credentials {
key := cred.Username + ":" + cred.Password
if !seen[key] {
seen[key] = true
unique = append(unique, cred)
}
}
return unique
}
// performServiceIdentification 执行服务识别(-nobr模式 // performServiceIdentification 执行服务识别(-nobr模式
func (p *ActiveMQPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { func (p *ActiveMQPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {

View File

@ -85,30 +85,7 @@ func (p *CassandraPlugin) Scan(ctx context.Context, info *common.HostInfo) (*bas
return result, nil return result, nil
} }
// generateCredentials 生成Cassandra凭据 // 已移除未使用的 generateCredentials 方法
func (p *CassandraPlugin) generateCredentials() []*base.Credential {
// 获取Cassandra专用的用户名字典
usernames := common.Userdict["cassandra"]
if len(usernames) == 0 {
// 默认Cassandra用户名包含空用户名用于测试未授权访问
usernames = []string{"", "cassandra", "admin", "root", "user"}
}
// 生成凭据组合,包括空密码测试未授权访问
var credentials []*base.Credential
// 首先测试未授权访问(空用户名和密码)
credentials = append(credentials, &base.Credential{
Username: "",
Password: "",
})
// 然后生成常规用户名密码组合
regularCreds := base.GenerateCredentials(usernames, common.Passwords)
credentials = append(credentials, regularCreds...)
return credentials
}
// autoExploit 自动利用功能 // autoExploit 自动利用功能
func (p *CassandraPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) { func (p *CassandraPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) {

View File

@ -99,17 +99,7 @@ func (p *FTPPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Scan
return result, nil return result, nil
} }
// generateCredentials 生成FTP凭据 // 已移除未使用的 generateCredentials 方法
func (p *FTPPlugin) generateCredentials() []*base.Credential {
// 获取FTP专用的用户名字典
usernames := common.Userdict["ftp"]
if len(usernames) == 0 {
// 默认FTP用户名
usernames = []string{"ftp", "ftpuser", "admin", "test", "user", "guest"}
}
return base.GenerateCredentials(usernames, common.Passwords)
}
// autoExploit 自动利用功能 // autoExploit 自动利用功能
func (p *FTPPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) { func (p *FTPPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) {

View File

@ -75,17 +75,7 @@ func (p *IMAPPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sca
return result, nil return result, nil
} }
// generateCredentials 重写凭据生成方法 // 已移除未使用的 generateCredentials 方法
func (p *IMAPPlugin) generateCredentials() []*base.Credential {
// 获取IMAP专用的用户名字典
usernames := common.Userdict["imap"]
if len(usernames) == 0 {
// 默认IMAP用户名
usernames = []string{"admin", "root", "test", "mail", "postmaster", "administrator"}
}
return base.GenerateCredentials(usernames, common.Passwords)
}
// Exploit 使用exploiter执行利用 // Exploit 使用exploiter执行利用
func (p *IMAPPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { func (p *IMAPPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {

View File

@ -93,17 +93,7 @@ func (p *KafkaPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sc
return result, nil return result, nil
} }
// generateCredentials 重写凭据生成方法 // 已移除未使用的 generateCredentials 方法
func (p *KafkaPlugin) generateCredentials() []*base.Credential {
// 获取Kafka专用的用户名字典
usernames := common.Userdict["kafka"]
if len(usernames) == 0 {
// 默认Kafka用户名
usernames = []string{"admin", "kafka", "test", "user", "root"}
}
return base.GenerateCredentials(usernames, common.Passwords)
}
// Exploit 使用exploiter执行利用 // Exploit 使用exploiter执行利用
func (p *KafkaPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { func (p *KafkaPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {

View File

@ -94,17 +94,7 @@ func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sca
return result, nil return result, nil
} }
// generateCredentials 重写凭据生成方法 // 已移除未使用的 generateCredentials 方法
func (p *LDAPPlugin) generateCredentials() []*base.Credential {
// 获取LDAP专用的用户名字典
usernames := common.Userdict["ldap"]
if len(usernames) == 0 {
// 默认LDAP用户名
usernames = []string{"admin", "administrator", "ldap", "root", "manager", "directory", "test", "user"}
}
return base.GenerateCredentials(usernames, common.Passwords)
}
// Exploit 使用exploiter执行利用 // Exploit 使用exploiter执行利用
func (p *LDAPPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { func (p *LDAPPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {

View File

@ -87,13 +87,7 @@ func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo) (*bas
}, nil }, nil
} }
// generateCredentials Memcached通常无需凭据返回空凭据 // 已移除未使用的 generateCredentials 方法
func (p *MemcachedPlugin) generateCredentials() []*base.Credential {
// Memcached通常无认证机制只返回空凭据用于未授权访问检测
return []*base.Credential{
{Username: "", Password: ""},
}
}
// Exploit 使用exploiter执行利用 // Exploit 使用exploiter执行利用
func (p *MemcachedPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { func (p *MemcachedPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {

View File

@ -94,13 +94,7 @@ func (p *ModbusPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.S
}, nil }, nil
} }
// generateCredentials Modbus通常无需凭据返回空凭据 // 已移除未使用的 generateCredentials 方法
func (p *ModbusPlugin) generateCredentials() []*base.Credential {
// Modbus协议通常无认证机制只返回空凭据用于协议检测
return []*base.Credential{
{Username: "", Password: ""},
}
}
// getDeviceInfo 获取Modbus设备信息 // getDeviceInfo 获取Modbus设备信息
func (p *ModbusPlugin) getDeviceInfo(ctx context.Context, info *common.HostInfo) string { func (p *ModbusPlugin) getDeviceInfo(ctx context.Context, info *common.HostInfo) string {

View File

@ -89,33 +89,7 @@ func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.
}, nil }, nil
} }
// generateCredentials MongoDB主要用于未授权访问检测 // 已移除未使用的 generateCredentials 方法
func (p *MongoDBPlugin) generateCredentials() []*base.Credential {
// MongoDB主要检查未授权访问但也可以尝试一些默认凭据
credentials := []*base.Credential{
{Username: "", Password: ""}, // 未授权访问
}
// 如果有MongoDB专用字典添加常见凭据
usernames := common.Userdict["mongodb"]
if len(usernames) == 0 {
usernames = []string{"admin", "root", "mongo", "mongodb"}
}
// 添加一些常见的MongoDB凭据
for _, username := range usernames {
credentials = append(credentials, &base.Credential{
Username: username,
Password: "", // MongoDB常见空密码
})
credentials = append(credentials, &base.Credential{
Username: username,
Password: username, // 用户名等于密码
})
}
return credentials
}
// Exploit 使用exploiter执行利用 // Exploit 使用exploiter执行利用
func (p *MongoDBPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { func (p *MongoDBPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {

View File

@ -103,22 +103,7 @@ func (c *MySQLConnector) Close(conn interface{}) error {
return nil return nil
} }
// connectWithCredentials 使用凭据创建新连接 // 已移除未使用的 connectWithCredentials 方法
func (c *MySQLConnector) connectWithCredentials(ctx context.Context, originalDB *sql.DB, cred *base.Credential) (*sql.DB, error) {
// 从原始连接中提取主机和端口信息
// 这里简化处理,实际应该从原始连接字符串中解析
// 为了示例,我们假设可以从某种方式获取主机端口信息
// 临时解决方案:重新构建连接字符串
connStr := c.buildConnectionStringWithCredentials(cred)
db, err := sql.Open("mysql", connStr)
if err != nil {
return nil, fmt.Errorf("创建认证连接失败: %v", err)
}
return db, nil
}
// buildConnectionString 构建MySQL连接字符串 // buildConnectionString 构建MySQL连接字符串
// 根据是否配置SOCKS代理选择合适的连接方式 // 根据是否配置SOCKS代理选择合适的连接方式
@ -136,11 +121,7 @@ func (c *MySQLConnector) buildConnectionString(host string, port int, username,
} }
} }
// buildConnectionStringWithCredentials 构建带凭据的连接字符串 // 已移除未使用的 buildConnectionStringWithCredentials 方法
func (c *MySQLConnector) buildConnectionStringWithCredentials(cred *base.Credential) string {
// 使用保存的主机和端口信息
return c.buildConnectionString(c.host, c.port, cred.Username, cred.Password)
}
// connectDirect 内存优化直接建立MySQL连接避免连接池开销 // connectDirect 内存优化直接建立MySQL连接避免连接池开销
// 用于单次认证场景,减少内存分配和资源浪费 // 用于单次认证场景,减少内存分配和资源浪费

View File

@ -124,17 +124,7 @@ func (p *MySQLPlugin) IsExploitSupported(method base.ExploitType) bool {
return p.exploiter.IsExploitSupported(method) return p.exploiter.IsExploitSupported(method)
} }
// generateCredentials 重写凭据生成方法 // 已移除未使用的 generateCredentials 方法
func (p *MySQLPlugin) generateCredentials() []*base.Credential {
// 获取MySQL专用的用户名字典
usernames := common.Userdict["mysql"]
if len(usernames) == 0 {
// 默认MySQL用户名
usernames = []string{"root", "admin", "mysql"}
}
return base.GenerateCredentials(usernames, common.Passwords)
}
// performServiceIdentification 执行MySQL服务识别-nobr模式 // performServiceIdentification 执行MySQL服务识别-nobr模式
func (p *MySQLPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { func (p *MySQLPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {

View File

@ -220,68 +220,9 @@ func (e *RedisExploiter) exploitCrontabInjection(ctx context.Context, info *comm
return result, nil return result, nil
} }
// exploitDataExtraction 数据提取利用 // 已移除未使用的 exploitDataExtraction 方法
func (e *RedisExploiter) exploitDataExtraction(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
conn, err := e.connectToRedis(ctx, info, creds)
if err != nil {
return base.CreateFailedExploitResult(base.ExploitDataExtraction, "data_extraction", err), nil
}
defer e.connector.Close(conn)
redisConn := conn.(*RedisConnection) // 已移除未使用的 exploitInfoGathering 方法
result := base.CreateSuccessExploitResult(base.ExploitDataExtraction, "data_extraction")
// 获取所有键
keys, err := e.getAllKeys(redisConn)
if err == nil && len(keys) > 0 {
base.AddOutputToResult(result, i18n.GetText("redis_keys_found", strings.Join(keys[:min(10, len(keys))], ", ")))
result.Extra["keys"] = keys
// 获取部分键值
for i, key := range keys {
if i >= 5 { // 限制只获取前5个键的值
break
}
value, err := e.getKeyValue(redisConn, key)
if err == nil && value != "" {
base.AddOutputToResult(result, fmt.Sprintf("%s = %s", key, value))
}
}
}
return result, nil
}
// exploitInfoGathering 信息收集利用
func (e *RedisExploiter) exploitInfoGathering(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
conn, err := e.connectToRedis(ctx, info, creds)
if err != nil {
return base.CreateFailedExploitResult(base.ExploitDataExtraction, "info_gathering", err), nil
}
defer e.connector.Close(conn)
redisConn := conn.(*RedisConnection)
result := base.CreateSuccessExploitResult(base.ExploitDataExtraction, "info_gathering")
// 获取Redis信息
infoResponse, err := e.connector.ExecuteCommand(redisConn, "INFO")
if err == nil {
lines := strings.Split(infoResponse, "\n")
for _, line := range lines {
if strings.Contains(line, "redis_version") ||
strings.Contains(line, "os") ||
strings.Contains(line, "arch_bits") {
base.AddOutputToResult(result, strings.TrimSpace(line))
}
}
}
// 获取配置信息
base.AddOutputToResult(result, i18n.GetText("redis_config_info", fmt.Sprintf("Dir: %s", redisConn.config.Dir)))
base.AddOutputToResult(result, i18n.GetText("redis_config_info", fmt.Sprintf("DBFilename: %s", redisConn.config.DBFilename)))
return result, nil
}
// ============================================================================= // =============================================================================
// Redis操作辅助函数 // Redis操作辅助函数
@ -413,36 +354,8 @@ func (e *RedisExploiter) readFirstNonEmptyLine(filename string) (string, error)
return "", fmt.Errorf("文件为空或无内容") return "", fmt.Errorf("文件为空或无内容")
} }
// getAllKeys 获取所有Redis键 // 已移除未使用的 getAllKeys 方法
func (e *RedisExploiter) getAllKeys(conn *RedisConnection) ([]string, error) {
response, err := e.connector.ExecuteCommand(conn, "KEYS *")
if err != nil {
return nil, err
}
// 简单解析键列表实际应该按Redis协议解析 // 已移除未使用的 getKeyValue 方法
lines := strings.Split(response, "\n")
var keys []string
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" && !strings.HasPrefix(line, "*") && !strings.HasPrefix(line, "$") {
keys = append(keys, line)
}
}
return keys, nil // 已移除未使用的 min 函数
}
// getKeyValue 获取键值
func (e *RedisExploiter) getKeyValue(conn *RedisConnection, key string) (string, error) {
command := fmt.Sprintf("GET %s", key)
return e.connector.ExecuteCommand(conn, command)
}
// min 返回两个整数中的较小值
func min(a, b int) int {
if a < b {
return a
}
return b
}

View File

@ -164,11 +164,7 @@ func (p *RedisPlugin) IsExploitSupported(method base.ExploitType) bool {
return p.exploiter.IsExploitSupported(method) return p.exploiter.IsExploitSupported(method)
} }
// generateCredentials 重写凭据生成方法Redis只需要密码 // 已移除未使用的 generateCredentials 方法
func (p *RedisPlugin) generateCredentials() []*base.Credential {
// Redis通常只需要密码不需要用户名
return base.GeneratePasswordOnlyCredentials(common.Passwords)
}
// performServiceIdentification 执行Redis服务识别-nobr模式 // performServiceIdentification 执行Redis服务识别-nobr模式
func (p *RedisPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { func (p *RedisPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {

View File

@ -207,17 +207,7 @@ func (p *SSHPlugin) scanWithKey(ctx context.Context, info *common.HostInfo) *bas
return nil return nil
} }
// generateCredentials 重写凭据生成方法 // 已移除未使用的 generateCredentials 方法
func (p *SSHPlugin) generateCredentials() []*base.Credential {
// 获取SSH专用的用户名字典
usernames := common.Userdict["ssh"]
if len(usernames) == 0 {
// 默认SSH用户名
usernames = []string{"root", "admin", "ubuntu", "centos", "user", "test"}
}
return base.GenerateCredentials(usernames, common.Passwords)
}
// Exploit 使用exploiter执行利用 // Exploit 使用exploiter执行利用

View File

@ -1,111 +0,0 @@
package vnc
import (
"context"
"fmt"
"net"
"time"
"github.com/mitchellh/go-vnc"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/plugins/base"
)
// VNCConnector VNC服务连接器
type VNCConnector struct{}
// NewVNCConnector 创建新的VNC连接器
func NewVNCConnector() *VNCConnector {
return &VNCConnector{}
}
// Connect 连接到VNC服务
func (c *VNCConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
timeout := time.Duration(common.Timeout) * time.Second
// 使用带上下文的TCP连接
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout)
if err != nil {
return nil, fmt.Errorf(i18n.GetText("vnc_connection_failed"), err)
}
// 设置读写超时
if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil {
conn.Close()
return nil, fmt.Errorf("failed to set connection deadline: %v", err)
}
return conn, nil
}
// Authenticate 认证VNC服务
func (c *VNCConnector) Authenticate(ctx context.Context, conn interface{}, cred *base.Credential) error {
netConn, ok := conn.(net.Conn)
if !ok {
return fmt.Errorf("invalid connection type")
}
// 检查上下文是否已取消
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// VNC只使用密码认证忽略用户名
password := cred.Password
if password == "" && cred.Username != "" {
// 如果密码为空但用户名不为空,尝试使用用户名作为密码
password = cred.Username
}
// 创建完成通道
doneChan := make(chan error, 1)
// 在协程中处理VNC认证
go func() {
// 配置VNC客户端
config := &vnc.ClientConfig{
Auth: []vnc.ClientAuth{
&vnc.PasswordAuth{
Password: password,
},
},
}
// 尝试VNC认证
client, err := vnc.Client(netConn, config)
if err != nil {
select {
case <-ctx.Done():
case doneChan <- err:
}
return
}
// 认证成功,立即关闭客户端
client.Close()
select {
case <-ctx.Done():
case doneChan <- nil:
}
}()
// 等待认证结果或上下文取消
select {
case err := <-doneChan:
return err
case <-ctx.Done():
return ctx.Err()
}
}
// Close 关闭连接
func (c *VNCConnector) Close(conn interface{}) error {
if closer, ok := conn.(interface{ Close() error }); ok && closer != nil {
return closer.Close()
}
return nil
}

View File

@ -1,25 +0,0 @@
package vnc
import (
"context"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/plugins/base"
)
// VNCExploiter VNC服务利用器
// 遵循新架构设计模式,当前为空实现
type VNCExploiter struct{}
// NewVNCExploiter 创建新的VNC利用器
func NewVNCExploiter() *VNCExploiter {
return &VNCExploiter{}
}
// Exploit 执行VNC服务利用
// 当前为空实现,遵循其他插件的一致性设计
func (e *VNCExploiter) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
// 空实现 - 遵循新架构中其他服务插件的模式
// 主要功能集中在连接器和插件主体中实现
return nil, nil
}

View File

@ -1,187 +0,0 @@
package vnc
import (
"context"
"fmt"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/plugins/base"
)
// VNCPlugin VNC服务插件
type VNCPlugin struct {
*base.ServicePlugin
exploiter *VNCExploiter
}
// NewVNCPlugin 创建VNC插件
func NewVNCPlugin() *VNCPlugin {
// 插件元数据
metadata := &base.PluginMetadata{
Name: "vnc",
Version: "2.0.0",
Author: "fscan-team",
Description: "VNC远程桌面协议服务检测和弱口令扫描",
Category: "service",
Ports: []int{5900, 5901, 5902, 5903}, // VNC常用端口
Protocols: []string{"tcp"},
Tags: []string{"vnc", "remote-desktop", "weak-password"},
}
// 创建连接器和服务插件
connector := NewVNCConnector()
servicePlugin := base.NewServicePlugin(metadata, connector)
// 创建VNC插件
plugin := &VNCPlugin{
ServicePlugin: servicePlugin,
exploiter: NewVNCExploiter(),
}
// 设置能力
plugin.SetCapabilities([]base.Capability{
base.CapWeakPassword,
})
return plugin
}
// init 自动注册VNC插件
func init() {
// 创建插件工厂
metadata := &base.PluginMetadata{
Name: "vnc",
Version: "2.0.0",
Author: "fscan-team",
Description: "VNC远程桌面协议服务检测和弱口令扫描",
Category: "service",
Ports: []int{5900, 5901, 5902, 5903},
Protocols: []string{"tcp"},
Tags: []string{"vnc", "remote-desktop", "weak-password"},
}
factory := base.NewSimplePluginFactory(metadata, func() base.Plugin {
return NewVNCPlugin()
})
base.GlobalPluginRegistry.Register("vnc", factory)
}
// Scan 重写扫描方法进行VNC服务扫描
func (p *VNCPlugin) 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)
// 生成凭据进行暴力破解
credentials := p.generateCredentials()
if len(credentials) == 0 {
return &base.ScanResult{
Success: false,
Error: fmt.Errorf("no credentials available"),
}, nil
}
// 遍历凭据进行测试
for _, cred := range credentials {
result, err := p.ScanCredential(ctx, info, cred)
if err == nil && result.Success {
// 认证成功
common.LogSuccess(i18n.GetText("vnc_weak_password_success", target, cred.Password))
return &base.ScanResult{
Success: true,
Service: "VNC",
Credentials: []*base.Credential{cred},
Banner: result.Banner,
Extra: map[string]interface{}{
"service": "VNC",
"port": info.Ports,
"password": cred.Password,
"type": "weak-password",
},
}, nil
}
}
// 没有找到有效凭据
return &base.ScanResult{
Success: false,
Service: "VNC",
Error: fmt.Errorf("authentication failed for all credentials"),
}, nil
}
// performServiceIdentification 执行服务识别
func (p *VNCPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
// 尝试连接到服务进行基本识别
conn, err := p.GetServiceConnector().Connect(ctx, info)
if err != nil {
return &base.ScanResult{
Success: false,
Error: err,
}, nil
}
defer p.GetServiceConnector().Close(conn)
// 服务识别成功
return &base.ScanResult{
Success: true,
Service: "VNC",
Banner: "VNC service detected",
Extra: map[string]interface{}{
"service": "VNC",
"port": info.Ports,
"type": "service-identification",
},
}, nil
}
// generateCredentials 生成VNC认证凭据
func (p *VNCPlugin) generateCredentials() []*base.Credential {
var credentials []*base.Credential
// VNC只使用密码认证不需要用户名
passwords := common.Passwords
if len(passwords) == 0 {
// 使用默认VNC密码
passwords = []string{"", "123456", "password", "vnc", "admin", "root", "888888", "123123"}
}
// 生成密码凭据VNC不使用用户名
for _, password := range passwords {
credentials = append(credentials, &base.Credential{
Username: "", // VNC不需要用户名
Password: password,
})
}
// 额外尝试常见的VNC密码组合
commonVNCPasswords := []string{
"vnc", "password", "123456", "admin", "root", "guest",
"1234", "12345", "qwerty", "abc123", "888888", "000000",
}
for _, password := range commonVNCPasswords {
// 避免重复添加
found := false
for _, existing := range credentials {
if existing.Password == password {
found = true
break
}
}
if !found {
credentials = append(credentials, &base.Credential{
Username: "",
Password: password,
})
}
}
return credentials
}