Articles August 24, 2008 at 12:00 pm

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:

[email protected]

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.

About 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.

No Comments

  • You can go one step further by using a kerberos password to authenticate sudo requests. The following is an article I wrote for our internal KB:

    PAM kerberos module needed for sudo command
    ——————————————————

    When a user with an NIS or LDAP account (and no password) needs to escalate to root, the preferred
    method is to use the "sudo" command ("sudo -s" will give the user a root shell). If
    the computer uses kerberos for authentication then the sudo command will not work.
    This page describes how to kerberize the sudo command by adding a PAM module.

    1. Get the PAM module.
    * Source code for the module can be found at
    http://www.math.gatech.edu/~villegas/pam_krb5/

    2. Install the PAM module
    — 1. sudo cp pam_krb5.so /usr/lib/pam
    — 2. sudo chmod 444 /usr/lib/pam/pam_krb5.so
    — 3. sudo chown root:wheel /usr/lib/pam/pam_krb5.so

    3. Tell the computer to use the new PAM module
    — 1. vi /etc/pam.d/sudo
    — 2. add the following line below the other "auth sufficient" lines
    auth sufficient pam_krb5.so
    — 3. :wq!

    4. Modify the /etc/sudoers file with visudo as appropriate.

    To recap, one best practice to secure your Mac (or other *nix box) is to limit access
    to the root account. If you turn off PermitRootLogin in the sshd_config, then no one
    can login as root. You then need to add an account for each user that needs to access
    the machine (or use NIS or LDAP), and add to the /etc/sudoers file those users that
    need to have escalated privileges. You can use sudo to give all or limited escalated
    privileges to different users, groups, or computers (via netgroups). See man sudoers .

    If you are using LDAP or NIS with kerberos passwords, you should not use a
    .k5login in the root home directory. If a person’s credentials are hijaked (which is
    possible) you don’t want the hijacker to have unauthenticated root access to your
    box. To reduce the chance of this happening, instead of the .k5login file, have the
    users use the sudo command. On Red Hat, sudo is already kerberized and the user’s
    kerberos password will work. On a Mac you need to follow the instructions above to kerberize
    sudo. You also need to configure the machine for kerberos
    (/Library/Preferences/edu.mit.kerberos needs to be configured). If the users need to
    ssh into the machine, then the machine also needs a keytab

Leave a reply

You must be logged in to post a comment.