欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

如何滥用SMB挂载点绕过客户端符号链接保护策略

来源: 作者: 时间:2019-02-24 21:26 点击: 我要投稿
广告位API接口通信错误,查看德得广告获取帮助

本文简要介绍了SMBv2中的一个有趣特性,可能用于横向渗透或者红方行动中。之前我曾专门花时间研究Windows上的符号链接(symbolic link)攻击,当时我仔细研究过SMB服务器。从SMBv2开始,该协议就已支持符号链接(特别是NTFS 重解析点(Reparse Point)格式)。如果SMB服务器在共享目录中遇到NTFS符号链接,则会提取REPARSE_DATA_BUFFER结构,然后遵循SMBv2协议中相应规范将该信息返回给客户端。

客户端操作系统负责解析REPARSE_DATA_BUFFER数据,然后再从本地访问。这意味着符号链接只能引用客户端已经能够访问的文件。实际上,虽然默认情况下Windows没有启用符号链接本地解析功能,我还是找到了绕过客户端策略的一种方法,能够本地解析符号链接。目前微软拒绝修复这个绕过问题,如果大家感兴趣可以访问此处了解官方回复。
 
0x01 问题描述
我发现有一点非常有趣,虽然IO_REPARSE_TAG_SYMLINK会在客户端上处理,但如果服务器遇到IO_REPARSE_TAG_MOUNT_POINT重解析点,则会到服务器上去解析。因此,如果我们能在共享目录中设置挂载点(mout point),就可以访问服务器上的任意固定位置(即使该位置没有直接共享出来)。这种场景在横向渗透中非常有用,但问题在于,我们如何在无法本地访问硬盘的情况下添加挂载点?
 
0x02 具体分析
首先我们尝试一下通过UNC路径创建挂载点,可以在CMD中使用MKLINK命令,结果如下所示:

输出信息表示系统不支持在远程服务器上设置挂载点。这一点也能够理解,因为在远程驱动器上设置挂载点可能会导致不可预期后果。我们可以猜测一下,要么该协议不支持设置重解析点,要么做了些限制,只允许符号链接。如果想了解协议具体支持的功能,我们可以查看协议规范。设置重解析点需要向某个文件发送FSCTL_SET_REPARSE_POINT IO控制代码(control code),因此我们可以参考SMB2 IOCTL命令,查看其中是否存在与控制代码有关的信息。
一番搜索后,我们可以看到协议的确支持FSCTL_SET_REPARSE_POINT,并且协议规范中有如下描述(§3.3.5.15.13):
当服务器收到包含包含SMB2头部的请求,并且Command值等于SMB2 IOCTL、CtlCode等于FSCTL_SET_REPARSE_POINT时,那么消息处理过程如下:
根据[MS-FSCC] section 2.3.65规范,如果FSCTL_SET_REPARSE_POINT中的ReparseTag字段不等于IO_REPARSE_TAG_SYMLINK,那么服务器应该验证调用方的确有权限执行这个FSCTL。如果调用方不具备所需的权限,那么服务器必须拒绝该调用,返回STATUS_ACCESS_DENIED错误代码。
根据上述文字,貌似服务器只需要显示检查IO_REPARSE_TAG_SYMLINK即可,如果不匹配该标签,则会执行其他检查操作判断请求是否允许,但并没有提到服务器会设置另一个标签来显式禁止请求。也许系统内置的MKLINK工具不能处理这种场景,换个工具试试?这里我们可以尝试下CreateMountPoint工具(来自于我的symboliclink-testing-tools项目),看能不能成功。

CreateMountPoint工具并没有显示之前的错误(“只支持本地NTFS卷”),但返回了拒绝访问错误。这与§3.3.5.15.13中的描述相符,如果隐式检查失败,应当返回拒绝访问错误。当然协议规范中并没有表明需要执行哪些检查,我认为这时候应该派上反编译工具,分析一下SMBv2驱动(srv2.sys)的具体实现。
我使用IDA来查找IO_REPARSE_TAG_SYMLINK对应的立即数(immediate value,这里为0xA000000C),根据分析结果,貌似系统在查找其他标志时,会先会查找这个值。在Windows 10 1809系统的驱动中,我只在Smb2ValidateIoctl找到一处匹配值,相关代码大致如下:
NTSTATUS Smb2ValidateIoctl(SmbIoctlRequest* request) {
  // ...
  switch(request->IoControlCode) {
    case FSCTL_SET_REPARSE_POINT:
      REPARSE_DATA_BUFFER* reparse = (REPARSE_DATA_BUFFER*)request->Buffer;
      // Validate length etc.
      if (reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK &&
          !request->SomeOffset->SomeByteValue) {
          return STATUS_ACCESS_DENIED;
      }
      // Complete FSCTL_SET_REPARSE_POINT request.
    }
}
上述代码首先从IOCTL请求中提取数据,如果标志不等于IO_REPARSE_TAG_SYMLINK并且请求中某些字节值不等于0,那么就会返回STATUS_ACCESS_DENIED错误。如果想跟踪这个值的来源,有时候会比较棘手,但其实我只需要在IDA中将变量偏移值作为立即数来搜索,通常就能得出结论。这里对应的立即数为0x200,我们可以只搜索MOV指令。最终我在Smb2ExecuteSessionSetupReal中找到了一条指令:MOV [RCX+0x200], AL,这似乎就是我们想要的结果。系统会使用Smb2IsAdmin函数的返回值来设置该变量,而该函数只会检查调用方令牌中是否包含BUILTIN\Administrators组。因此貌似只要我们是主机上的管理员,就可以在远程共享上设置任意重解析点。我们需要验证这一点:

