AFP548

Using host principals to secure connections to 3rd party KDCs

If you are in an environment where you are integrating Mac OS X with a 3rd party KDCs, you already know about builtin:krb5authnoverify addition to your /etc/authorization.  But did you know that you can use the builtin:krb5authenticate option to provide better security by assuring that your KDC is not being spoofed?  Are you safe from the "Zanarotti attack"?  Read on to find out how to get it set up and running.

Getting Mac OS X set up to use a 3rd party KDC is relatively straightforward, and is covered in some detail at http://docs.info.apple.com/article.html?artnum=107154.  However, let's dig in a bit deeper and see what those changes to your /etc/authorization are actually doing, and how to provide TGT verification.  

 First, let's review how to set Mac OS X up for kerberos authentication with a 3rd party KDC.

 1.  Craft a valid /Library/Preference/edu.mit.Kerberos file.  This is the same file that is normally found in /etc/krb5.conf file on other *nixs in your network, so grab a copy and install it on the client.  It specifies your kerberos realm, where the KDC is, and other client related options.  You can now do a "kinit" in terminal and should be able to authenticate as a kerberos user.  This helps to verify that you got the edu.mit.Kerberos file correct.

 2.  Set up the login window to use your 3rd party KDC.  In order for login window to use your 3rd party KDC, you'll need to modify /etc/authorization.   /etc/authorization  is the file that the Security framework uses to figure out who can access what system resources.  For instance, when you click on the lock in the Accounts pane of System Preferences, the /etc/authorization file specifies that "system.preferences.accounts" right requires admin authentication.   /etc/authorization could be an article on its own, but for now, let's focus on the section for login window.  This is the system.login.console section:

<key>system.login.console</key>
    <dict>
        <key>class</key>
        <string>evaluate-mechanisms</string>
        <key>comment</key>
        <string>Login mechanism based rule.  Not for general use, yet.</string>
        <key>mechanisms</key>
         <array>
            <string>builtin:smartcard-sniffer,privileged</string>
            <string>loginwindow:login</string>
            <string>builtin:reset-password,privileged</string>
            <string>builtin:auto-login,privileged</string>
            <string>builtin:authenticate,privileged</string>
            <string>HomeDirMechanism:login,privileged</string>
            <string>HomeDirMechanism:status</string>
            <string>MCXMechanism:login</string>
            <string>loginwindow:success</string>
            <string>loginwindow:done</string>
        </array>
    </dict>

The login window uses this section to figure out how to authenticate the user, and uses Security Agent Plugins to do this.  These live in /System/Library/CoreServices/SecurityAgentPlugins, and are specified in the mechanisms section.  Each mechanism is specified by the name of the plugin, a colon, and the name of the mechanism that is passed to the plugin.  This allows the same plugin to provide multiple mechanisms.  There is also the "privileged" option.  If this is specified, the plugin is run in a privileged context where the effective UID is 0 (root).  If privileged is not specified, the plugin is in non-privileged mode, and can access the GUI. 

The mechanisms are checked in order, and a fallure or error in any mechanism would cause the authenication to fail.  Let's go down them in order:

builtin:smartcard-sniffer,privileged
provides smart card support at login window

loginwindow:login
Presents the actual login window GUI.   Doesn't authenicate, but rather just puts up the GUI.

builtin:reset-password,privileged
Checks to see if the users password needs to be reset.

builtin:auto-login,privileged
support for auto-login via the /etc/kcpassword file

builtin:authenticate,privileged
checks the user's credentials via Directory Services

HomeDirMechanism:login,privileged
HomeDirMechanism:status
Filevault support, and tools to fix filevault issues, such as password changing.

MCXMechanism:login
GUI for selecting workgroup if you are in multiple workgroups

loginwindow:success
loginwindow:done
cleanup and GUI progress updates

As you can see, the heavy lifting for authenication is done by the builtin:authenticate,privileged mechanism. This is the mechanism we need to change in order to authenicate off of a 3rd party KDC.  You can  change "builtin:authenticate,privileged" to "builtin:krb5authnoverify,privileged", and you can authenticate via the login window to a KDC, but you'll be vunerable an the Zanarotti attack. 

