Closed GoogleCodeExporter closed 9 years ago
[deleted comment]
Also, this is not sufficient:
void errorExitIfAttackViaString(NSString * string)
{
BOOL startsWithDot = [string hasPrefix: @"."];
NSRange r = [string rangeOfString: @"/.."];
if ( startsWithDot
|| (r.length != 0) ) {
fprintf(stderr, "Tunnelblick openvpnstart: Apparent attack detected; string being tested is %s\n", [string UTF8String]);
[pool drain];
exit(EXIT_FAILURE);
}
}
Because of symlinks.
Which means it's probably possible to abuse the "deleteLogs" function to delete
things as root.
What are we left with? killOneOpenVpn and killAllOpenVpn. In these, there's a
race condition between checking process names and actually killing the process,
so depending on what is to get killed, there could be some situations where an
attacker could send SIGTERM to various ephemeral processes.
I guess I should also point out that allowing users to load OpenVPN as root
with a user-controlled config file is also a vector, since OpenVPN itself can
be told not to drop privs, and execute various things on various events.
Original comment by Jason.Donenfeld
on 11 Aug 2012 at 3:19
So okay, a small summary for CVEs and whatnot:
1. A race condition in file permissions checking can lead to local root.
2. Insufficient checking of merely 0:0 744 can lead to local root on systems
with particular configurations.
3. Insufficient validation of path names can allow for arbitrary kernel module
loading, which can lead to local root.
4. Insufficient validation of path names can allow execution of arbitrary
scripts as root, leading to local root.
5. Insufficient path validation in errorExitIfAttackViaString can lead to
deletion of files as root, leading to DoS.
6. Allowing OpenVPN to run with user given configurations can lead to local
root.
I think at this point, rather than trying to put a band aid on each of these,
it's probably best to rework the security architecture of the program.
Original comment by Jason.Donenfeld
on 11 Aug 2012 at 3:23
Professional Cocoa Application Security, http://www.amazon.com/dp/0470525959.
Graham Lee offers code to elevate privileges, check paths, etc when using the
Cocoa framework.
Lee also has a blog with lots of sample code at
http://blog.securemacprogramming.com/.
Original comment by noloa...@gmail.com
on 11 Aug 2012 at 3:24
Left one out.
7. Race condition in process killing.
Original comment by Jason.Donenfeld
on 11 Aug 2012 at 3:37
(I'm the current Tunnelblick developer, having taken over from Angelo Laub, the
original author, several years ago.)
Thanks Jason, for your very helpful comments. And thanks to ctrlaltca for
submitting this, and to noloaderfor the book reference.
I am not sure how to "rework the security architecture" but I'll look at
noloader's book.
Everything (so far!) comes down to five problems:
1. Allowing unsecured paths to configuration and other files (even if the files
themselves are 0:0 744, all their containing folders must also be writable only
by root).
2. Insufficient validation of paths.
3. Race condition in process killing.
4. Bug in process killing
5. Bug in log deletion.
#1 will need more thinking, but I think that the only solution is properly
secured configuration paths. This will mean that "private" configurations will
need to use "shadow copies".
#2 is solvable by fixing the code to properly validate argv[0] (i.e., make sure
that the realpath to the executable is a secured path as in #1, and has a
trailing '/Contents/Resources/openvpnstart'). The second part is necessary (and
I think sufficient) to make sure that arbitrary OS X paths that are secure
aren't used.
#3:The race condition I see is that if someone tells openvpnstart to kill a
process, and, between checking that the process is named "openvpn" (assuming
that check is added, see #4) and actually killing it, the user caused a
different process to be running with that process number. That seems farfetched
(does OS X actually reuse process numbers like that? Hard to believe!) but
could be eliminated by changing the code to not use (and thus not make
available) the "kill by process number" subcommand of openvpnstart. That is
possible, although will be some situations (when openvpn isn't responding to
management commands) where Tunnelblick won't be able to stop and OpenVPN
process.
#4: There is not only a race condition in openvpnstart's kill subcommand, there
is a bug, too -- openvpnstart should check that the process name is "openvpn"
before killing it. But if the command is eliminated, that won't be necessary.
#5: Is a leftover from when logs could be in arbitrary places. The code could
restrict them to the actual folder in which logs are kept.
I would REALLY LIKE to get as much help and input on this as I can get.
Original comment by jkbull...@gmail.com
on 11 Aug 2012 at 6:19
> 1. Allowing unsecured paths to configuration and other files (even if the
files themselves are 0:0 744, all their containing folders must also be
writable only by root).
Even if you resolve symlinks, fix the race condition, and check every component
of the path to see that it's root owned etc, there is still a more fundamental
problem here: 744 is not an indication that it's safe to run something as root.
> #2 is solvable by fixing the code to properly validate argv[0]
Probably not. _NSGetExecutablePath is probably what you want, but even so,
there are race conditions and symlink attacks to worry about too.
> (does OS X actually reuse process numbers like that? Hard to believe!)
After you create enough processes, the PIDs cycle around.
> but could be eliminated by changing the code to not use
That's one solution. Another solution is to have openvpn always drop privs to a
special openvpn user, and then seteuid(openvpn-uid) before calling kill(pid,
term). This way, the kernel does the validation, not you.
--
Also:
* Kext issue.
* Running openvpn as root using user provided config files that can exec more
things.
--
> I would REALLY LIKE to get as much help and input on this as I can get.
I think the most helpful thing I can tell you is: stop. Don't stop making
Tunnelblicker -- it's great -- but don't go down the dark and scary road of
trying to make root-SUID helpers secure. It's just really incredibly hard and
error-prone, and nowadays there's usually a better alternative solution.
I believe OS X has some nice APIs for doing things in a privileged manner
that's controlled by OS policies -- such as nice confirmation dialogues and
whatnot. Try to work out a framework based on these frameworks, and not based
on a SUID helper.
I know that OpenVPN can drop privs -- you should look into this too. But
perhaps, even more so, you might look around and see if there's a way to
administer the TUN device without needing root privs. Linux offers
CAP_NET_ADMIN and related; maybe OSX has something similar?
Original comment by Jason.Donenfeld
on 11 Aug 2012 at 6:39
Thanks, Jason. I appreciate your advice to not try to "patch" this SUID helper,
but I'd like to explore that a bit before I give up.
I even agree that the best solution is to have a better way of doing things,
but I can't see that happening very soon (as opposed to "fixing" the problems
within the SUID helper framework).
> Even if you resolve symlinks, fix the race condition, and check every
component of the
> path to see that it's root owned etc, there is still a more fundamental
problem here:
> 744 is not an indication that it's safe to run something as root.
If it is owned by 0:0 with 744 that's not sufficient? How come?
>> #2 is solvable by fixing the code to properly validate argv[0]
> Probably not. _NSGetExecutablePath is probably what you want, but even so,
there are
> race conditions and symlink attacks to worry about too.
Sorry, I should have been more specific, I meant using _NSGetExecutablePath and
realpath. Clearly it is wrong to rely on argv[0]. But if Tunnelblick
1. Uses _NSGetExecutablePath and realpath to get the real path to the program
that is executing;
2. Verifies that each folder in that path (starting with the root folder) is
owned by root and not writable except by root; and
3. Verifies that the final path element (the executable) is owned by 0:0, and
has 744 permissions
then what is the vulnerability?
> Also:
> * Kext issue.
> * Running openvpn as root using user provided config files that can exec more
things.
Kext issue is the same as the exploit -- wrongheaded use of argv[0]. Fixed by
same fix. (Well, I'll have to make sure that's really what the code does, but
it should have the same solution in general terms.)
"Running openvpn as root using user provided config files that can exec more
things" is fixed by not allowing that. This was what I meant by "properly
secured configuration paths". (Of course, it is still necessary for the person
installing Tunnelblick and installing configurations to be sure that nothing
malicious is included in what they are installing.) Once a configuration has
been "secured" by shadow copying (which requires admin username/password), the
configuration will be secure. And it will contain only references to secured
scripts, etc.
> I know that OpenVPN can drop privs -- you should look into this too. But
perhaps,
> even more so, you might look around and see if there's a way to administer
the TUN
> device without needing root privs. Linux offers CAP_NET_ADMIN and related;
maybe
> OSX has something similar?
Not that I've found. Anybody else?
Again, Jason, thanks for your helpful comments.
Original comment by jkbull...@gmail.com
on 11 Aug 2012 at 7:11
> I appreciate your advice to not try to "patch" this SUID helper, but I'd like
to explore that a bit before I give up.
You'll most likely spend more time trying to get the SUID helper right than you
would doing things another way.
> If it is owned by 0:0 with 744 that's not sufficient? How come?
Many reasons, one of which is that this destroys the security of the nosuid
mount flag, that's commonly used on network file systems and FUSE.
> 1. Uses _NSGetExecutablePath and realpath to get the real path to the program
that is executing;
You have to be a bit careful, also, to see if it still exists.
_NSGetExecutablePath will return paths to symlinks that can be removed before
realpath is called.
> 2. Verifies that each folder in that path (starting with the root folder) is
owned by root and not writable except by root; and
And is not a symlink. Key: lstat, not stat.
> 3. Verifies that the final path element (the executable) is owned by 0:0, and
has 744 permissions
Nope. See above.
Original comment by Jason.Donenfeld
on 11 Aug 2012 at 7:52
For the Cocoa equivalent of realpath(3), see stringByStandardizingPath
(https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundati
on/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString
/stringByStandardizingPath).
realpath could suffer truncations after PATH_MAX, and will return ENAMETOOLONG.
I don't believe NSString's stringByStandardizingPath suffers the same.
Original comment by noloa...@gmail.com
on 11 Aug 2012 at 9:27
Jason, thank you for all your input. You've given me a lot to think about.
It would have been nice to be notified of this in advance and have this
discussion privately. Did I miss an attempt on your part to do that?
Original comment by jkbull...@gmail.com
on 11 Aug 2012 at 10:51
> Did I miss an attempt on your part to do that?
No. I actually had meant to post it here before the mailing lists, but
exhaustion struck and I got confused.
If you want to discuss anything privately, though, shoot me an email or instant
message.
Original comment by Jason.Donenfeld
on 11 Aug 2012 at 10:54
Issue 213 has been merged into this issue.
Original comment by jkbull...@gmail.com
on 12 Aug 2012 at 1:08
The following CVEs have been assigned to this issue.
==================
1. A race condition in file permissions checking can lead to local
root. - TOCTOU
Please use CVE-2012-3483 for this issue
==================
2. Insufficient checking of merely 0:0 744 can lead to local root on
systems with particular configurations.
Please use CVE-2012-3484 for this issue
==================
3. Insufficient validation of path names can allow for arbitrary
kernel module loading, which can lead to local root.
4. Insufficient validation of path names can allow execution of
arbitrary scripts as root, leading to local root.
5. Insufficient path validation in errorExitIfAttackViaString can lead
to deletion of files as root, leading to DoS.
Please use CVE-2012-3485 for these issues
==================
6. Allowing OpenVPN to run with user given configurations can lead to
local root.
Please use CVE-2012-3486 for this issue
==================
7. Race condition in process killing. - TOCTOU
Please use CVE-2012-3487 for this issue
Original comment by Jason.Donenfeld
on 14 Aug 2012 at 1:47
WARNING -- JASON'S EXPLOIT DELETES TUNNELBLICK CONFIGURATIONS!
I have removed Jason's comment #1, and reproduce it below without the link to
his exploit program. I don't know if it is due to carelessness or maliciousness
by Jason, but his exploit program deletes all of your private (i.e., not Shared
or Deployed) Tunnelblick configurations.
Note: I left in the link to the second, "for kids", exploit, because -- as far
as I can tell -- it doesn't seem to do anything malicious.
Sorry to have not noticed this earlier; I just had a chance to look at the
exploit code in detail.
==================================================================
Here is Jason's comment (previously comment #1), without the link to the expoit:
==================================================================
Comment 1 by Jason.Donenfeld , Aug 11, 2012
This particular exploit affects this code:
if ( checkOwnerAndPermissions(scriptPath, 0, 0, @"744") ) {
fprintf(stderr, "'%s' executing...\n", [scriptName UTF8String]);
returnValue = runAsRoot(scriptPath, [NSArray array]);
fprintf(stderr, "'%s' returned with status %d\n", [scriptName UTF8String], returnValue);
}
checkOwnerAndPermissions runs before runAsRoot, so it's easy to swap out
symlinks or hardlinks in between, so that runAsRoot executes a program other
than the one validated by checkOwnerAndPermissions. Sure, one fix would be to
open a fd, and then just use fstat and fexecve, but really this whole security
model is broken. 0:0 and 744 is not a sufficient check.
The exploit code for that is here:
[LINK REMOVED BY MODERATOR 2011-08-21]
Actually, there are more problems with the SUID helper. Check this one out:
in main:
execPath = [[NSString stringWithUTF8String:argv[0]] stringByDeletingLastPathComponent];
loadKexts:
NSString * tapkext = [@"tap" stringByAppendingString: TunTapSuffixToUse([execPath stringByAppendingPathComponent: @"tap"])];
[arguments addObject: [execPath stringByAppendingPathComponent: tapkext]];
becomeRoot();
int status;
int i;
for (i=0; i < 5; i++) {
NSTask * task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath:@"/sbin/kextload"];
[task setArguments:arguments];
[task launch];
[task waitUntilExit];
So here, we can load any kernel module that we please.
Here's another one. There is no proper checking, again, of argv[0] (which isn't
really the right way to do things anyway), and so we can play an easy symlink
game with the version function, with no race required at all, for an easy root:
Exploit code:
http://git.zx2c4.com/Pwnnel-Blicker/tree/pwnnel-blicker-for-kids.sh
Original comment by jkbull...@gmail.com
on 21 Aug 2012 at 7:31
I have prepared modifications to Tunnelblick to fix the security problems
raised in this Issue.
I would like people to test the new version and report back problems/successes.
TESTERS SHOULD BE VERY CAREFUL!
THIS IS AN EXPERIMENTAL BUILD. It has not been tested very thoroughly. A lot of
code that deals with configurations has changed -- there is the possibility of
losing configurations (or losing access to them). BACK UP BEFORE USING IT.
As a minimum, back up the following three folders:
/Applications/Tunnelblick.app
/Library/Application Support/Tunnelblick
~/Library/Application Support/Tunnelblick
At the end of this post is a list of some of the changes in this version.
I have uploaded a .zip of this new version (along with the source code); you
can download it from
http://code.google.com/p/tunnelblick/downloads/detail?name=Tunnelblick_3.3beta21
_Experimental_Unsigned.zip&can=2&q=
PLEASE GIVE ME FEEDBACK about what works and what doesn't. Try everything you
can -- creating new configurations, sharing, privatizing, duplicating,
renaming, etc. (You can even try connecting them :)
Please email directly to me at jkb ull ard at gmail.
============================
Some of the changes include:
* Tunnelblick.app must now be in /Applications. (A side effect of this is that you are no longer able to use multiple "Deployed" versions of Tunnelblick located in different places on the boot volume.)
* "Private" configurations may only be "Tunnelblick VPN Configurations" (.tblk). ("Bare" .ovpn or .conf configurations may continue to be used in Deployed configurations.)
* "Private" configurations are no longer secured. Previously secured private configurations will be "un-secured" (changed so they are owned by the user, etc.).
* "Shadow copies" of private configurations are *always* used, and the checkbox on the Preferences panel to use them or not has been removed.
* Updating a Deployed version no longer invalidates the new copy's digital signature. (The Deploy data is no longer copied into the application bundle itself.)
* The "Quit All OpenVPN Processes" button has been removed from the "Utilities" panel.
* "Flush DNS after connecting/disconnecting" is only available for configurations using "Set name server".
============================
I hope to include some additional features in a future release:
* Enhancements for installing a .tblk -- fix subfolder references, detect CR-LF in certificates and keys (because OpenSSL rejects them), detect missing certificate and key files, etc.
* Some way of converting a .conf or .ovpn configuration to a .tblk. (Perhaps a a "gear" menu item on the Configurations panel, or maybe automatically create them on first launch, or maybe provide a method via drag and drop or something.) Suggestions are welcome!
* A "Revert to Last Saved" gear menu item on the Configurations panel. This would replace a private configuration (which is now unprotected, remember) with the last shadow copy that was created for that configuration. This would *not* require admin access. If a non-admin user modifies a VPN configuration, this will allow them to "undo" the changes and connect to the VPN.
Original comment by jkbull...@gmail.com
on 23 Aug 2012 at 9:14
Attachments:
Hi,
Thanks for spending the time to fix this. A lot of people are not as motivated
or hard working as you are when it comes to security things. Unfortunately
there are still many significant issues. The one that jumped out at me
immediately is the ability to make gOkIfNotSecure always be true.
zx2c4@Jasons-MacBook ~ $ cat give-up-on-suid-helpers.sh
#!/bin/sh
rm -rf /tmp/pwn
mkdir -vp /tmp/pwn/Tunnelblick.app/Contents/Resources/
sed 's/NO/YES/' /Applications/Tunnelblick.app/Contents/Info.plist >
/tmp/pwn/Tunnelblick.app/Contents/Info.plist
ln /Applications/Tunnelblick.app/Contents/Resources/openvpnstart
/tmp/pwn/Tunnelblick.app/Contents/Resources/
exec /tmp/pwn/Tunnelblick.app/Contents/Resources/openvpnstart
From here, we can choose our own adventure with other exploitation attacks.
Maybe some 744 link magic, maybe something else; it doesn't matter -- it's easy
from here.
***PLEASE GIVE UP ON MAKING AN SUID HELPER***
I respectfully beg you to invest your time in saner approaches using Cocoa
security frameworks as discussed above. You're clearly an able and intelligent
programmer, but SUID helpers will nearly always be troublesome. Not to mention,
there are very few cases when SUID helpers are absolutely necessary and this is
not one of them.
***I will not audit any subsequent patches you release for SUID helpers.*** By
pursuing the SUID route, you put your Macintosh users at great risk and pave
the way for a myriad of security issues in the future from the extremely
brittle SUID codebase.
I like the work you've done, and you're by no means lacking talent, but this is
not the place for SUID helpers. For the good of your users, please give up with
the SUID route and do something properly.
Thank you,
Jason
Original comment by Jason.Donenfeld
on 24 Aug 2012 at 3:09
Today I uploaded a new version which addresses more security problems,
including the problem Jason pointed out in comment #17.
It may be downloaded from
https://code.google.com/p/tunnelblick/downloads/detail?name=Tunnelblick_3.3beta2
1_Experimental_2_Unsigned.zip&can=2
All the warnings in my earlier comment 16 still apply: this is experimental;
backup before using it, etc.
=======================================
New comments:
I do plan to use a more sophisticated security scheme in future versions of
Tunnelblick, but this one still uses a SUID helper.
Special thanks to noloader for his very helpful comments and advice. (I haven't
taken all of his advice -- all problems are my fault, not his!)
Original comment by jkbull...@gmail.com
on 31 Aug 2012 at 11:25
Again, please give up with making an SUID helper. Spend your time working a
better solution. You are wasting time that should be spent on a more secure
solution.
You're doing your users a grievous disservice. You put Mac users at unnecessary
risk. You will not succeed in securing this code base; your design is flawed.
Your negligence and gross disregard for the safety of your users is shocking,
and I can no longer recommend that anyone uses Tunnelblick or any of the code
you write that runs privileged.
Despite several pleas, you have continued to pursue a design that will never
succeed.
There are still holes in the most recent source you posted. In congruence with
my previous message, I will not post any details here, in order to motivate you
to drop the SUID approach completely.
Original comment by Jason.Donenfeld
on 31 Aug 2012 at 3:55
It's been a while, have this issue been addressed?
Original comment by t.mikae...@gmail.com
on 1 Apr 2014 at 11:48
t.mikael.d --
Depending on what you mean by "this issue", yes or no.
All of the specific vulnerabilities raised on posts in this Issue have been
fixed (and so have many others).
However, I have left this issue in "Started" status for two reasons:
1. Tunnelblick still uses an SUID binary. Jason says that that, in itself, is a vulnerability.
2. Jason says "There are still holes in the most recent source you posted" (as of 8/31/12) but that he will not disclose details. Subsequent to his comment, several potential vulnerabilities were fixed but it is impossible to know if the "holes" he says he knows about were fixed since he has not disclosed them.
Original comment by jkbull...@gmail.com
on 1 Apr 2014 at 12:17
I have committed changes to the Tunnelblick source code that implement a
launchd daemon instead of using an SUID helper on OS X 10.5 ("Lion") and
higher. The changes will be available in the next beta release.
A "snapshot" (pre-release version of Tunnelblick) is available that includes
the changes. Email me privately at my Gmail address, jkbullard, for a link to
download the snapshot.
Original comment by jkbull...@gmail.com
on 14 Jan 2015 at 9:17
Original issue reported on code.google.com by
ctrlal...@gmail.com
on 11 Aug 2012 at 9:41