fscan/plugins/legacy/smb/common/errors.go
ZacharyZcR daa7fb2dcb refactor: 重构SMB和SMB2插件架构,大幅减少代码重复
- 创建通用SMB框架,包含抽象接口、凭据管理和并发扫描引擎
- SMB2插件代码量从492行减少到159行,减少68%代码量
- 统一错误分类和处理机制,提高代码可维护性
- 支持密码和哈希两种认证方式,保持向后兼容性
- 模块化设计便于单元测试和功能扩展
2025-08-12 19:11:40 +08:00

102 lines
3.2 KiB
Go

package common
import (
"errors"
"strings"
)
// 定义常见的SMB错误类型
var (
ErrAuthFailed = errors.New("认证失败")
ErrAccountLocked = errors.New("账户锁定")
ErrAccessDenied = errors.New("拒绝访问")
ErrAccountDisabled = errors.New("账户禁用")
ErrPasswordExpired = errors.New("密码过期")
ErrConnectionFailed = errors.New("连接失败")
ErrTimeout = errors.New("连接超时")
ErrSessionDeleted = errors.New("会话断开")
)
// ClassifySmbError 对SMB错误进行分类和标准化
func ClassifySmbError(err error) error {
if err == nil {
return nil
}
// 清理错误信息中的换行符和多余空格
errMsg := strings.TrimSpace(strings.ReplaceAll(err.Error(), "\n", " "))
errMsgLower := strings.ToLower(errMsg)
// SMB1特定错误处理
if strings.Contains(errMsg, "NT Status Error") {
switch {
case strings.Contains(errMsg, "STATUS_LOGON_FAILURE"):
return ErrAuthFailed
case strings.Contains(errMsg, "STATUS_ACCOUNT_LOCKED_OUT"):
return ErrAccountLocked
case strings.Contains(errMsg, "STATUS_ACCESS_DENIED"):
return ErrAccessDenied
case strings.Contains(errMsg, "STATUS_ACCOUNT_DISABLED"):
return ErrAccountDisabled
case strings.Contains(errMsg, "STATUS_PASSWORD_EXPIRED"):
return ErrPasswordExpired
case strings.Contains(errMsg, "STATUS_USER_SESSION_DELETED"):
return ErrSessionDeleted
default:
return ErrAuthFailed
}
}
// SMB2特定错误处理
switch {
case strings.Contains(errMsgLower, "account has been automatically locked") ||
strings.Contains(errMsgLower, "account has been locked") ||
strings.Contains(errMsgLower, "user account has been automatically locked"):
return ErrAccountLocked
case strings.Contains(errMsgLower, "access denied") ||
strings.Contains(errMsgLower, "access is denied"):
return ErrAccessDenied
case strings.Contains(errMsgLower, "account disabled") ||
strings.Contains(errMsgLower, "account is disabled"):
return ErrAccountDisabled
case strings.Contains(errMsgLower, "password expired") ||
strings.Contains(errMsgLower, "password has expired"):
return ErrPasswordExpired
case strings.Contains(errMsgLower, "connection refused") ||
strings.Contains(errMsgLower, "connection failed") ||
strings.Contains(errMsgLower, "no connection could be made"):
return ErrConnectionFailed
case strings.Contains(errMsgLower, "timeout") ||
strings.Contains(errMsgLower, "timed out"):
return ErrTimeout
case strings.Contains(errMsgLower, "session") && strings.Contains(errMsgLower, "deleted"):
return ErrSessionDeleted
case strings.Contains(errMsgLower, "logon failure") ||
strings.Contains(errMsgLower, "authentication failed") ||
strings.Contains(errMsgLower, "login failed"):
return ErrAuthFailed
}
// 默认返回原始错误
return err
}
// IsAccountLockError 判断是否为账户锁定错误
func IsAccountLockError(err error) bool {
return errors.Is(err, ErrAccountLocked) ||
strings.Contains(strings.ToLower(err.Error()), "locked")
}
// IsFatalError 判断是否为致命错误(应该停止尝试该用户)
func IsFatalError(err error) bool {
return errors.Is(err, ErrAccountLocked) ||
errors.Is(err, ErrAccountDisabled) ||
errors.Is(err, ErrPasswordExpired)
}