fscan/Plugins/services/rsync/plugin.go
ZacharyZcR c2bb4bfd35 feat: Rsync和SMTP服务插件迁移到新架构完成
- 完成Rsync文件同步服务插件迁移
  * 实现RSYNCD协议支持和模块列表获取
  * 支持匿名访问和认证扫描
  * 添加Docker测试环境配置

- 完成SMTP邮件服务插件迁移
  * 实现SMTP协议和PLAIN认证支持
  * 支持匿名访问检测和弱密码扫描
  * 添加Docker测试环境配置

- 更新国际化消息和插件注册机制
- 两个插件均通过完整功能测试验证
2025-08-09 13:46:46 +08:00

254 lines
7.0 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 rsync
import (
"context"
"fmt"
"strings"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/plugins/base"
)
// RsyncPlugin Rsync插件实现
type RsyncPlugin struct {
*base.ServicePlugin
exploiter *RsyncExploiter
}
// NewRsyncPlugin 创建Rsync插件
func NewRsyncPlugin() *RsyncPlugin {
// 插件元数据
metadata := &base.PluginMetadata{
Name: "rsync",
Version: "2.0.0",
Author: "fscan-team",
Description: "Rsync文件同步服务扫描插件",
Category: "service",
Ports: []int{873}, // Rsync默认端口
Protocols: []string{"tcp"},
Tags: []string{"rsync", "file-sync", "weak-password", "unauthorized-access"},
}
// 创建连接器和服务插件
connector := NewRsyncConnector()
servicePlugin := base.NewServicePlugin(metadata, connector)
// 创建Rsync插件
plugin := &RsyncPlugin{
ServicePlugin: servicePlugin,
exploiter: NewRsyncExploiter(),
}
// 设置能力
plugin.SetCapabilities([]base.Capability{
base.CapWeakPassword,
base.CapUnauthorized,
})
return plugin
}
// Scan 重写扫描方法进行Rsync服务扫描
func (p *RsyncPlugin) 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)
// 首先尝试匿名访问
anonymousCred := &base.Credential{Username: "", Password: ""}
result, err := p.ScanCredential(ctx, info, anonymousCred)
if err == nil && result.Success {
// 匿名访问成功
common.LogSuccess(i18n.GetText("rsync_anonymous_success", target))
return &base.ScanResult{
Success: true,
Service: "Rsync",
Credentials: []*base.Credential{anonymousCred},
Banner: result.Banner,
Extra: map[string]interface{}{
"service": "Rsync",
"port": info.Ports,
"type": "anonymous-access",
},
}, nil
}
// 优先尝试默认凭据
defaultCredentials := []*base.Credential{
{Username: "root", Password: "root123"},
{Username: "admin", Password: "123456"},
{Username: "testuser", Password: "123456"},
{Username: "backup", Password: "backup"},
{Username: "rsync", Password: "rsync"},
}
// 先测试默认凭据
for _, cred := range defaultCredentials {
result, err := p.ScanCredential(ctx, info, cred)
if err == nil && result.Success {
// 认证成功
common.LogSuccess(i18n.GetText("rsync_weak_pwd_success", target, cred.Username, cred.Password))
return &base.ScanResult{
Success: true,
Service: "Rsync",
Credentials: []*base.Credential{cred},
Banner: result.Banner,
Extra: map[string]interface{}{
"service": "Rsync",
"port": info.Ports,
"username": cred.Username,
"password": cred.Password,
"type": "default-credentials",
},
}, nil
}
}
// 生成其他凭据进行暴力破解
credentials := p.generateCredentials()
// 遍历凭据进行测试
for _, cred := range credentials {
result, err := p.ScanCredential(ctx, info, cred)
if err == nil && result.Success {
// 认证成功
common.LogSuccess(i18n.GetText("rsync_weak_pwd_success", target, cred.Username, cred.Password))
return &base.ScanResult{
Success: true,
Service: "Rsync",
Credentials: []*base.Credential{cred},
Banner: result.Banner,
Extra: map[string]interface{}{
"service": "Rsync",
"port": info.Ports,
"username": cred.Username,
"password": cred.Password,
"type": "weak-password",
},
}, nil
}
}
// 所有凭据都失败但可能识别到了Rsync服务
return p.performServiceIdentification(ctx, info)
}
// generateCredentials 生成Rsync凭据
func (p *RsyncPlugin) generateCredentials() []*base.Credential {
var credentials []*base.Credential
// 获取Rsync用户名字典
usernames := common.Userdict["rsync"]
if len(usernames) == 0 {
usernames = []string{"root", "admin", "rsync", "backup", "user", "test", "testuser"}
}
// 获取密码字典
passwords := common.Passwords
if len(passwords) == 0 {
passwords = []string{"", "admin", "password", "123456", "rsync", "root123", "admin123", "backup", "test123"}
}
// 生成用户名密码组合
for _, username := range usernames {
for _, password := range passwords {
// 替换密码中的用户名占位符
actualPassword := strings.Replace(password, "{user}", username, -1)
credentials = append(credentials, &base.Credential{
Username: username,
Password: actualPassword,
})
}
}
return credentials
}
// Exploit 使用exploiter执行利用
func (p *RsyncPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) {
return p.exploiter.Exploit(ctx, info, creds)
}
// GetExploitMethods 获取利用方法
func (p *RsyncPlugin) GetExploitMethods() []base.ExploitMethod {
return p.exploiter.GetExploitMethods()
}
// IsExploitSupported 检查利用支持
func (p *RsyncPlugin) IsExploitSupported(method base.ExploitType) bool {
return p.exploiter.IsExploitSupported(method)
}
// performServiceIdentification 执行Rsync服务识别-nobr模式
func (p *RsyncPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 尝试识别Rsync服务
connector := NewRsyncConnector()
conn, err := connector.Connect(ctx, info)
if err == nil && conn != nil {
if rsyncConn, ok := conn.(*RsyncConnection); ok {
// 记录服务识别成功
common.LogSuccess(i18n.GetText("rsync_service_identified", target, rsyncConn.info))
connector.Close(conn)
return &base.ScanResult{
Success: true,
Service: "Rsync",
Banner: rsyncConn.info,
Extra: map[string]interface{}{
"service": "Rsync",
"port": info.Ports,
"info": rsyncConn.info,
"protocol": "RSYNCD",
"modules": rsyncConn.modules,
},
}, nil
}
}
// 如果无法识别为Rsync返回失败
return &base.ScanResult{
Success: false,
Error: fmt.Errorf("无法识别为Rsync服务"),
}, nil
}
// =============================================================================
// 插件注册
// =============================================================================
// RegisterRsyncPlugin 注册Rsync插件
func RegisterRsyncPlugin() {
factory := base.NewSimplePluginFactory(
&base.PluginMetadata{
Name: "rsync",
Version: "2.0.0",
Author: "fscan-team",
Description: "Rsync文件同步服务扫描插件",
Category: "service",
Ports: []int{873}, // Rsync默认端口
Protocols: []string{"tcp"},
Tags: []string{"rsync", "file-sync", "weak-password", "unauthorized-access"},
},
func() base.Plugin {
return NewRsyncPlugin()
},
)
base.GlobalPluginRegistry.Register("rsync", factory)
}
// 自动注册
func init() {
RegisterRsyncPlugin()
}