EventLog.SourceExists 在 Windows Server 2019 上失败

9
我正在使用Windows Server 2019和.Net Framework 4.7.2测试一个ASP.NET应用程序。IIS应用程序被设置为模拟不具备管理特权的用户。 应用程序调用EventLog.SourceExists来检查事件日志源是否存在,然后再尝试创建新的源。我了解到这种方法需要管理员权限才能搜索现有的事件日志以查找源[1]。另一种实现方法是显式地给予我的用户对注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog及其所有子项的读取权限。 在Windows Server 2019之前的版本(2016、2012 R2、2018)中都起作用。 在测试时,这个应用程序在Windows Server 2019上失败,并出现异常。 当运行procmon时,我看到尝试打开“State”事件日志的注册表键时出现访问被拒绝。 “State”注册表键在Windows Server 2019中似乎是新的。它也受到保护——它由系统拥有,管理员只能进行只读操作。当我尝试授予我的用户读取权限时,我会收到访问被拒绝的消息。因此,我的非管理员用户运行的应用程序在调用EventLog.SourceExists时将失败并显示“Inaccessible logs: State”。 我意识到我可以取得“State”注册表键的所有权并添加我的用户。然而,在执行此操作之前,我想先了解一下是否有人了解Windows Server 2019中这个新的注册表键(事件日志)。 谢谢。[1]https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.eventlog.sourceexists?view=netframework-4.7.2
1个回答

8

问题根源:

在HKLM\SYSTEM\CCS\Services\EventLog树中的“State”蜂巢拥有奇怪的安全配置。因此,任何尝试枚举事件源的应用程序最终都会遇到“访问被拒绝”异常并退出。

默认权限如下:

  • 系统(完全控制)
  • EventLog(完全控制)
  • 管理员(读取键)

它们不会像“Security”蜂巢那样继承。

相比之下,第二个新蜂巢命名为“Parameters”会继承权限。

通常情况下,应用程序会像这样进行枚举:

[System.Diagnostics.EventLog]::SourceExists("Source Name")

即使你尝试使用PowerShell枚举,你也会遇到“访问被拒绝”的错误。

PS C:\> (gci -Recurse HKLM:\System\CurrentControlSet\services\eventlog).Name

虽然我不知道“State” hive确切的作用是什么(微软没有详细说明),但我找到了解决方法。
解决方案:
1. 交互式解决方案,使用REGEDIT: a)使用“PSexec”以SYSTEM身份运行REGEDIT; b)使用REGEDIT的UI,为IIS_IUSRS或任何您的服务或IIS应用程序池运行的任意帐户授予“State” hive的读取权限。
2. 脚本方式,使用PowerShell: a)使用“PSexec”以SYSTEM身份运行PowerShell; b)使用“Get-ACL”/“Set-ACL” cmdlets,为IIS_IUSRS或任何您的服务或IIS应用程序池运行的任意帐户授予“State” hive的读取权限。
最好使用PSexec以SYSTEM用户身份运行应用程序,可以从Microsoft SysInternals网站免费下载(https://learn.microsoft.com/en-us/sysinternals/downloads/psexec)。
PS C:\> PSexec.exe -accepteula -d -i -s powershell.exe

这将打开一个以NT AUTHORITY\System身份运行的PowerShell窗口。 从这里,可以使用REGEDIT更改您的服务用户帐户或IIS应用程序池用户在“State”注册表项上的权限。或者,使用Get-ACL / Set-ACL cmdlets以脚本方式执行相同操作。只需要“读取键”权限即可,无需“完全控制”。

PS C:\> $hive = HKLM:\System\CurrentControlSet\services\eventlog\state; $acl = Get-ACL $hive; $rule = New-Object System.Security.AccessControl.RegistryAccessRule ("IIS_IUSRS","ReadKey","ContainerInherit","None","Allow"); $acl.SetAccessRule($rule); $acl |Set-ACL $hive

您的应用程序现在应该能够枚举运行在其上的计算机上的所有事件源,并创建一个事件源(如果枚举未找到它)。


谢谢Franz!这对我来说是解决方案,解释得非常好。 - Ryan Sampson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接