(cherry picked from commit fc08c1f3c5
)
This commit is contained in:
parent
07a9de1247
commit
2327ef9da8
2 changed files with 27 additions and 6 deletions
2
changelogs/fragments/runas-become-system-privileges.yml
Normal file
2
changelogs/fragments/runas-become-system-privileges.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- runas - create a new token when running as ``SYSTEM`` to ensure it has the full privileges assigned to that account
|
|
@ -339,7 +339,11 @@ namespace Ansible.Become
|
||||||
|
|
||||||
// Try and impersonate a SYSTEM token, we need a SYSTEM token to either become a well known service
|
// Try and impersonate a SYSTEM token, we need a SYSTEM token to either become a well known service
|
||||||
// account or have administrative rights on the become access token.
|
// account or have administrative rights on the become access token.
|
||||||
systemToken = GetPrimaryTokenForUser(new SecurityIdentifier("S-1-5-18"), new List<string>() { "SeTcbPrivilege" });
|
// If we ultimately are becoming the SYSTEM account we want the token with the most privileges available.
|
||||||
|
// https://github.com/ansible/ansible/issues/71453
|
||||||
|
bool mostPrivileges = becomeSid == "S-1-5-18";
|
||||||
|
systemToken = GetPrimaryTokenForUser(new SecurityIdentifier("S-1-5-18"),
|
||||||
|
new List<string>() { "SeTcbPrivilege" }, mostPrivileges);
|
||||||
if (systemToken != null)
|
if (systemToken != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -425,7 +429,8 @@ namespace Ansible.Become
|
||||||
return userTokens;
|
return userTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SafeNativeHandle GetPrimaryTokenForUser(SecurityIdentifier sid, List<string> requiredPrivileges = null)
|
private static SafeNativeHandle GetPrimaryTokenForUser(SecurityIdentifier sid,
|
||||||
|
List<string> requiredPrivileges = null, bool mostPrivileges = false)
|
||||||
{
|
{
|
||||||
// According to CreateProcessWithTokenW we require a token with
|
// According to CreateProcessWithTokenW we require a token with
|
||||||
// TOKEN_QUERY, TOKEN_DUPLICATE and TOKEN_ASSIGN_PRIMARY
|
// TOKEN_QUERY, TOKEN_DUPLICATE and TOKEN_ASSIGN_PRIMARY
|
||||||
|
@ -435,6 +440,9 @@ namespace Ansible.Become
|
||||||
TokenAccessLevels.AssignPrimary |
|
TokenAccessLevels.AssignPrimary |
|
||||||
TokenAccessLevels.Impersonate;
|
TokenAccessLevels.Impersonate;
|
||||||
|
|
||||||
|
SafeNativeHandle userToken = null;
|
||||||
|
int privilegeCount = 0;
|
||||||
|
|
||||||
foreach (SafeNativeHandle hToken in TokenUtil.EnumerateUserTokens(sid, dwAccess))
|
foreach (SafeNativeHandle hToken in TokenUtil.EnumerateUserTokens(sid, dwAccess))
|
||||||
{
|
{
|
||||||
// Filter out any Network logon tokens, using become with that is useless when S4U
|
// Filter out any Network logon tokens, using become with that is useless when S4U
|
||||||
|
@ -443,10 +451,15 @@ namespace Ansible.Become
|
||||||
if (tokenLogonType == NativeHelpers.SECURITY_LOGON_TYPE.Network)
|
if (tokenLogonType == NativeHelpers.SECURITY_LOGON_TYPE.Network)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
List<string> actualPrivileges = TokenUtil.GetTokenPrivileges(hToken).Select(x => x.Name).ToList();
|
||||||
|
|
||||||
|
// If the token has less or the same number of privileges than the current token, skip it.
|
||||||
|
if (mostPrivileges && privilegeCount >= actualPrivileges.Count)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Check that the required privileges are on the token
|
// Check that the required privileges are on the token
|
||||||
if (requiredPrivileges != null)
|
if (requiredPrivileges != null)
|
||||||
{
|
{
|
||||||
List<string> actualPrivileges = TokenUtil.GetTokenPrivileges(hToken).Select(x => x.Name).ToList();
|
|
||||||
int missing = requiredPrivileges.Where(x => !actualPrivileges.Contains(x)).Count();
|
int missing = requiredPrivileges.Where(x => !actualPrivileges.Contains(x)).Count();
|
||||||
if (missing > 0)
|
if (missing > 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -455,16 +468,22 @@ namespace Ansible.Become
|
||||||
// Duplicate the token to convert it to a primary token with the access level required.
|
// Duplicate the token to convert it to a primary token with the access level required.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return TokenUtil.DuplicateToken(hToken, TokenAccessLevels.MaximumAllowed, SecurityImpersonationLevel.Anonymous,
|
userToken = TokenUtil.DuplicateToken(hToken, TokenAccessLevels.MaximumAllowed,
|
||||||
TokenType.Primary);
|
SecurityImpersonationLevel.Anonymous, TokenType.Primary);
|
||||||
|
privilegeCount = actualPrivileges.Count;
|
||||||
}
|
}
|
||||||
catch (Process.Win32Exception)
|
catch (Process.Win32Exception)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we don't care about getting the token with the most privileges, escape the loop as we already
|
||||||
|
// have a token.
|
||||||
|
if (!mostPrivileges)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return userToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SafeNativeHandle GetS4UTokenForUser(SecurityIdentifier sid, LogonType logonType)
|
private static SafeNativeHandle GetS4UTokenForUser(SecurityIdentifier sid, LogonType logonType)
|
||||||
|
|
Loading…
Reference in a new issue