package services import ( "bufio" "context" "fmt" "net" "strings" "time" "github.com/shadow1ng/fscan/common" ) type RsyncPlugin struct { name string ports []int } func NewRsyncPlugin() *RsyncPlugin { return &RsyncPlugin{ name: "rsync", ports: []int{873}, } } func (p *RsyncPlugin) GetName() string { return p.name } func (p *RsyncPlugin) GetPorts() []int { return p.ports } func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) if common.DisableBrute { return p.identifyService(ctx, info) } if result := p.testUnauthorizedAccess(ctx, info); result != nil && result.Success { common.LogSuccess(fmt.Sprintf("Rsync %s 未授权访问", target)) return result } credentials := GenerateCredentials("rsync") if len(credentials) == 0 { return &ScanResult{ Success: false, Service: "rsync", Error: fmt.Errorf("没有可用的测试凭据"), } } for _, cred := range credentials { if p.testCredential(ctx, info, cred) { common.LogSuccess(fmt.Sprintf("Rsync %s %s:%s", target, cred.Username, cred.Password)) return &ScanResult{ Success: true, Service: "rsync", Username: cred.Username, Password: cred.Password, } } } return &ScanResult{ Success: false, Service: "rsync", Error: fmt.Errorf("未发现弱密码"), } } func (p *RsyncPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo) *ScanResult { conn := p.connectToRsync(ctx, info) if conn == nil { return nil } defer conn.Close() modules := p.getModules(conn) if len(modules) > 0 { return &ScanResult{ Success: true, Service: "rsync", Banner: "未授权访问", } } return nil } func (p *RsyncPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { return false } func (p *RsyncPlugin) connectToRsync(ctx context.Context, info *common.HostInfo) net.Conn { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) timeout := time.Duration(common.Timeout) * time.Second conn, err := net.DialTimeout("tcp", target, timeout) if err != nil { return nil } conn.SetDeadline(time.Now().Add(timeout)) return conn } func (p *RsyncPlugin) getModules(conn net.Conn) []string { timeout := time.Duration(common.Timeout) * time.Second conn.SetWriteDeadline(time.Now().Add(timeout)) if _, err := conn.Write([]byte("\n")); err != nil { return nil } conn.SetReadDeadline(time.Now().Add(timeout)) scanner := bufio.NewScanner(conn) var modules []string for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" { continue } if strings.HasPrefix(line, "@RSYNCD: EXIT") { break } if strings.HasPrefix(line, "@RSYNCD:") { continue } modules = append(modules, line) } return modules } func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) conn := p.connectToRsync(ctx, info) if conn == nil { return &ScanResult{ Success: false, Service: "rsync", Error: fmt.Errorf("无法连接到Rsync服务"), } } defer conn.Close() timeout := time.Duration(common.Timeout) * time.Second conn.SetWriteDeadline(time.Now().Add(timeout)) if _, err := conn.Write([]byte("\n")); err != nil { return &ScanResult{ Success: false, Service: "rsync", Error: err, } } conn.SetReadDeadline(time.Now().Add(timeout)) response := make([]byte, 1024) n, err := conn.Read(response) if err != nil { return &ScanResult{ Success: false, Service: "rsync", Error: err, } } responseStr := string(response[:n]) var banner string if strings.Contains(responseStr, "@RSYNCD") { lines := strings.Split(responseStr, "\n") for _, line := range lines { if strings.HasPrefix(line, "@RSYNCD:") { banner = fmt.Sprintf("Rsync服务 (%s)", strings.TrimSpace(line)) break } } if banner == "" { banner = "Rsync文件同步服务" } } else { return &ScanResult{ Success: false, Service: "rsync", Error: fmt.Errorf("无法识别为Rsync服务"), } } common.LogSuccess(fmt.Sprintf("Rsync %s %s", target, banner)) return &ScanResult{ Success: true, Service: "rsync", Banner: banner, } } func init() { // 使用高效注册方式:直接传递端口信息,避免实例创建 RegisterPluginWithPorts("rsync", func() Plugin { return NewRsyncPlugin() }, []int{873}) }