package services import ( "bytes" "context" "fmt" "net" "time" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/plugins" ) // RDPPlugin RDP远程桌面服务扫描插件 - 弱密码检测和服务识别 type RDPPlugin struct { plugins.BasePlugin } // NewRDPPlugin 创建RDP插件 func NewRDPPlugin() *RDPPlugin { return &RDPPlugin{ BasePlugin: plugins.NewBasePlugin("rdp"), } } // GetPorts 实现Plugin接口 // Scan 执行RDP扫描 - 基础服务识别 func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 检查端口 if info.Ports != "3389" { return &ScanResult{ Success: false, Service: "rdp", Error: fmt.Errorf("RDP插件仅支持3389端口"), } } // 如果禁用暴力破解,只做服务识别 if common.DisableBrute { return p.identifyService(ctx, info) } // 生成测试凭据 credentials := GenerateCredentials("rdp") if len(credentials) == 0 { // RDP默认凭据 credentials = []Credential{ {Username: "administrator", Password: ""}, {Username: "administrator", Password: "administrator"}, {Username: "administrator", Password: "password"}, {Username: "administrator", Password: "123456"}, {Username: "admin", Password: "admin"}, {Username: "admin", Password: "123456"}, {Username: "user", Password: "user"}, {Username: "test", Password: "test"}, } } // 逐个测试凭据(简化版本,实际RDP认证需要复杂的协议处理) for _, cred := range credentials { // 检查Context是否被取消 select { case <-ctx.Done(): return &ScanResult{ Success: false, Service: "rdp", Error: ctx.Err(), } default: } // 简化的RDP连接测试(实际需要完整的RDP协议实现) if p.testRDPConnection(ctx, info) { common.LogSuccess(fmt.Sprintf("RDP %s 服务可用", target)) return &ScanResult{ Success: true, Service: "rdp", Username: cred.Username, Password: cred.Password, Banner: "RDP服务可用", } } } // 所有凭据都失败 return &ScanResult{ Success: false, Service: "rdp", Error: fmt.Errorf("RDP认证失败"), } } // testRDPConnection 测试RDP连接 func (p *RDPPlugin) testRDPConnection(ctx context.Context, info *common.HostInfo) bool { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 检查发包限制 if canSend, reason := common.CanSendPacket(); !canSend { common.LogError(fmt.Sprintf("RDP连接 %s 受限: %s", target, reason)) return false } conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) if err != nil { common.IncrementTCPFailedPacketCount() return false } common.IncrementTCPSuccessPacketCount() defer conn.Close() conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) // 发送简单的RDP连接请求 rdpRequest := []byte{ 0x03, 0x00, 0x00, 0x13, 0x0e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, } _, err = conn.Write(rdpRequest) if err != nil { return false } // 读取响应 response := make([]byte, 1024) n, err := conn.Read(response) if err != nil || n == 0 { return false } // 简单检查是否为RDP响应 if len(response) >= 4 && response[0] == 0x03 && response[1] == 0x00 { return true } return false } // checkNLAStatus 检查网络级别身份验证状态 func (p *RDPPlugin) checkNLAStatus(ctx context.Context, info *common.HostInfo) string { // 检查发包限制 target := fmt.Sprintf("%s:%s", info.Host, info.Ports) if canSend, reason := common.CanSendPacket(); !canSend { common.LogError(fmt.Sprintf("RDP NLA检测 %s 受限: %s", target, reason)) return "检测失败" } conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) if err != nil { common.IncrementTCPFailedPacketCount() return "检测失败" } common.IncrementTCPSuccessPacketCount() defer conn.Close() conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) // 发送支持NLA的连接请求 nlaRequest := []byte{ 0x03, 0x00, 0x00, 0x2a, 0x25, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x3a, 0x20, 0x6d, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x0d, 0x0a, } _, err = conn.Write(nlaRequest) if err != nil { return "检测失败" } response := make([]byte, 1024) n, err := conn.Read(response) if err != nil || n == 0 { return "检测失败" } // 简化的NLA状态检测 if bytes.Contains(response, []byte("SSL")) || bytes.Contains(response, []byte("TLS")) { return "已启用" } return "未启用" } // detectRDPVersion 检测RDP版本 func (p *RDPPlugin) detectRDPVersion(ctx context.Context, info *common.HostInfo) string { // 简化实现,返回通用信息 return "RDP Protocol (Remote Desktop Protocol)" } // identifyService 服务识别 - 检测RDP服务 func (p *RDPPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) if p.testRDPConnection(ctx, info) { banner := "RDP远程桌面服务" common.LogSuccess(fmt.Sprintf("RDP %s %s", target, banner)) return &ScanResult{ Success: true, Service: "rdp", Banner: banner, } } return &ScanResult{ Success: false, Service: "rdp", Error: fmt.Errorf("无法识别为RDP服务"), } } // init 自动注册插件 func init() { // 使用高效注册方式:直接传递端口信息,避免实例创建 RegisterPluginWithPorts("rdp", func() Plugin { return NewRDPPlugin() }, []int{3389}) }