The Zanarotti attack leverages the idea that if successful authentication is based on the receipt of the TGT, this can be exploted to break into system.  The attacker sets up a machine on the local network that can craft TGT with a current user name and a password made up by the attacker.  This machine then continually floods the network with the TGT.  The attacker then goes to the machine they want to break into, and puts in a valid username and the password that was used to generate the rogue TGTs.  The client system will try to authenicate via kerberos by requesting a TGT, and there is a good chance that the TGT that gets received back is from the rogue system.  Since the fake TGT is encrypted with the attackers password, the login window can decrypt the TGT and allow login. The TGT is not good for getting actual service tickets, but the attacker doesn't care; they got access to the local files.

Note that this attack requires access to the network to flood the network with TGTs, as well as access to the Login Window to type in the credentials.   Also note that the Zanarotti attack doesn't work with Open Directory, since the login windows does not predicate login with getting a TGT, but rather authenticates via the Password Server specified in the user's authentication authority. The Active Directory plugin does a host princincal verification like the one that is described below.

In order to prevent this type of attack, the host should actually try and use the TGT that it receives, and see if it can access services locally with it.  In order to do this, a keytab must be installed on the local machine, and must contain a host principal, like this:

host/host1.example.com@EXAMPLE.COM

Now, when login window receives the TGT, and decrypts it with the user's password, it turns around and asks the KDC for a services ticket for the "host" service on the local machine.  Since the service ticket is encrypted with the host principal on the KDC and can only be decrypted with the host principal on the client, the client can be sure that the TGT and the user's password are valid (since only the "real" KDC would be able to encrypt something with the host principal)

If you are installing keytabs on the local clients, there is an issue you should be aware of. They keytab principals for services on the local machine as based on DNS name (like host1.example.com from above). If your clients are assigned IP address via DHCP, the hostname of the client system will change. In order to prevent this, you either need to assign static IP address and the corresponding forward DNS records, or use the scutil to hardcode in the hostname:

sudo scutil –set HostName host1.example.com

You now need to get a keytab from your KDC that has a host principal for each client.  Install it in /etc/krb5.keytab, and verify you can read it with:

sudo klist -k

Also verify that they keytab is valid by trying to authenticate as the host principal, but instead of using a password to authenicate, use the keytab:

kinit -k host/host1.example.com 

If you don't get an error, verify that you have a TGT with the host principal using klist.

Now that you have verified that the keytab is correct, in /etc/authorization, change "builtin:authenticate,privileged" to "builtin:krb5authenticate,privileged".  You should now be able to log in with authentication via your 3rd party KDC.  If you look in the logs on the KDC, you should see a request for a TGT for the user principal, followed by a host principal request for the client.

Sweet!  It is all working.  Or is it?  If you try and use that user as a admin user by adding them to the admin groups via dseditgroup, or if you try to unlock the screen saver or unlock from sleep, you cannot use these credentials.  Why?  Because the authentication dialog that comes up is not the login window, but a different authentication dialog, and does not use the system.login.console rights.  In order to get this last piece to work,  edit the "authenticate" rule /etc/authorization:

<key>authenticate</key>
        <dict>
            <key>class</key>
            <string>evaluate-mechanisms</string>
            <key>mechanisms</key>
            <array>
                <string>builtin:smartcard-sniffer,privileged</string>
                <string>builtin:authenticate</string>
                <string>builtin:authenticate,privileged</string>
            </array>
        </dict>

Note that it looks similar to the system.console.login, but has a smaller set of mechanisms.  The difference in the mechanisms is the "builtin:authenticate" mechanism without the privilege option. This presents the dialog box that asks for the user's credentials.  As with the system.console.login, replace "builtin:authenticate,privileged" with "builtin:krb5authenticate,privileged".  Now when you authenticate when waking from sleep, unlocking the screen saver, or unlocking a system preference, you'll renew your TGT and know that both the user's and the TGT are valid.

It will also give you rights to drop the "Zanarotti attack" phrase at dinner parties when people talk about Kerberos authentication.  Good times.

Timothy Perfitt

Timothy Perfitt is currently the head of Twocanoes Software, Inc, creator of iOS and Mac apps for the IT market. Prior to Twocanoes Software, he survived the collapse of the dot com era by jumping from Coolboard.com to Apple, Inc in 2001. He worked on the initial certification training materials for Mac OS X, worked in Education Sales, and then finished his time at Apple in 2012 working with Fortune 500 customers to integrate Macs and iOS devices into complex environments. He is a returned Peace Corps volunteer, serving in the Solomon Islands as a math and science teacher from 1991 to 1993.

More Posts - Website

Follow Me:

Exit mobile version