跳转到帖子

授权内网测试:SMB 登录成功却访问被拒绝,如何定位权限边界?

精选回复

发布于

背景:一个需要分层回答的问题

授权测试时,普通域账号能够连接文件服务器,服务端也出现了登录成功日志,但读取指定共享文件仍然提示 Access is denied。到底是账号权限不足、共享配置错误,还是测试时用错了身份?应该收集哪些证据?

下面使用一个示例环境说明排查方法:文件服务器 FS01,域 EXAMPLE,测试账号 EXAMPLE\audit.reader,共享名 AuditDrop,本地目录 D:\Shares\AuditDrop。管理员预先放置无敏感内容的 probe.txt,授权范围仅包括读取该文件,不包括扫描其他共享、修改 ACL 或执行远程命令。示例名称需要替换成实际批准的对象,文中不假定已经取得任何测试结果。

一、问题定位:登录成功不等于文件读取成功

首先区分身份认证与对象授权。文件服务器上的 4624 表示成功登录,LogonType 为 3 表示网络登录;它不能单独证明某个共享中的文件已经读到。应核对事件里的 TargetUserName、TargetDomainName、TargetLogonId,而不是只看到“登录成功”就判断权限链路已经打通。([learn.microsoft.com]( → 共享 ACL → 目标文件 NTFS ACL → 对应访问事件”的顺序排查。客户端查看连接用 Get-SmbConnection,服务端查看会话用 Get-SmbSession,共享权限用 Get-SmbShareAccess;不要把客户端连接信息与服务端会话信息混为一谈。([learn.microsoft.com]( 的结果只证明这次指定文件读取是否成功,不代表整个共享都可访问。

# 客户端 PowerShell;在批准的测试身份下执行
$server = 'FS01'
$target = '\\FS01\AuditDrop\probe.txt'

Get-Date -Format o
whoami

try {
    Get-Content -LiteralPath $target -TotalCount 1 -ErrorAction Stop
} catch {
    $_ | Format-List FullyQualifiedErrorId,CategoryInfo,Exception
}

Get-SmbConnection |
    Where-Object { $_.ServerName -ieq $server } |
    Format-List ServerName,ShareName,UserName,Credential,Dialect

将 whoami 作为本地执行身份的记录,将 SMB 连接信息作为连接侧核对材料,再由管理员用服务端会话确认实际账号。若两者不符合预期,先解决身份偏差,再讨论权限;不要直接清理整台机器的所有网络连接。上述 SMB 查询命令均有明确的客户端或服务端作用范围。([learn.microsoft.com]( FS01 本地执行以下只读检查。先用 Get-SmbShare 确认共享真实路径,再检查根目录和目标文件,避免只看共享名称就对错误目录下结论。Get-SmbShareAccess 返回共享 ACL,不会代替你检查目标文件的安全描述符。([learn.microsoft.com]( 文件服务器 FS01;管理员 PowerShell $share = Get-SmbShare -Name 'AuditDrop' -ErrorAction Stop $share | Format-List Name,Path Get-SmbShareAccess -Name 'AuditDrop' | Format-Table AccountName,AccessControlType,AccessRight -AutoSize $root = $share.Path $file = Join-Path $root 'probe.txt' foreach ($path in @($root, $file)) { Write-Output "=== $path ===" $acl = Get-Acl -LiteralPath $path $acl | Format-List Owner,AreAccessRulesProtected $acl.Access | Format-Table IdentityReference,AccessControlType, FileSystemRights,IsInherited,InheritanceFlags, PropagationFlags -AutoSize } Get-SmbSession | Where-Object { $_.ClientUserName -ieq 'EXAMPLE\audit.reader' } | Format-Table ClientComputerName,ClientUserName,SessionId, NumOpens -AutoSize

建议把以下内容列成核对清单:共享 ACL 中涉及的用户或组、目标文件上的允许与拒绝条目、条目是否继承,以及测试账号的实际组成员关系。不要在排查时直接运行权限重置或递归授权命令;先保留原始输出,再让资源负责人确认预期访问范围。

四、日志留痕:5145 和 4663 最容易看错

关键区别是:5145 的失败事件只记录共享层拒绝,NTFS 层拒绝不会产生对应的 5145 失败事件。因此,“没有找到失败的 5145”不能证明文件系统权限允许访问,也不能证明测试没有发生。5145 的 ShareName、RelativeTargetName、AccessMask 和 SubjectLogonId 是定位这次请求的重要字段。([learn.microsoft.com]( 表示请求对象句柄,并可记录拒绝;4663 表示某项对象访问权限已经被使用,且没有失败事件版本。不能通过搜索“失败的 4663”来排查读取被拒绝,也不能把一个普通的 4656 成功事件直接当作文件内容已读取的证据。([learn.microsoft.com]( Audit File System,并在目标对象配置匹配账号、操作类型与成功/失败条件的 SACL。若现有日志不足,应由管理员在批准窗口补充配置后重新复现;不要期待事后开启审计能够补出历史访问记录。审计应限于测试对象,避免无计划地扩大日志量。([learn.microsoft.com]( auditpol /get /category:* 只读查看有效审计配置,再由管理员核对高级审核策略中的 Logon、Detailed File Share 和 File System。需要补充文件 SACL 时,在目标文件的“属性 → 安全 → 高级 → 审核”中仅为测试主体配置所需读取操作,记录变更前后状态;不要把“审核”规则误改成“权限”规则。

下面的脚本在 FS01 本地提取最近十五分钟的相关事件,按 XML 字段名称读取数据,不依赖事件属性数组下标。服务器日志量较大时,应把时间窗口缩小到刚才那次复现。

# FS01 本地执行;需要读取 Security 日志的权限
$start = (Get-Date).AddMinutes(-15)

Get-WinEvent -FilterHashtable @{
    LogName = 'Security'
    Id = 4624,5145,4656,4663
    StartTime = $start
} -ErrorAction Stop | ForEach-Object {
    $event = $_
    $xml = [xml]$event.ToXml()
    $data = @{}
    foreach ($item in $xml.Event.EventData.Data) {
        $data[[string]$item.Name] = [string]$item.'#text'
    }

    $user = $data['SubjectUserName']
    $domain = $data['SubjectDomainName']
    $logonId = $data['SubjectLogonId']
    if ($event.Id -eq 4624) {
        $user = $data['TargetUserName']
        $domain = $data['TargetDomainName']
        $logonId = $data['TargetLogonId']
    }

    if (($user -ieq 'audit.reader') -and ($domain -ieq 'EXAMPLE')) {
        [pscustomobject]@{
            Time = $event.TimeCreated
            Computer = $event.MachineName
            RecordId = $event.RecordId
            EventId = $event.Id
            AuditResult = $event.KeywordsDisplayNames -join ';'
            Account = "$domain\$user"
            LogonId = $logonId
            LogonType = $data['LogonType']
            SourceIP = $data['IpAddress']
            Share = $data['ShareName']
            RelativePath = $data['RelativeTargetName']
            ObjectPath = $data['ObjectName']
            AccessMask = $data['AccessMask']
        }
    }
} | Sort-Object Time | Format-List

关联时,在同一台文件服务器上,把 4624 的 TargetLogonId 与后续事件的 SubjectLogonId 对照,并同时核对账号、时间和目标路径。4624 的登录 ID 可用于关联相关事件,但不要把不同主机上的相同数值直接认作同一会话。已有 SMB 会话的登录可能早于十五分钟窗口,此时应扩大查询范围,而不是要求每次读文件前都必须出现新的 4624。([learn.microsoft.com]( 5145 失败:优先核对共享 ACL,不能直接归因于 NTFS。([learn.microsoft.com]( 4656 失败:结合请求权限及访问检查信息,继续定位文件系统授权问题。([learn.microsoft.com]( Everyone 完全控制,也不要把换成域管理员账号后的成功当成问题已经解决。

建议验收至少覆盖三组用例:应允许的账号能够读取 probe.txt;应拒绝的账号仍被拒绝;相邻未授权对象保持原有边界。若需要验证写入权限,必须单独取得批准,并使用专用测试文件,不覆盖现有业务内容。审计记录及导出材料按内部证据规范保管,避免把账号、路径和源地址原样贴到公开帖子。

总结:问答帖应交付可复核的证据

这类问题的有效答案不是“再换一个工具试试”,而是明确三件事:服务器实际看到了谁、哪一层处理了什么访问请求、结果是否符合权限设计。发帖求助时,建议附上脱敏后的客户端错误、共享与文件 ACL、复现时间和对应事件字段。凭这些信息,其他成员才能判断问题卡在身份、共享还是文件系统层,而不是围绕一句 Access is denied 猜测。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意
网络流量与边界分析示意图
网络请求、日志与边界流量分析示意

这类情况先不要把“登录成功”当成“有目录权限”。SMB 至少要分两层判断:共享级权限和共享目录的 NTFS/文件系统权限,最终结果通常取两者中更严格的一层。

建议在授权范围内按下面顺序定位:

  1. 确认实际使用的身份和连接是否复用。Windows 客户端可能复用了已有的 SMB 会话,导致你输入的新账号并未真正生效:

    net use \\server\share
    net use * /delete
    net use \\server\share /user:DOMAIN\testuser *

    如果是 IP 访问而不是主机名,也要注意 Kerberos 可能退化为 NTLM,进一步影响服务端看到的身份。服务端安全日志 4624、5140/5145 可用于确认登录账号和访问对象。

  2. 先看共享级 ACL。在文件服务器上执行:

    Get-SmbShareAccess -Name "share"
    
    Get-SmbShare -Name "share" |
      Select-Object Name,Path,EncryptData,ContinuouslyAvailable

    重点确认账号是否通过直接授权或组成员关系获得了 Read、Change 或 Full。如果共享级只有 Read,即使 NTFS 允许写入,创建文件仍会被拒绝。

  3. 再看共享根目录及目标子目录的 NTFS ACL:

    icacls D:\Shares\share
    icacls D:\Shares\share\subdir
    
    Get-Acl D:\Shares\share\subdir |
      Format-List Owner,Access

    特别检查是否存在显式 Deny、继承被关闭、以及父目录上的“仅遍历文件夹/列出文件夹”权限。需要判断某个账号的有效权限时,可以使用:

    Get-ChildItem "D:\Shares\share\subdir" -Force |
      Get-Acl |
      Select-Object Path,Owner,AccessToString

    不要只看用户的直接 ACE,还要展开其实际组成员关系:

    whoami /user
    whoami /groups
    net user testuser /domain
  4. 注意访问路径对应的真实目录。共享可能指向 DFS、挂载点、符号链接或重解析点,看到的路径不一定是最终 NTFS 权限所在位置。先确认:

    Get-SmbShare -Name "share" | Select Name,Path
    fsutil reparsepoint query D:\Shares\share\subdir

    如果是 DFS,还要分别检查命名空间权限和后端目标服务器上的共享/NTFS 权限。

  5. 用最小化动作区分是哪一层拒绝。例如分别测试列目录、读取已有文件、创建临时文件、删除临时文件,而不是直接用资源管理器判断:

    dir \\server\share\subdir
    type \\server\share\subdir\readme.txt
    echo test > \\server\share\subdir\perm-test.txt
    del \\server\share\subdir\perm-test.txt

    “能列目录但不能创建文件”通常是写入/创建权限不足;“能读文件但不能列目录”则可能是目录枚举权限受限,不一定代表文件不可读。

如果 ACL 看起来都允许但仍然返回拒绝,建议在服务端同时查 Microsoft-Windows-SMBServer/Operational 日志,以及安全日志中的 5145 详细共享访问事件。重点核对 SubjectUserName、ShareName、RelativeTargetName 和访问掩码,避免把“认证成功的账号”与“实际访问资源时使用的令牌”混淆。对于域账号,还要确认客户端是否拿到了最新组成员关系,必要时注销重新登录后再测。

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。