From df4d39fb1f983011fbddbe76f9e5882a31bb66ec Mon Sep 17 00:00:00 2001 From: ZacharyZcR <2903735704@qq.com> Date: Wed, 1 Jan 2025 00:39:39 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BA=86SMB=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=B7=B2=E7=9F=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plugins/SMB.go | 176 ++++++++++++++++++++----------------------------- 1 file changed, 73 insertions(+), 103 deletions(-) diff --git a/Plugins/SMB.go b/Plugins/SMB.go index f9e036b..049dbbe 100644 --- a/Plugins/SMB.go +++ b/Plugins/SMB.go @@ -1,7 +1,6 @@ package Plugins import ( - "errors" "fmt" "github.com/shadow1ng/fscan/Common" "github.com/stacktitan/smb/smb" @@ -10,24 +9,20 @@ import ( "time" ) -// SmbScan 执行SMB服务的认证扫描 func SmbScan(info *Common.HostInfo) (tmperr error) { if Common.DisableBrute { return nil } - maxRetries := Common.MaxRetries threads := Common.BruteThreads + totalTasks := len(Common.Userdict["smb"]) * len(Common.Passwords) - // 创建任务通道 taskChan := make(chan struct { user string pass string - }, len(Common.Userdict["smb"])*len(Common.Passwords)) + }, totalTasks) - resultChan := make(chan error, threads) - - // 生成所有用户名密码组合任务 + // 生成任务 for _, user := range Common.Userdict["smb"] { for _, pass := range Common.Passwords { pass = strings.Replace(pass, "{user}", user, -1) @@ -39,108 +34,48 @@ func SmbScan(info *Common.HostInfo) (tmperr error) { } close(taskChan) - // 启动工作线程 var wg sync.WaitGroup + successChan := make(chan struct{}, 1) + + // 启动工作线程 for i := 0; i < threads; i++ { wg.Add(1) go func() { defer wg.Done() - startTime := time.Now().Unix() - for task := range taskChan { - // 重试循环 - for retryCount := 0; retryCount < maxRetries; retryCount++ { - // 检查是否超时 - if time.Now().Unix()-startTime > int64(Common.Timeout) { - resultChan <- fmt.Errorf("扫描超时") - return + select { + case <-successChan: + return + default: + } + + success, err := doWithTimeOut(info, task.user, task.pass) + if success { + if Common.Domain != "" { + Common.LogSuccess(fmt.Sprintf("[+] SMB认证成功 %v:%v Domain:%v\\%v Pass:%v", + info.Host, info.Ports, Common.Domain, task.user, task.pass)) + } else { + Common.LogSuccess(fmt.Sprintf("[+] SMB认证成功 %v:%v User:%v Pass:%v", + info.Host, info.Ports, task.user, task.pass)) } - - // 执行SMB认证 - done := make(chan struct { - success bool - err error - }) - - go func(user, pass string) { - success, err := doWithTimeOut(info, user, pass) - done <- struct { - success bool - err error - }{success, err} - }(task.user, task.pass) - - // 等待结果或超时 - var err error - select { - case result := <-done: - err = result.err - if result.success && err == nil { - // 认证成功 - var successLog string - if Common.Domain != "" { - successLog = fmt.Sprintf("[✓] SMB认证成功 %v:%v Domain:%v\\%v Pass:%v", - info.Host, info.Ports, Common.Domain, task.user, task.pass) - } else { - successLog = fmt.Sprintf("[✓] SMB认证成功 %v:%v User:%v Pass:%v", - info.Host, info.Ports, task.user, task.pass) - } - Common.LogSuccess(successLog) - resultChan <- nil - return - } - case <-time.After(time.Duration(Common.Timeout) * time.Second): - err = fmt.Errorf("连接超时") - } - - // 处理错误情况 - if err != nil { - errlog := fmt.Sprintf("[x] SMB认证失败 %v:%v User:%v Pass:%v Err:%v", - info.Host, info.Ports, task.user, task.pass, - strings.ReplaceAll(err.Error(), "\n", "")) - Common.LogError(errlog) - - // 检查是否需要重试 - if retryErr := Common.CheckErrs(err); retryErr != nil { - if retryCount == maxRetries-1 { - resultChan <- err - return - } - continue // 继续重试 - } - } - - break // 如果不需要重试,跳出重试循环 + successChan <- struct{}{} + return + } + if err != nil { + Common.LogError(fmt.Sprintf("[-] SMB认证失败 %v:%v User:%v Pass:%v Err:%v", + info.Host, info.Ports, task.user, task.pass, err)) } } - resultChan <- nil }() } - // 等待所有线程完成 - go func() { - wg.Wait() - close(resultChan) - }() - - // 检查结果 - for err := range resultChan { - if err != nil { - tmperr = err - if retryErr := Common.CheckErrs(err); retryErr != nil { - return err - } - } - } - - return tmperr + wg.Wait() + return nil } -// SmblConn 尝试建立SMB连接并进行认证 func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struct{}) (flag bool, err error) { flag = false - // 配置SMB连接选项 options := smb.Options{ Host: info.Host, Port: 445, @@ -150,34 +85,69 @@ func SmblConn(info *Common.HostInfo, user string, pass string, signal chan struc Workstation: "", } - // 尝试建立SMB会话 session, err := smb.NewSession(options, false) if err == nil { defer session.Close() if session.IsAuthenticated { flag = true + return flag, nil + } + return flag, fmt.Errorf("认证失败") + } + + // 清理错误信息中的换行符和多余空格 + errMsg := strings.TrimSpace(strings.ReplaceAll(err.Error(), "\n", " ")) + if strings.Contains(errMsg, "NT Status Error") { + switch { + case strings.Contains(errMsg, "STATUS_LOGON_FAILURE"): + err = fmt.Errorf("用户名或密码错误") + case strings.Contains(errMsg, "STATUS_ACCOUNT_LOCKED_OUT"): + err = fmt.Errorf("账号已锁定") + case strings.Contains(errMsg, "STATUS_ACCESS_DENIED"): + err = fmt.Errorf("访问被拒绝") + case strings.Contains(errMsg, "STATUS_ACCOUNT_DISABLED"): + err = fmt.Errorf("账号已禁用") + case strings.Contains(errMsg, "STATUS_PASSWORD_EXPIRED"): + err = fmt.Errorf("密码已过期") + case strings.Contains(errMsg, "STATUS_USER_SESSION_DELETED"): + return flag, fmt.Errorf("会话已断开") + default: + err = fmt.Errorf("认证失败") // 简化错误信息 } } - // 发送完成信号 signal <- struct{}{} return flag, err } -// doWithTimeOut 执行带超时的SMB连接认证 func doWithTimeOut(info *Common.HostInfo, user string, pass string) (flag bool, err error) { - signal := make(chan struct{}) + signal := make(chan struct{}, 1) + result := make(chan struct { + success bool + err error + }, 1) - // 在goroutine中执行SMB连接 go func() { - flag, err = SmblConn(info, user, pass, signal) + success, err := SmblConn(info, user, pass, signal) + select { + case result <- struct { + success bool + err error + }{success, err}: + default: + } }() - // 等待连接结果或超时 select { - case <-signal: - return flag, err + case r := <-result: + return r.success, r.err case <-time.After(time.Duration(Common.Timeout) * time.Second): - return false, errors.New("[-] SMB连接超时") + // 尝试从result通道读取,避免协程泄露 + select { + case r := <-result: + return r.success, r.err + default: + return false, fmt.Errorf("连接超时") + } } }