Compare commits

..

3 Commits

3 changed files with 127 additions and 599 deletions

View File

@@ -0,0 +1,126 @@
# Title: System Information - CVE_2025_38236
# ID: SY_CVE_2025_38236
# Author: HT Bot
# Last Update: 17-12-2025
# Description: Detect Linux kernels exposed to CVE-2025-38236 (AF_UNIX MSG_OOB UAF) that allow local privilege escalation:
# - Vulnerable scope:
# * Linux kernels 6.9+ before commit 32ca245464e1479bfea8592b9db227fdc1641705
# * AF_UNIX stream sockets with MSG_OOB enabled (CONFIG_AF_UNIX_OOB or implicit support)
# - Exploitation summary:
# * send/recv MSG_OOB pattern leaves zero-length SKBs in the receive queue
# * manage_oob() skips cleanup, freeing the OOB SKB while u->oob_skb still points to it
# * Subsequent recv(MSG_OOB) dereferences the dangling pointer → kernel UAF → LPE
# - Mitigations:
# * Update to a kernel that includes commit 32ca245464e1479bfea8592b9db227fdc1641705 (or newer)
# * Disable CONFIG_AF_UNIX_OOB or block MSG_OOB in sandboxed processes
# * Backport vendor fixes or follow Chrome's MSG_OOB filtering approach
# License: GNU GPL
# Version: 1.0
# Functions Used: print_2title, print_info
# Global Variables: $MACPEAS, $SED_RED_YELLOW, $SED_GREEN, $E
# Initial Functions:
# Generated Global Variables: $cve38236_kernel_release, $cve38236_kernel_version, $cve38236_oob_line, $cve38236_unix_line, $cve38236_oob_status, $CVE38236_CONFIG_SOURCE, $cve38236_conf_file, $cve38236_config_key, $cve38236_release, $cve38236_cfg, $cve38236_config_line
# Fat linpeas: 0
# Small linpeas: 1
_cve38236_version_to_number() {
if [ -z "$1" ]; then
printf '0\n'
return
fi
echo "$1" | awk -F. '{
major=$1+0
if (NF>=2) minor=$2+0; else minor=0
if (NF>=3) patch=$3+0; else patch=0
printf "%d\n", (major*1000000)+(minor*1000)+patch
}'
}
_cve38236_version_ge() {
local v1 v2
v1=$(_cve38236_version_to_number "$1")
v2=$(_cve38236_version_to_number "$2")
[ "$v1" -ge "$v2" ]
}
_cve38236_cat_config_file() {
local cve38236_conf_file="$1"
if [ -z "$cve38236_conf_file" ] || ! [ -r "$cve38236_conf_file" ]; then
return 1
fi
if printf '%s' "$cve38236_conf_file" | grep -q '\\.gz$'; then
if command -v zcat >/dev/null 2>&1; then
zcat "$cve38236_conf_file" 2>/dev/null
elif command -v gzip >/dev/null 2>&1; then
gzip -dc "$cve38236_conf_file" 2>/dev/null
else
cat "$cve38236_conf_file" 2>/dev/null
fi
else
cat "$cve38236_conf_file" 2>/dev/null
fi
}
_cve38236_read_config_line() {
local cve38236_config_key="$1"
local cve38236_release cve38236_config_line cve38236_cfg
cve38236_release="$(uname -r 2>/dev/null)"
for cve38236_cfg in /proc/config.gz \
"/boot/config-${cve38236_release}" \
"/usr/lib/modules/${cve38236_release}/build/.config" \
"/lib/modules/${cve38236_release}/build/.config"; do
if [ -r "$cve38236_cfg" ]; then
cve38236_config_line=$(_cve38236_cat_config_file "$cve38236_cfg" | grep -E "^(${cve38236_config_key}=|# ${cve38236_config_key} is not set)" | head -n1)
if [ -n "$cve38236_config_line" ]; then
CVE38236_CONFIG_SOURCE="$cve38236_cfg"
printf '%s\n' "$cve38236_config_line"
return 0
fi
fi
done
return 1
}
if [ ! "$MACPEAS" ]; then
cve38236_kernel_release="$(uname -r 2>/dev/null)"
cve38236_kernel_version="$(printf '%s' "$cve38236_kernel_release" | sed 's/[^0-9.].*//')"
if [ -n "$cve38236_kernel_version" ] && _cve38236_version_ge "$cve38236_kernel_version" "6.9.0"; then
print_2title "CVE-2025-38236 - AF_UNIX MSG_OOB UAF"
cve38236_oob_line=$(_cve38236_read_config_line "CONFIG_AF_UNIX_OOB")
cve38236_oob_status="unknown"
if printf '%s' "$cve38236_oob_line" | grep -q '=y\|=m'; then
cve38236_oob_status="enabled"
elif printf '%s' "$cve38236_oob_line" | grep -q 'not set'; then
cve38236_oob_status="disabled"
fi
if [ "$cve38236_oob_status" = "unknown" ]; then
cve38236_unix_line=$(_cve38236_read_config_line "CONFIG_UNIX")
if printf '%s' "$cve38236_unix_line" | grep -q 'not set'; then
cve38236_oob_status="disabled"
elif printf '%s' "$cve38236_unix_line" | grep -q '=y\|=m'; then
cve38236_oob_status="enabled"
fi
fi
if [ "$cve38236_oob_status" = "disabled" ]; then
printf 'Kernel %s >= 6.9 but MSG_OOB support is disabled (%s).\n' "$cve38236_kernel_release" "${cve38236_oob_line:-CONFIG_AF_UNIX disabled}" | sed -${E} "s,.*,${SED_GREEN},"
print_info "CVE-2025-38236 requires AF_UNIX MSG_OOB; disabling CONFIG_AF_UNIX_OOB/CONFIG_UNIX mitigates it."
else
printf 'Kernel %s (parsed %s) may be vulnerable to CVE-2025-38236 - AF_UNIX MSG_OOB UAF.\n' "$cve38236_kernel_release" "$cve38236_kernel_version" | sed -${E} "s,.*,${SED_RED_YELLOW},"
[ -n "$cve38236_oob_line" ] && print_info "Config hint: $cve38236_oob_line"
if [ "$cve38236_oob_status" = "unknown" ]; then
print_info "Could not read CONFIG_AF_UNIX_OOB directly; AF_UNIX appears enabled, so assume MSG_OOB reachable."
fi
print_info "Exploit chain: crafted MSG_OOB send/recv frees the OOB SKB while u->oob_skb still points to it, enabling kernel UAF → arbitrary read/write primitives (Project Zero 2025/08)."
print_info "Mitigations: update to a kernel containing commit 32ca245464e1479bfea8592b9db227fdc1641705, disable CONFIG_AF_UNIX_OOB, or filter MSG_OOB in sandbox policies."
print_info "Heuristic detection: based solely on uname -r and kernel config; vendor kernels with backported fixes should be verified manually."
fi
echo ""
fi
fi

