[OpenAFS] The Illusion of Security
Rodney M Dyer
rmdyer@uncc.edu
Sun, 17 Aug 2003 17:59:55 -0400
Subtitled "My Gripe with Pipe"
Hi everyone,
I've just been in an interesting short debate via personal email with one
of the developers of MIT's Kerberos toolset. I will keep their name
private out of professional courtesy. The debate centers around the
reasoning behind preventing plaintext passwords to be passed to certain
applications that require them. In this instance, kinit, ssh, etc. This
polite exchange expanded into bigger issues of security. I'm emailing this
list to get some commentary from a larger community that deals with these
issues every day. I'd be interested in what the global concensus might be.
Originally the email centered around the simple question of why the MIT
Kerberos for Windows "kinit" client will not allow passwords to be provided
through stdin. See...
http://www.coe.uncc.edu/~rmdyer/krblogon.htm
Section: Very Important Notes
SubSection: "Bug in MIT's version of KINIT.EXE prevents reading passwords
from stdin"
The standard answer from MIT is...it's not a bug, it was intentional.
Apparently there is some rational for not allowing plaintext passwords to
be passed around between processes via pipes. The following points merit
that rational...
1. STDIN is a pipe. The operating system may create a temporary file for
transfering the plaintext through the pipe. Someone may figure out the
file name and grab the password. If the pipe has been redirected over a
network, it's likely not through a secured channel like SSL.
2. Since pipes are essentially FIFO's the recieving application may not be
written well, so it might be buffer overflowed.
3. Using the stdin method allows dumb users to do stupid things like...
kinit < file
or,
echo "password_1234" | kinit
4. Processes that request passwords from users should have their own
direct user input channels that can't be overridden.
5. If you absoulutely need to pass a plaintext password to another process
like "kinit", you should instead create your own application that calls the
libraries that the other application uses.
6. What if the auth process needs more than a password, as with a hardware
or bio crypto system?
7. SSH doesn't allow stdin. Why should kinit?
At this point if anyone has any other reasons I'd love to hear them. I
suppose these are all perfectly valid reasons for intentionally coding
"kinit" so that it can't allow stdin to be used.
But...
I'm what might be termed as a practical, or practitioning systems
programmer. That means that for solving the given problem of the day I may
not always be capable of pursuing idealistic solutions.
Case in point, for the problem of gluing together three differing systems
of AFS, Windows, and Kerberos 5 I had to put together something that I had
hoped would be easy to understand, require little code, be easily
scriptable, use off-the-shelf components that people are already familiar
with, and above all else be secure. I had put together the method of using
the AFSLogonShell, kinit, and aklog, to solve a number of niggling little
problems with storing user accounts in AFS while authenticating my users to
Kerberos 5. This all seemed to be very rational to me.
Then, one day recently I get this email from a developer at MIT saying that
what I've done is really bad mojo. I shouldn't be sending the user
passwords to kinit via stdin and I shouldn't allow it. Well now, this is a
wake-up call. He gladly retorted some of the above reasons.
My response to him was to be sympathic to his reasons, but at the same
time, stand in the devils advocates shoes. I understand ideology and
political correctness, but many times those reasons don't play well with
getting things done, and making things supportable.
My responses are...
1. Even though the OS may create a temporary file for the pipe, the
contents of that file should be off-limits to unpriviledged users. That
is, assuming you could figure out the file name in the first
place. Moreover, as an experience systems admin/programmer working at the
level of password authentication, not one of us is likely to redirect the
pipe over a network. Give us some credit please!
2. Most passwords are rather limited in scope. The characters used, and
the length of the string would extremely limit the probablity of a buffer
overflow, especially if we pre-validate it first.
3. Users can be stupid. It isn't my job as admin to limit what they do in
their sandbox. My job is to create a safe sandbox for them to work
in. You will never be able to write code that manages dumb users. And, if
if matters so much to prevent ordinary users from doing this, then do
something smart like make "kinit" find out what level of secuity they
have. Require both a "-pipe" option on the command line as well as
internal code that checks to see if you are running as root, or in the case
of Windows, user "SYSTEM". But, even this won't pevent the user from being
a smartass. See Bigger Issues below.
4. Since the process runs in the users context anyway isn't it up to the
user to decide what channels the password takes for authentication? This
is related to the Bigger Issues below.
5. In our IT group we try to limit the number of special "in-house" apps
we have to write, while at the same time use common "well-known" apps with
well defined interfaces. This minimizes the knowledge base that our IT
people have to deal with. People "know" kinit, they "know" aklog, they
"know" pipes and scripting. They've never heard of some special app that
I've written just for our site.
6. I don't really have a response here. The question of what we do in
this circumstance depends largely on whether we need such
flexability. Some do, others don't. When processes like "kinit" and "ssh"
request that kind of input, please let me know. It's my job as systems
programmer to determine yet another solution to the problem.
7. The Solaris "kinit" allows stdin "out-of-the-box". Why not the Windows
version?
Bigger issues...
Installing open-source software on unmanaged Windows machines is a risky
business in the first place. If you don't find some way of protecting the
very files that you are using to authenticate your users, then they can be
changed...by the users, or by someone else.
For example, installing OpenAFS, Kerberos, and Kerberos for Windows on any
ordinary unmanaged user box is not secure. Since any hacker can download
the source code, they can potentially sneak into one of your user boxes a
socket based password grabber in the form of "afslogon.dll", "kinit", or
"Leash32". You would never know unless you performed a checksum of some
kind like MD5.
Microsoft itself passes the plaintext password to all the logon
authenticators in the form of an environment variable. All that needs to
be done is to make a change to "afslogon.dll" to send the password to some
site. The source is readily available.
The AFSLogonShell is simply a glue that allows you to pass the password
(provided by Microsoft) to "kinit" which gets a tgt. The reason I can do
this is because I've modified (hacked) "prompter.c" to allow "kinit" to
accept input from stdin. However I don't like adding in my prompter hack
with every new version of "kinit". I'd rather have that functionality
"out-of-the-box". I believe this should be allowed.
The cultural history of Windows is that users have complete control, or
root level priviledge on their boxes. This is slowly beginning to
change. Our group has managed a "closed" network of NT/2000/XP machines
since '97. The users don't have the ability to change local system files
and settings beyond their own environments. The local file system and
processes are protected by ACLs. We've managed our boxes with rather
unorthodox (in the windows world) UNIX-like techniques. In a sense they
are very much like our Sun Solaris machines.
Based on this environment, the entire authentication chain, including the
AFSLogonShell is protected. No user is going to be able to grab the
plaintext password, change a system file, or modify the process. No user
is going to be able to grab the information passed through stdin to
"kinit". It is "secured", and it works.
MIT Rebuttle...
What I've done is just wrong. Instead of piping to "kinit", I should write
my own application that is coded against the Leash libraries. According to
them, I can take my environment variable password and pass it directly to
the LeashAPI. I thought about this for a bit, then it hit me...how is this
any different? I've just changed this...
c:\>envout env_password_var | kinit
to this...
set env_password_var=Password_1234
mykinit.exe
Nothing has changed here. This won't help.
My further rebuttle...
The simple issue is this...OpenAFS, Leash, MIT Kerberos, AFSLogonShell, are
"add-on" applications that don't link into the "real" kernel. No add-on
application, especially an open-source one will make your environment
secure, no matter how smart you think you've coded the password input. If
your box is unmanaged, or can be "owned" by a hacker, then "all bets are
off". The justification for not allowing stdin to be used for password
entry is flimsy at best, and leads to a false sense of security at
worst. It also prevents me, a practical systems programmer from
implementing a rather simple yet effective technique to provide an interim
solution for a rather long term problem.
This is not a rant, or flamefest against my MIT friend. I respect their
opinion and value their input. I do not however believe it is in the best
interest of the community as a whole to "decide for us" on how we should
implement our solutions to complex problems. This smells of the "we know
better than you" syndrome. In fact, it actually costs MIT some code to
prevent us from performing the pipe.
I'm ready to take the slings and arrows of the OpenAFS community at
large. I also value your opinion too. Please let me know how you feel on
this issue. I'm open to suggestions and ready to consider another
solution. Do any of you use "kinit" authentication via a pipe of some kind?
A Cleaner Way
Speaking of which, does anyone know how to modify ms2mit.exe so that it
will work in the AFSLogonShell? The problem here is that the AFSLogonShell
doesn't run in the user's process space at logon, it runs as user SYSTEM,
in the WinLogon process space. This is why it has so much appeal, it
actually runs before the user's process space is init'ed, before the
profile downloads, and before folders are redirected. I simply need a way
to grab the user's Windows Krb5 logon credential as user SYSTEM. This
would be the best fix for my problem, but I'm not sure how to accomplish
this. That way I would have no need for the password, even though...don't
forget, it would still be provided to me by WinLogon.
I would essentially be changing this...
envout env_password_var | kinit
aklog
to this...
ms2mit -special_logon_option?
aklog
Anybody got a clue?
Thanks for listening,
Rodney
Rodney M. Dyer
Windows Systems Programmer
Mosaic Computing Group
The William States Lee College of Engineering
University of North Carolina at Charlotte
Email rmdyer@uncc.edu
Phone (704)687-3518
Help Desk Line (704)687-3150
FAX (704)687-2352
Office 267 Smith Building