READ_CONTROL 的 CreateFileW 失败并显示 "Access is denied" 尽管是文件的所有者
CreateFileW for READ_CONTROL fails with "Access is denied" despite being owner of the file
在Windows上,即使自由ACL(DACL)为空,即没有人对该文件有权限,文件所有者也可以读写DACL(READ_CONTROL
和WRITE_DAC
访问)。
所以我尝试执行以下操作:
- 在文件上设置空 DACL
- 获取
READ_CONTROL
的文件句柄
- 使用
GetSecurityInfo
和句柄 获取安全描述符
- 检查 DACL 是否确实为空
但是,使用 CreateFileW
获取句柄失败并出现 Access is denied
错误。令人惊讶的是,GetFileSecurity
,相当于文件的 GetSecurityInfo
,工作正常。
根据 documentation,GetFileSecurity
需要 READ_CONTROL
访问权限。
为什么 CreateFileW
在下面的例子中失败了?
import sys
import win32security
import win32con
import win32file
import ntsecuritycon
import os
path = sys.argv[1]
with open(path, "w"):
pass # I am the owner of the file
print("Set empty ACL")
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = win32security.ACL()
sd.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)
try:
print("Ensure that ACL is empty with GetFileSecurity")
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()
assert 0 == dacl.GetAceCount()
print("Try to ensure that ACL is empty using handle")
handle = win32file.CreateFileW(
path,
ntsecuritycon.READ_CONTROL,
0,
None, # security attributes
win32con.OPEN_EXISTING,
0,
None,
)
sd = win32security.GetSecurityInfo(handle, win32security.SE_FILE_OBJECT, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()
assert 0 == dacl.GetAceCount()
except Exception as e:
print("FAILURE:", e)
finally:
print("Restore inherited ACEs before removing file")
dacl = win32security.ACL()
win32security.SetNamedSecurityInfo(
path,
win32security.SE_FILE_OBJECT,
win32security.DACL_SECURITY_INFORMATION,
None,
None,
dacl,
None
)
os.unlink(path)
输出:
> python acl-test.py file
Set empty ACL
Ensure that ACL is empty with GetFileSecurity
Try to ensure that ACL is empty using handle
FAILURE: (5, 'CreateFileW', 'Access is denied.')
Restore inherited ACEs before removing file
CreateFileW
internally calls NtCreateFile
,DesiredAccess
参数作为 dwDesiredAccess | FILE_READ_ATTRIBUTES | SYNCHRONIZE
传递。因此,如果您将 dwDesiredAccess
作为 READ_CONTROL
传递,那么它实际上会尝试使用 READ_CONTROL | FILE_READ_ATTRIBUTES | SYNCHRONIZE
访问权限打开文件。如果调用者对父文件夹具有 FILE_LIST_DIRECTORY
访问权限,则文件系统隐式授予 FILE_READ_ATTRIBUTES
访问权限。但是,如果文件的 DACL 为空,将不会授予 SYNCHRONIZE
访问权限。
这里的一个解决方案是使用 NtOpenFile
或 NtCreateFile
来控制请求的确切访问权限。
在Windows上,即使自由ACL(DACL)为空,即没有人对该文件有权限,文件所有者也可以读写DACL(READ_CONTROL
和WRITE_DAC
访问)。
所以我尝试执行以下操作:
- 在文件上设置空 DACL
- 获取
READ_CONTROL
的文件句柄
- 使用
GetSecurityInfo
和句柄 获取安全描述符
- 检查 DACL 是否确实为空
但是,使用 CreateFileW
获取句柄失败并出现 Access is denied
错误。令人惊讶的是,GetFileSecurity
,相当于文件的 GetSecurityInfo
,工作正常。
根据 documentation,GetFileSecurity
需要 READ_CONTROL
访问权限。
为什么 CreateFileW
在下面的例子中失败了?
import sys
import win32security
import win32con
import win32file
import ntsecuritycon
import os
path = sys.argv[1]
with open(path, "w"):
pass # I am the owner of the file
print("Set empty ACL")
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = win32security.ACL()
sd.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)
try:
print("Ensure that ACL is empty with GetFileSecurity")
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()
assert 0 == dacl.GetAceCount()
print("Try to ensure that ACL is empty using handle")
handle = win32file.CreateFileW(
path,
ntsecuritycon.READ_CONTROL,
0,
None, # security attributes
win32con.OPEN_EXISTING,
0,
None,
)
sd = win32security.GetSecurityInfo(handle, win32security.SE_FILE_OBJECT, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()
assert 0 == dacl.GetAceCount()
except Exception as e:
print("FAILURE:", e)
finally:
print("Restore inherited ACEs before removing file")
dacl = win32security.ACL()
win32security.SetNamedSecurityInfo(
path,
win32security.SE_FILE_OBJECT,
win32security.DACL_SECURITY_INFORMATION,
None,
None,
dacl,
None
)
os.unlink(path)
输出:
> python acl-test.py file
Set empty ACL
Ensure that ACL is empty with GetFileSecurity
Try to ensure that ACL is empty using handle
FAILURE: (5, 'CreateFileW', 'Access is denied.')
Restore inherited ACEs before removing file
CreateFileW
internally calls NtCreateFile
,DesiredAccess
参数作为 dwDesiredAccess | FILE_READ_ATTRIBUTES | SYNCHRONIZE
传递。因此,如果您将 dwDesiredAccess
作为 READ_CONTROL
传递,那么它实际上会尝试使用 READ_CONTROL | FILE_READ_ATTRIBUTES | SYNCHRONIZE
访问权限打开文件。如果调用者对父文件夹具有 FILE_LIST_DIRECTORY
访问权限,则文件系统隐式授予 FILE_READ_ATTRIBUTES
访问权限。但是,如果文件的 DACL 为空,将不会授予 SYNCHRONIZE
访问权限。
这里的一个解决方案是使用 NtOpenFile
或 NtCreateFile
来控制请求的确切访问权限。