From e504c22d82089252e15a626eb35b381dd638240c Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Thu, 15 Jan 2026 00:10:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D-user/-pwd=E5=87=AD?= =?UTF-8?q?=E6=8D=AE=E5=8F=82=E6=95=B0=E4=B8=8D=E7=94=9F=E6=95=88=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题原因: - Parse()解析凭据后更新globalConfig - 但BuildConfigFromFlags()创建新Config时使用默认字典 - 导致解析的UserPassPairs等凭据信息被丢弃 修复内容: 1. initialize.go: 将Parse解析的凭据结果应用到新Config 2. credential.go: 单用户密码对时创建UserPassPairs 3. rdp.go: 单凭据测试时跳过指纹识别,减少连接次数 --- common/initialize.go | 23 ++++++++++++++++++++++- common/parsers/credential.go | 12 ++++++++++++ plugins/services/rdp.go | 26 ++++++++++++++++++++------ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/common/initialize.go b/common/initialize.go index a6bfe29..2d6aefe 100644 --- a/common/initialize.go +++ b/common/initialize.go @@ -24,15 +24,36 @@ func Initialize(info *HostInfo) (*InitResult, error) { // 初始化日志系统 InitLogger() - // 解析和验证参数 + // 解析和验证参数(会更新 globalConfig 的凭据信息) if err := Parse(info); err != nil { return nil, fmt.Errorf("参数解析失败: %w", err) } + // 获取 Parse 更新过的凭据信息 + parsedCreds := GetGlobalConfig().Credentials + // 从 FlagVars 构建 Config(新架构) cfg := BuildConfigFromFlags(flagVars) state := NewState() + // 关键修复:应用 Parse 解析的凭据结果到新 Config + // Parse 会根据 -user/-pwd/-usera/-pwda 等参数更新凭据 + if len(parsedCreds.UserPassPairs) > 0 { + cfg.Credentials.UserPassPairs = parsedCreds.UserPassPairs + } + if len(parsedCreds.Userdict) > 0 { + cfg.Credentials.Userdict = parsedCreds.Userdict + } + if len(parsedCreds.Passwords) > 0 { + cfg.Credentials.Passwords = parsedCreds.Passwords + } + if len(parsedCreds.HashValues) > 0 { + cfg.Credentials.HashValues = parsedCreds.HashValues + } + if len(parsedCreds.HashBytes) > 0 { + cfg.Credentials.HashBytes = parsedCreds.HashBytes + } + // 设置全局实例 SetGlobalConfig(cfg) SetGlobalState(state) diff --git a/common/parsers/credential.go b/common/parsers/credential.go index e65fa6b..7172bd4 100644 --- a/common/parsers/credential.go +++ b/common/parsers/credential.go @@ -354,6 +354,18 @@ func (cp *CredentialParser) parseUserPassPairs(input *CredentialInput) ([]config var errors []error var warnings []string + // 如果命令行同时指定了单个用户名和单个密码(不是逗号分隔的多个), + // 将其视为精确的用户密码对,而不是做笛卡尔积 + if input.Username != "" && input.Password != "" && + !strings.Contains(input.Username, ",") && !strings.Contains(input.Password, ",") && + input.UsersFile == "" && input.PasswordsFile == "" && input.UserPassFile == "" { + pairs = append(pairs, config.CredentialPair{ + Username: strings.TrimSpace(input.Username), + Password: input.Password, // 密码不trim,可能包含空格 + }) + return pairs, errors, warnings + } + if input.UserPassFile == "" { return pairs, errors, warnings } diff --git a/plugins/services/rdp.go b/plugins/services/rdp.go index e440f35..cfaed47 100644 --- a/plugins/services/rdp.go +++ b/plugins/services/rdp.go @@ -39,12 +39,23 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo, config *com login.Socks5Proxy = config.Network.Socks5Proxy } + // 生成测试凭据(提前生成,用于判断是否为单一凭据测试) + credentials := GenerateCredentials("rdp", config) + + // 判断是否为单一凭据测试模式(只有1个凭据时跳过指纹识别) + isSingleCredentialTest := len(credentials) == 1 + + var osInfo map[string]any + // ============================================ // 第一阶段:系统指纹识别(无需密码) + // 单一凭据测试时跳过此阶段,减少连接次数 // ============================================ - osInfo := p.probeOSInfo(target, config, state) - if len(osInfo) > 0 { - p.logOSInfo(target, osInfo) + if !isSingleCredentialTest { + osInfo = p.probeOSInfo(target, config, state) + if len(osInfo) > 0 { + p.logOSInfo(target, osInfo) + } } // ============================================ @@ -52,6 +63,12 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo, config *com // ============================================ if config.DisableBrute { // 禁用暴力破解,仅返回服务识别结果 + if osInfo == nil { + osInfo = p.probeOSInfo(target, config, state) + if len(osInfo) > 0 { + p.logOSInfo(target, osInfo) + } + } banner := p.buildBanner(osInfo) common.LogSuccess(i18n.Tr("rdp_service", target, banner)) return &ScanResult{ @@ -61,9 +78,6 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo, config *com Banner: banner, } } - - // 生成测试凭据 - credentials := GenerateCredentials("rdp", config) if len(credentials) == 0 { credentials = []Credential{ {Username: "administrator", Password: ""},