View File

@@ -86,7 +86,6 @@ The tool is based on **[SeatBelt](https://github.com/GhostPack/Seatbelt)**.
- Active Directory quick checks now include:
- gMSA readable managed passwords: enumerate msDS-GroupManagedServiceAccount objects and report those where the current user/group is allowed to retrieve the managed password (PrincipalsAllowedToRetrieveManagedPassword).
- AD object control surfaces: parse ACLs for high-value objects plus a sampled set of users/groups/computers and flag when the current security principal already has GenericAll/GenericWrite/WriteDacl/WriteOwner or attribute-specific rights (SPN, UAC, msDS-AllowedToActOnBehalfOfOtherIdentity, sidHistory, member, unicodePwd, replication) that can be abused for password resets, Kerberoasting, delegation/RBCD, DCSync, or stealth persistence.
- AD CS (ESC4) hygiene: enumerate published certificate templates and highlight templates where the current user/group has dangerous control rights (GenericAll/WriteDacl/WriteOwner/WriteProperty/ExtendedRight) that could allow template abuse (e.g., ESC4 -> ESC1).
These checks are lightweight, read-only, and only run when the host is domain-joined.

View File

@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using winPEAS.Helpers;
using winPEAS.Helpers.Registry;
using winPEAS.Info.FilesInfo.Certificates;
namespace winPEAS.Checks
{
@@ -20,16 +19,10 @@ namespace winPEAS.Checks
new List<Action>
{
PrintGmsaReadableByCurrentPrincipal,
PrintAdObjectControlPaths,
PrintAdcsMisconfigurations
}.ForEach(action => CheckRunner.Run(action, isDebug));
}
private const int SampleObjectLimit = 120;
private const int MaxFindingsToPrint = 40;
private static readonly Dictionary<Guid, string> GuidNameCache = new Dictionary<Guid, string>();
private static readonly object GuidCacheLock = new object();
private static HashSet<string> GetCurrentSidSet()
{
var sids = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
@@ -72,596 +65,6 @@ namespace winPEAS.Checks
: null;
}
// Highlight objects where the current principal already has useful write/control rights
private void PrintAdObjectControlPaths()
{
try
{
Beaprint.MainPrint("AD object control surfaces");
Beaprint.LinkPrint(
"https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/index.html#acl-abuse",
"Look for objects where you have GenericAll/GenericWrite/attribute rights for ACL abuse (password reset, SPN/UAC/RBCD, sidHistory, delegation, DCSync).");
if (!Checks.IsPartOfDomain)
{
Beaprint.GrayPrint(" [-] Host is not domain-joined. Skipping.");
return;
}
var defaultNC = GetRootDseProp("defaultNamingContext");
var schemaNC = GetRootDseProp("schemaNamingContext");
var configNC = GetRootDseProp("configurationNamingContext");
if (string.IsNullOrEmpty(defaultNC))
{
Beaprint.GrayPrint(" [-] Could not resolve defaultNamingContext.");
return;
}
var sidSet = GetCurrentSidSet();
var processedDns = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var findings = new List<AdObjectFinding>();
foreach (var target in EnumerateHighValueTargets(defaultNC))
{
var finding = AnalyzeDirectoryObject(target.DistinguishedName, target.Label, sidSet, schemaNC, configNC);
if (finding == null)
{
continue;
}
if (processedDns.Add(finding.DistinguishedName))
{
findings.Add(finding);
}
}
try
{
using (var baseDe = new DirectoryEntry("LDAP://" + defaultNC))
using (var ds = new DirectorySearcher(baseDe))
{
ds.PageSize = 200;
ds.SizeLimit = SampleObjectLimit;
ds.SearchScope = SearchScope.Subtree;
ds.SecurityMasks = SecurityMasks.Dacl;
ds.Filter = "(|(objectClass=user)(objectClass=group)(objectClass=computer))";
ds.PropertiesToLoad.Add("distinguishedName");
ds.PropertiesToLoad.Add("sAMAccountName");
ds.PropertiesToLoad.Add("name");
using (var results = ds.FindAll())
{
foreach (SearchResult r in results)
{
var dn = GetProp(r, "distinguishedName");
if (string.IsNullOrEmpty(dn) || processedDns.Contains(dn))
{
continue;
}
var label = GetProp(r, "sAMAccountName") ?? GetProp(r, "name") ?? dn;
var finding = AnalyzeDirectoryObject(dn, label, sidSet, schemaNC, configNC);
if (finding != null && processedDns.Add(finding.DistinguishedName))
{
findings.Add(finding);
}
}
}
}
}
catch (Exception ex)
{
Beaprint.GrayPrint(" [!] LDAP sampling failed: " + ex.Message);
}
if (findings.Count == 0)
{
Beaprint.GrayPrint(" [-] No impactful ACLs detected for the current principal (sampled set).");
return;
}
var ordered = findings
.OrderByDescending(f => f.MaxScore)
.ThenBy(f => f.DisplayName, StringComparer.OrdinalIgnoreCase)
.ToList();
var truncated = ordered.Count > MaxFindingsToPrint;
if (truncated)
{
ordered = ordered.Take(MaxFindingsToPrint).ToList();
}
Beaprint.GrayPrint($" [+] Found {findings.Count} object(s) where your principal has abuse-friendly rights:");
foreach (var finding in ordered)
{
Beaprint.BadPrint($" -> {finding.DisplayName} ({finding.ClassName})");
Beaprint.GrayPrint(" DN: " + finding.DistinguishedName);
foreach (var impact in finding.Impacts.OrderByDescending(i => i.Score))
{
Beaprint.GrayPrint($" * {impact.Impact}: {impact.Detail}");
}
}
if (truncated)
{
Beaprint.GrayPrint($" [!] Additional {findings.Count - MaxFindingsToPrint} object(s) not shown (enable domain mode or run winPEAS with more time to enumerate all objects).");
}
}
catch (Exception ex)
{
Beaprint.PrintException(ex.Message);
}
}
private static IEnumerable<(string Label, string DistinguishedName)> EnumerateHighValueTargets(string defaultNC)
{
return new List<(string, string)>
{
("Domain Root", defaultNC),
("AdminSDHolder", $"CN=AdminSDHolder,CN=System,{defaultNC}"),
("Domain Controllers OU", $"OU=Domain Controllers,{defaultNC}"),
("Domain Controllers group", $"CN=Domain Controllers,CN=Users,{defaultNC}"),
("Domain Admins", $"CN=Domain Admins,CN=Users,{defaultNC}"),
("Enterprise Admins", $"CN=Enterprise Admins,CN=Users,{defaultNC}"),
("Schema Admins", $"CN=Schema Admins,CN=Users,{defaultNC}"),
("Administrators", $"CN=Administrators,CN=Builtin,{defaultNC}"),
("Account Operators", $"CN=Account Operators,CN=Builtin,{defaultNC}"),
("Backup Operators", $"CN=Backup Operators,CN=Builtin,{defaultNC}"),
("Group Policy Creator Owners", $"CN=Group Policy Creator Owners,CN=Users,{defaultNC}"),
("krbtgt", $"CN=krbtgt,CN=Users,{defaultNC}")
};
}
private static AdObjectFinding AnalyzeDirectoryObject(string dn, string label, HashSet<string> sidSet, string schemaNC, string configNC)
{
if (string.IsNullOrEmpty(dn))
{
return null;
}
try
{
using (var entry = new DirectoryEntry("LDAP://" + dn))
{
entry.Options.SecurityMasks = SecurityMasks.Owner | SecurityMasks.Dacl;
entry.RefreshCache();
return EvaluateSecurity(entry, label ?? dn, sidSet, schemaNC, configNC);
}
}
catch (Exception)
{
return null;
}
}
private static AdObjectFinding EvaluateSecurity(DirectoryEntry entry, string label, HashSet<string> sidSet, string schemaNC, string configNC)
{
ActiveDirectorySecurity security;
try
{
security = entry.ObjectSecurity;
}
catch
{
return null;
}
if (security == null)
{
return null;
}
var finding = new AdObjectFinding
{
DisplayName = label ?? entry.Name,
DistinguishedName = entry.Properties?["distinguishedName"]?.Value as string ?? entry.Path,
ClassName = entry.SchemaClassName ?? "object"
};
var seenImpacts = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
try
{
var ownerSid = security.GetOwner(typeof(SecurityIdentifier)) as SecurityIdentifier;
if (ownerSid != null && sidSet.Contains(ownerSid.Value))
{
var impact = new AdAccessImpact
{
Impact = "Object owner",
Detail = "You own this object and can rewrite its ACL to grant full control.",
Score = 3
};
finding.Impacts.Add(impact);
seenImpacts.Add(impact.Impact);
}
}
catch
{
// ignore owner lookup issues
}
AuthorizationRuleCollection rules;
try
{
rules = security.GetAccessRules(true, true, typeof(SecurityIdentifier));
}
catch
{
return finding.Impacts.Count > 0 ? finding : null;
}
foreach (ActiveDirectoryAccessRule rule in rules)
{
if (rule == null || rule.AccessControlType != AccessControlType.Allow)
{
continue;
}
if (!(rule.IdentityReference is SecurityIdentifier sid))
{
continue;
}
if (!sidSet.Contains(sid.Value))
{
continue;
}
foreach (var impact in MapRuleToImpacts(rule, schemaNC, configNC))
{
if (impact == null)
{
continue;
}
var key = impact.Impact + "|" + impact.Detail;
if (seenImpacts.Add(key))
{
finding.Impacts.Add(impact);
}
}
}
return finding.Impacts.Count > 0 ? finding : null;
}
private static IEnumerable<AdAccessImpact> MapRuleToImpacts(ActiveDirectoryAccessRule rule, string schemaNC, string configNC)
{
var impacts = new List<AdAccessImpact>();
var rights = rule.ActiveDirectoryRights;
if ((rights & ActiveDirectoryRights.GenericAll) != 0)
{
impacts.Add(new AdAccessImpact
{
Impact = "GenericAll",
Detail = "Full control -> reset password, add group members, edit SPNs/UAC, change ACLs.",
Score = 5
});
return impacts;
}
if ((rights & ActiveDirectoryRights.GenericWrite) != 0)
{
impacts.Add(new AdAccessImpact
{
Impact = "GenericWrite",
Detail = "Can modify most attributes (logon scripts, SPNs, UAC, etc.).",
Score = 4
});
}
if ((rights & ActiveDirectoryRights.WriteDacl) != 0)
{
impacts.Add(new AdAccessImpact
{
Impact = "WriteDACL",
Detail = "Can edit the ACL to grant yourself additional rights/persistence.",
Score = 4
});
}
if ((rights & ActiveDirectoryRights.WriteOwner) != 0)
{
impacts.Add(new AdAccessImpact
{
Impact = "WriteOwner",
Detail = "Can take ownership and then modify the DACL.",
Score = 3
});
}
if ((rights & ActiveDirectoryRights.CreateChild) != 0)
{
impacts.Add(new AdAccessImpact
{
Impact = "CreateChild",
Detail = "Can create new users/computers/groups under this container (great for planting attack principals).",
Score = 3
});
}
if ((rights & ActiveDirectoryRights.ExtendedRight) != 0)
{
var extImpact = MapExtendedRightImpact(rule.ObjectType, schemaNC, configNC);
if (extImpact != null)
{
impacts.Add(extImpact);
}
}
if ((rights & ActiveDirectoryRights.WriteProperty) != 0)
{
var attrImpact = MapAttributeWriteImpact(rule.ObjectType, schemaNC, configNC, false);
if (attrImpact != null)
{
impacts.Add(attrImpact);
}
}
if ((rights & ActiveDirectoryRights.Self) != 0)
{
var validatedImpact = MapAttributeWriteImpact(rule.ObjectType, schemaNC, configNC, true);
if (validatedImpact != null)
{
impacts.Add(validatedImpact);
}
}
return impacts;
}
private static AdAccessImpact MapExtendedRightImpact(Guid objectType, string schemaNC, string configNC)
{
if (objectType == Guid.Empty)
{
return null;
}
var name = GetGuidFriendlyName(objectType, schemaNC, configNC)?.ToLowerInvariant();
if (string.IsNullOrEmpty(name))
{
return null;
}
if (name.Contains("reset password") || name.Contains("user-force-change-password"))
{
return new AdAccessImpact
{
Impact = "ResetPassword right",
Detail = "Can reset the target account password without knowing the current value.",
Score = 5
};
}
if (name.Contains("replicating directory changes"))
{
return new AdAccessImpact
{
Impact = "Replication (DCSync)",
Detail = "Has replication rights (part of DCSync privilege to dump NTDS hashes).",
Score = name.Contains("filtered") ? 5 : 4
};
}
return null;
}
private static AdAccessImpact MapAttributeWriteImpact(Guid objectType, string schemaNC, string configNC, bool validatedWrite)
{
if (objectType == Guid.Empty)
{
return new AdAccessImpact
{
Impact = validatedWrite ? "Validated write (broad)" : "WriteProperty (broad)",
Detail = "ACE applies to most attributes. Consider SPN/UAC/sidHistory abuse paths.",
Score = 3
};
}
var attributeName = GetGuidFriendlyName(objectType, schemaNC, configNC);
if (string.IsNullOrEmpty(attributeName))
{
return null;
}
var lower = attributeName.ToLowerInvariant();
if (lower.Contains("member"))
{
return new AdAccessImpact
{
Impact = "Group membership control",
Detail = "Can edit the 'member' attribute -> add principals to this group.",
Score = 5
};
}
if (lower.Contains("serviceprincipalname") || lower.Contains("validated-spn"))
{
return new AdAccessImpact
{
Impact = "SPN control",
Detail = "Can set servicePrincipalName -> Kerberoast or constrained delegation abuse.",
Score = 4
};
}
if (lower.Contains("useraccountcontrol"))
{
return new AdAccessImpact
{
Impact = "UAC control",
Detail = "Can toggle UserAccountControl bits (AS-REP roastable, delegation, unconstrained).",
Score = 4
};
}
if (lower.Contains("msds-allowedtoactonbehalfofotheridentity"))
{
return new AdAccessImpact
{
Impact = "RBCD control",
Detail = "Can edit msDS-AllowedToActOnBehalfOfOtherIdentity -> configure Resource-Based Constrained Delegation.",
Score = 5
};
}
if (lower.Contains("msds-allowedtodelegateto"))
{
return new AdAccessImpact
{
Impact = "Delegation target control",
Detail = "Can edit msDS-AllowedToDelegateTo -> establish constrained delegation paths.",
Score = 4
};
}
if (lower.Contains("sidhistory"))
{
return new AdAccessImpact
{
Impact = "sidHistory control",
Detail = "Can add privileged SIDs into sidHistory for stealth escalation/persistence.",
Score = 4
};
}
if (lower.Contains("unicodepwd") || lower.Contains("userpassword"))
{
return new AdAccessImpact
{
Impact = "Password write",
Detail = "Can directly set unicodePwd/userPassword -> immediate account takeover.",
Score = 5
};
}
return null;
}
private static string GetGuidFriendlyName(Guid guid, string schemaNC, string configNC)
{
if (guid == Guid.Empty)
{
return null;
}
lock (GuidCacheLock)
{
if (GuidNameCache.TryGetValue(guid, out var cached))
{
return cached;
}
}
string resolved = null;
if (!string.IsNullOrEmpty(schemaNC))
{
resolved = LookupGuidInSchema(guid, schemaNC);
}
if (resolved == null && !string.IsNullOrEmpty(configNC))
{
resolved = LookupGuidInExtendedRights(guid, configNC);
}
if (string.IsNullOrEmpty(resolved))
{
resolved = guid.ToString();
}
lock (GuidCacheLock)
{
if (!GuidNameCache.ContainsKey(guid))
{
GuidNameCache[guid] = resolved;
}
return GuidNameCache[guid];
}
}
private static string LookupGuidInSchema(Guid guid, string schemaNC)
{
try
{
using (var schema = new DirectoryEntry("LDAP://" + schemaNC))
using (var searcher = new DirectorySearcher(schema))
{
searcher.Filter = $"(schemaIDGUID={GuidToLdapFilter(guid)})";
searcher.PropertiesToLoad.Add("lDAPDisplayName");
searcher.PropertiesToLoad.Add("name");
var result = searcher.FindOne();
if (result != null)
{
return GetProp(result, "lDAPDisplayName") ?? GetProp(result, "name");
}
}
}
catch
{
// ignore schema lookup errors
}
return null;
}
private static string LookupGuidInExtendedRights(Guid guid, string configNC)
{
try
{
var extendedRightsDn = $"CN=Extended-Rights,{configNC}";
using (var rights = new DirectoryEntry("LDAP://" + extendedRightsDn))
using (var searcher = new DirectorySearcher(rights))
{
searcher.Filter = $"(rightsGuid={guid})";
searcher.PropertiesToLoad.Add("displayName");
searcher.PropertiesToLoad.Add("name");
var result = searcher.FindOne();
if (result != null)
{
return GetProp(result, "displayName") ?? GetProp(result, "name");
}
}
}
catch
{
// ignore extended rights lookup issues
}
return null;
}
private static string GuidToLdapFilter(Guid guid)
{
var bytes = guid.ToByteArray();
var sb = new StringBuilder();
foreach (var b in bytes)
{
sb.Append($"\\{b:X2}");
}
return sb.ToString();
}
private class AdObjectFinding
{
public string DisplayName { get; set; }
public string DistinguishedName { get; set; }
public string ClassName { get; set; }
public List<AdAccessImpact> Impacts { get; } = new List<AdAccessImpact>();
public int MaxScore => Impacts.Count == 0 ? 0 : Impacts.Max(i => i.Score);
}
private class AdAccessImpact
{
public string Impact { get; set; }
public string Detail { get; set; }
public int Score { get; set; }
}
// Detect gMSA objects where the current principal (or one of its groups) can retrieve the managed password
private void PrintGmsaReadableByCurrentPrincipal()
{