fscan/Plugins/services/vnc/plugin.go
ZacharyZcR 6fda09f183 feat: 实现VNC远程桌面协议专业扫描插件
- 新增VNC服务连接器,支持mitchellh/go-vnc库
- 实现基于密码的VNC认证机制
- 支持VNC常用端口(5900-5903)扫描
- 集成弱密码检测功能
- 添加VNC服务识别能力
- 配置Docker测试环境
- 更新插件注册表和国际化消息

测试验证: ✓ VNC弱密码检测正常工作
2025-08-09 16:02:05 +08:00

187 lines
4.7 KiB
Go
Raw 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 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
}