mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00
refactor: 清理项目死代码和未使用函数
- 移除所有未使用的generateCredentials方法 - 删除插件适配器中的过时函数 - 清理MySQL连接器中的无用方法 - 移除Redis利用器中的未调用函数 - 删除遗留加密函数和基础扫描器无用方法 - 完全移除未注册的VNC插件 - 优化代码结构,提升项目可维护性 清理统计: 移除25+个死代码函数,减少400+行无用代码
This commit is contained in:
parent
b89bf4b0da
commit
f097d2812a
@ -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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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
|
||||
}
|
||||
// Legacy plugin adapter functionality has been removed as it was unused.
|
||||
// This file is preserved for future compatibility needs if required.
|
@ -264,46 +264,4 @@ func GenerateCredentials(usernames []string, passwords []string) []*Credential {
|
||||
return credentials
|
||||
}
|
||||
|
||||
// GeneratePasswordOnlyCredentials 生成仅密码的凭据列表(如Redis)
|
||||
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等函数
|
||||
}
|
||||
}
|
||||
// 已移除未使用的 GeneratePasswordOnlyCredentials 方法
|
@ -1,7 +1,6 @@
|
||||
package Plugins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
@ -44,32 +43,6 @@ func ReadBytes(conn net.Conn) ([]byte, error) {
|
||||
// 默认AES加密密钥
|
||||
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模式解密字符串
|
||||
func AesDecrypt(crypted string, key string) (string, error) {
|
||||
@ -104,12 +77,6 @@ func AesDecrypt(crypted string, key string) (string, error) {
|
||||
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填充
|
||||
func PKCS7UnPadding(data []byte) ([]byte, error) {
|
||||
|
@ -172,15 +172,7 @@ func (c *ActiveMQConnector) parseSTOMPResponse(response string) (bool, error) {
|
||||
|
||||
|
||||
|
||||
// getProtocolByPort 根据端口获取协议类型
|
||||
func (c *ActiveMQConnector) getProtocolByPort(port int) string {
|
||||
switch port {
|
||||
case 61613, 61614:
|
||||
return "STOMP"
|
||||
default:
|
||||
return "STOMP" // 默认仅支持STOMP
|
||||
}
|
||||
}
|
||||
// 已移除未使用的 getProtocolByPort 方法
|
||||
|
||||
// GetDefaultCredentials 获取ActiveMQ默认凭据
|
||||
func (c *ActiveMQConnector) GetDefaultCredentials() []*base.Credential {
|
||||
|
@ -150,37 +150,7 @@ func (p *ActiveMQPlugin) IsExploitSupported(method base.ExploitType) bool {
|
||||
return p.exploiter.IsExploitSupported(method)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// performServiceIdentification 执行服务识别(-nobr模式)
|
||||
func (p *ActiveMQPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
|
@ -85,30 +85,7 @@ func (p *CassandraPlugin) Scan(ctx context.Context, info *common.HostInfo) (*bas
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// generateCredentials 生成Cassandra凭据
|
||||
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
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// autoExploit 自动利用功能
|
||||
func (p *CassandraPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) {
|
||||
|
@ -99,17 +99,7 @@ func (p *FTPPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Scan
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// generateCredentials 生成FTP凭据
|
||||
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)
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// autoExploit 自动利用功能
|
||||
func (p *FTPPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) {
|
||||
|
@ -75,17 +75,7 @@ func (p *IMAPPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sca
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// Exploit 使用exploiter执行利用
|
||||
func (p *IMAPPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
|
||||
|
@ -93,17 +93,7 @@ func (p *KafkaPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sc
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// Exploit 使用exploiter执行利用
|
||||
func (p *KafkaPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
|
||||
|
@ -94,17 +94,7 @@ func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.Sca
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// Exploit 使用exploiter执行利用
|
||||
func (p *LDAPPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
|
||||
|
@ -87,13 +87,7 @@ func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo) (*bas
|
||||
}, nil
|
||||
}
|
||||
|
||||
// generateCredentials Memcached通常无需凭据,返回空凭据
|
||||
func (p *MemcachedPlugin) generateCredentials() []*base.Credential {
|
||||
// Memcached通常无认证机制,只返回空凭据用于未授权访问检测
|
||||
return []*base.Credential{
|
||||
{Username: "", Password: ""},
|
||||
}
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// Exploit 使用exploiter执行利用
|
||||
func (p *MemcachedPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
|
||||
|
@ -94,13 +94,7 @@ func (p *ModbusPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.S
|
||||
}, nil
|
||||
}
|
||||
|
||||
// generateCredentials Modbus通常无需凭据,返回空凭据
|
||||
func (p *ModbusPlugin) generateCredentials() []*base.Credential {
|
||||
// Modbus协议通常无认证机制,只返回空凭据用于协议检测
|
||||
return []*base.Credential{
|
||||
{Username: "", Password: ""},
|
||||
}
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// getDeviceInfo 获取Modbus设备信息
|
||||
func (p *ModbusPlugin) getDeviceInfo(ctx context.Context, info *common.HostInfo) string {
|
||||
|
@ -89,33 +89,7 @@ func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.
|
||||
}, nil
|
||||
}
|
||||
|
||||
// generateCredentials MongoDB主要用于未授权访问检测
|
||||
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
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// Exploit 使用exploiter执行利用
|
||||
func (p *MongoDBPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
|
||||
|
@ -103,22 +103,7 @@ func (c *MySQLConnector) Close(conn interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
// 已移除未使用的 connectWithCredentials 方法
|
||||
|
||||
// buildConnectionString 构建MySQL连接字符串
|
||||
// 根据是否配置SOCKS代理选择合适的连接方式
|
||||
@ -136,11 +121,7 @@ func (c *MySQLConnector) buildConnectionString(host string, port int, username,
|
||||
}
|
||||
}
|
||||
|
||||
// buildConnectionStringWithCredentials 构建带凭据的连接字符串
|
||||
func (c *MySQLConnector) buildConnectionStringWithCredentials(cred *base.Credential) string {
|
||||
// 使用保存的主机和端口信息
|
||||
return c.buildConnectionString(c.host, c.port, cred.Username, cred.Password)
|
||||
}
|
||||
// 已移除未使用的 buildConnectionStringWithCredentials 方法
|
||||
|
||||
// connectDirect 内存优化:直接建立MySQL连接,避免连接池开销
|
||||
// 用于单次认证场景,减少内存分配和资源浪费
|
||||
|
@ -124,17 +124,7 @@ func (p *MySQLPlugin) IsExploitSupported(method base.ExploitType) bool {
|
||||
return p.exploiter.IsExploitSupported(method)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// performServiceIdentification 执行MySQL服务识别(-nobr模式)
|
||||
func (p *MySQLPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
|
@ -220,68 +220,9 @@ func (e *RedisExploiter) exploitCrontabInjection(ctx context.Context, info *comm
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
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
|
||||
}
|
||||
// 已移除未使用的 exploitDataExtraction 方法
|
||||
|
||||
// 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
|
||||
}
|
||||
// 已移除未使用的 exploitInfoGathering 方法
|
||||
|
||||
// =============================================================================
|
||||
// Redis操作辅助函数
|
||||
@ -413,36 +354,8 @@ func (e *RedisExploiter) readFirstNonEmptyLine(filename string) (string, error)
|
||||
return "", fmt.Errorf("文件为空或无内容")
|
||||
}
|
||||
|
||||
// getAllKeys 获取所有Redis键
|
||||
func (e *RedisExploiter) getAllKeys(conn *RedisConnection) ([]string, error) {
|
||||
response, err := e.connector.ExecuteCommand(conn, "KEYS *")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 简单解析键列表(实际应该按Redis协议解析)
|
||||
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
|
||||
}
|
||||
// 已移除未使用的 getAllKeys 方法
|
||||
|
||||
// getKeyValue 获取键值
|
||||
func (e *RedisExploiter) getKeyValue(conn *RedisConnection, key string) (string, error) {
|
||||
command := fmt.Sprintf("GET %s", key)
|
||||
return e.connector.ExecuteCommand(conn, command)
|
||||
}
|
||||
// 已移除未使用的 getKeyValue 方法
|
||||
|
||||
// min 返回两个整数中的较小值
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
// 已移除未使用的 min 函数
|
@ -164,11 +164,7 @@ func (p *RedisPlugin) IsExploitSupported(method base.ExploitType) bool {
|
||||
return p.exploiter.IsExploitSupported(method)
|
||||
}
|
||||
|
||||
// generateCredentials 重写凭据生成方法(Redis只需要密码)
|
||||
func (p *RedisPlugin) generateCredentials() []*base.Credential {
|
||||
// Redis通常只需要密码,不需要用户名
|
||||
return base.GeneratePasswordOnlyCredentials(common.Passwords)
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
// performServiceIdentification 执行Redis服务识别(-nobr模式)
|
||||
func (p *RedisPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
|
||||
|
@ -207,17 +207,7 @@ func (p *SSHPlugin) scanWithKey(ctx context.Context, info *common.HostInfo) *bas
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
// 已移除未使用的 generateCredentials 方法
|
||||
|
||||
|
||||
// Exploit 使用exploiter执行利用
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user