[1] [2]  下一页

本文简要介绍了SMBv2中的一个有趣特性,可能用于横向渗透或者红方行动中。之前我曾专门花时间研究Windows上的符号链接(symbolic link)攻击,当时我仔细研究过SMB服务器。从SMBv2开始,该协议就已支持符号链接(特别是NTFS 重解析点(Reparse Point)格式)。如果SMB服务器在共享目录中遇到NTFS符号链接,则会提取REPARSE_DATA_BUFFER结构,然后遵循SMBv2协议中相应规范将该信息返回给客户端。

客户端操作系统负责解析REPARSE_DATA_BUFFER数据,然后再从本地访问。这意味着符号链接只能引用客户端已经能够访问的文件。实际上,虽然默认情况下Windows没有启用符号链接本地解析功能,我还是找到了绕过客户端策略的一种方法,能够本地解析符号链接。目前微软拒绝修复这个绕过问题,如果大家感兴趣可以访问此处了解官方回复。

www.wnhack.com

 
0x01 问题描述
我发现有一点非常有趣,虽然IO_REPARSE_TAG_SYMLINK会在客户端上处理,但如果服务器遇到IO_REPARSE_TAG_MOUNT_POINT重解析点,则会到服务器上去解析。因此,如果我们能在共享目录中设置挂载点(mout point),就可以访问服务器上的任意固定位置(即使该位置没有直接共享出来)。这种场景在横向渗透中非常有用,但问题在于,我们如何在无法本地访问硬盘的情况下添加挂载点?
 
0x02 具体分析
首先我们尝试一下通过UNC路径创建挂载点,可以在CMD中使用MKLINK命令,结果如下所示:

输出信息表示系统不支持在远程服务器上设置挂载点。这一点也能够理解,因为在远程驱动器上设置挂载点可能会导致不可预期后果。我们可以猜测一下,要么该协议不支持设置重解析点,要么做了些限制,只允许符号链接。如果想了解协议具体支持的功能,我们可以查看协议规范。设置重解析点需要向某个文件发送FSCTL_SET_REPARSE_POINT IO控制代码(control code),因此我们可以参考SMB2 IOCTL命令,查看其中是否存在与控制代码有关的信息。 无奈人生安全网
一番搜索后,我们可以看到协议的确支持FSCTL_SET_REPARSE_POINT,并且协议规范中有如下描述(§3.3.5.15.13):
当服务器收到包含包含SMB2头部的请求,并且Command值等于SMB2 IOCTL、CtlCode等于FSCTL_SET_REPARSE_POINT时,那么消息处理过程如下:
根据[MS-FSCC] section 2.3.65规范,如果FSCTL_SET_REPARSE_POINT中的ReparseTag字段不等于IO_REPARSE_TAG_SYMLINK,那么服务器应该验证调用方的确有权限执行这个FSCTL。如果调用方不具备所需的权限,那么服务器必须拒绝该调用,返回STATUS_ACCESS_DENIED错误代码。
根据上述文字,貌似服务器只需要显示检查IO_REPARSE_TAG_SYMLINK即可,如果不匹配该标签,则会执行其他检查操作判断请求是否允许,但并没有提到服务器会设置另一个标签来显式禁止请求。也许系统内置的MKLINK工具不能处理这种场景,换个工具试试?这里我们可以尝试下CreateMountPoint工具(来自于我的symboliclink-testing-tools项目),看能不能成功。
内容来自无奈安全网

CreateMountPoint工具并没有显示之前的错误(“只支持本地NTFS卷”),但返回了拒绝访问错误。这与§3.3.5.15.13中的描述相符,如果隐式检查失败,应当返回拒绝访问错误。当然协议规范中并没有表明需要执行哪些检查,我认为这时候应该派上反编译工具,分析一下SMBv2驱动(srv2.sys)的具体实现。
我使用IDA来查找IO_REPARSE_TAG_SYMLINK对应的立即数(immediate value,这里为0xA000000C),根据分析结果,貌似系统在查找其他标志时,会先会查找这个值。在Windows 10 1809系统的驱动中,我只在Smb2ValidateIoctl找到一处匹配值,相关代码大致如下:
NTSTATUS Smb2ValidateIoctl(SmbIoctlRequest* request) {
  // ...
  switch(request->IoControlCode) {
    case FSCTL_SET_REPARSE_POINT:
      REPARSE_DATA_BUFFER* reparse = (REPARSE_DATA_BUFFER*)request->Buffer;
      // Validate length etc.
      if (reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK &&
          !request->SomeOffset->SomeByteValue) {

copyright 无奈人生


          return STATUS_ACCESS_DENIED;
      }
      // Complete FSCTL_SET_REPARSE_POINT request.
    }
}
上述代码首先从IOCTL请求中提取数据,如果标志不等于IO_REPARSE_TAG_SYMLINK并且请求中某些字节值不等于0,那么就会返回STATUS_ACCESS_DENIED错误。如果想跟踪这个值的来源,有时候会比较棘手,但其实我只需要在IDA中将变量偏移值作为立即数来搜索,通常就能得出结论。这里对应的立即数为0x200,我们可以只搜索MOV指令。最终我在Smb2ExecuteSessionSetupReal中找到了一条指令:MOV [RCX+0x200], AL,这似乎就是我们想要的结果。系统会使用Smb2IsAdmin函数的返回值来设置该变量,而该函数只会检查调用方令牌中是否包含BUILTIN\Administrators组。因此貌似只要我们是主机上的管理员,就可以在远程共享上设置任意重解析点。我们需要验证这一点:
内容来自无奈安全网

[1] [2]  下一页 本文来自无奈人生安全网

。 (责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。