Security: Don't add relative directories to PATH
As documented on the Wiki, uru currently adds two dummy entries to the PATH to mark the location where it added new Ruby directories to that variable. I understand why this is needed, but the specific names chosen for these markers have some unfortunate side effects which could be exploited by an attacker to trick a user into executing malicious code.
Specifically, if a malicious actor creates a directory with the name _U1_
, any executable files added to that directory will override system commands when the user cd's to that directory's parent after invoking uru. So the file _U1_/ls
could easily be run by a user accidentally if they cd to _U1_
's parent directory and then decide they want to know what files are in it.
In order to prevent this, uru should use absolute paths to a directory it controls in place of the relative _U1_
and _U2_
markers. (E.g. /path/to/uru/dummy/_U1_
and /path/to/uru/dummy/_U2_
instead of _U1_
and _U2_
.)
For more discussion on this, see Is it safe to add . to my PATH? How come? on StackExchange. All the same concerns there apply to this case.
Comments (20)
-
repo owner -
reporter The difference with that case is that it requires the attacker to have the ability to plant the malicious executable at a specific path in the user's home directory, instead of just anywhere the user might cd to.
If I add an absolute directory like
/home/me/bin
to the front of my PATH, I can easily make sure that only I have write access to that directory, not every user on the system, and I can avoid placing untrusted files in that directory.With a relative path though, I have to trust literally every directory I cd to to not contain malicious code.
Imagine I download a tar file from the internet with some cool cat pictures in it, and extract it to
~/downloads
. Then Icd
to that directory and runls
to see what photos I have. If a relative directory is on my PATH, I could easily get pwned just by doing that. If instead I used an absolute directory in my PATH, I won't get pwned unless I untarred those cat photos to, for example,/home/me/bin
, which would be rather stupid of me, especially given that I'm fully aware that/home/me/bin
is on my PATH. -
repo owner Multiple scenario's exist, including the following relevant to uru's current PATH behavior:
- Your system gets pawned - uru's behavior is the least of your worries in this game over scenario.
- Attacker convinces you to run, with privileges, a malicious exe - another variant of (1) with uru's behavior essentially a don't care.
- Attacker convinces you to run a malicious exe - the exe runs with your privileges and can do anything you can do, including tweaking your PATH, creating subdirs in $HOME, downloading payloads into newly created subdirs, etc.
Potential security concerns are not fixed If uru switches to using absolute PATH markers. In fact, the attack surface may be larger. In that case, a malicious exe would be usable (via short name) from any location in your filesystem. With uru's current behavior, the malicious exe is usable (via short name) from the parent dir of the "fake" relative dir when relative PATH markers are used.
The entire relative vs. absolute PATH marker distinction may be meaningless. If an attacker who's written a piece of malware that can create dirs, determine its current location, download, and do other nasty things, one should assume the attacker will not be slowed down by either absolute or relative PATH components.
I don't see how changing uru's current relative PATH markers to absolute paths meaningfully enhances security.
-
reporter - attached archive.tar
I already presented a scenario in my previous comment that falls into none of those three categories you mentioned, yet still allows an attacker to execute malicious code on your system.
tar
files are not executables, and I don't have to "run" a tar file in order to extract it. Yet, as things are,cd
ing to a directory I just extracted from a tar file and then running any common system command while uru is active could easily result in my computer being compromised.To be clear, let me explain the scenario I previously described in more detail:
- You download a tar file (such as the one I attached to this comment) from the internet:
wget https://bitbucket.org/jonforums/uru/issues/attachments/90/jonforums/uru/1471359926.9/90/archive.tar
- You extract the tar file to somewhere perfectly reasonable, a directory not on your PATH:
tar -xf archive.tar
Note that you are not executing the tar file or anything in it, just extracting it. - You cd into the place you extracted the tar file to, then try to look at (not execute) the contents of one of the files you just extracted:
cat cat_this_file.txt
- Oops. In addition to
cat_this_file.txt
, that tar file also contained an executable file_U1_/cat
that does something malicious. You just got compromised. Note that you never intentionally "ran" anything from that archive, you were just casually inspecting its contents.
And that's just one possible scenario. More generally, anytime you
cd
to a directory of files whose contents might be controlled by an attacker (a mounted network drive, another user's home directory on the same computer, etc), you're opening yourself up to unintentionally executing malicious code. Not including relative paths in yourPATH
variable would prevent this. -
reporter - attached archive.tar
Whoops. Used the wrong directory name in my example archive. Fixed.
-
repo owner I understood your original scenario. That said, thank you for explicitly describing it. The details may entice others who view this issue as important to weigh in.
The fundamental problem I have with your recommendation is that, while it appears to solve your particular scenario, it does not generally solve the root concern. Specifically, uru's current behavior of prepending stable, known dirs (absolute or relative) as
PATH
markers can be exploited.Absolute
PATH
markers (e.g. -/home/me/_U1_
or/home/_U1_
or/_U1_
) can minimize the initial attack surface for your tar example, but you are still not immune. Because thePATH
markers are currently fixed, any attacker who convinces you to run a malicious exe can populate those fixed, absolute dirs with a payload exe. Once that malicious payload is on yourPATH
, your tar scenario is not immune from compromise. It becomes a two step attack (reducing the attack surface) rather than the single step of your scenario.I'm still open to changing uru's current behavior. A bit of background...
- I originally used a
:::
or;;;
as the singlePATH
marker. This did not accomomdate user's who prepended thePATH
after using uru to activate a ruby via prependPATH
. - I considered using pseudo random
PATH
markers (hashed current timestamp?), storing their values in the$HOME/.uru/rubies.json
file, and using those values (that change every time you switch rubies) to mungePATH
. The idea being that if the prependedPATH
tokens kept changing, an attacker cannot easily know thePATH
, thereby making compromise much harder. I did not like the extra complexity and corner cases.
Based upon our discussions, I am reconsidering options. For example, can I easily use two
:::
to compartmentalize uru's prependingPATH
behavior? (e.g. -:::/home/me/.gems/bin:/home/me/.rubies/ruby-2.3/bin:::
or even/_U1_
and/_U2_
for both *nix and windows). The goal is to (a) minimize attack surface, (b) ensure acceptable usage performance, and (c) not create new behaviors that can be exploited. - I originally used a
-
reporter I'm not really all that concerned about a scenario where an attacker has already convinced you to run a malicious exe. In such a scenario you are already compromised (rule 1 of the 10 immutable laws of security) and the attacker gains nothing from placing more malicious executables on your PATH.
And even if they did want to override system executables with their own applications, they could easily do so by changing your
~/.profile
or~/.bashrc
to put any directory they want on your PATH. No need to hijack any directory used by uru.I would not recommend using
:::
as a delimiter, as many systems interpret an empty value between two:
characters as equivalent to having.
on your path, which presents a very similar problem as a relative directory like_U1_
./_U1_
and/_U2_
seem fine, so long as we can be certain other users aren't able to create those directories. On Linux it seems like only root can do that, which is fine, but I'm uncertain about Windows. (I'm pretty sure normal users can write to the root of the C drive.) I'd suggest~/_U1_
and~/_U2_
as the best alternative. It's simple, and points to a directory that only the current user should have write access to on all systems. -
repo owner I don't currently see a way to completely solve this scenario, but I can minimize the attack surface by using
/_U1_
and/_U2_
as thePATH
delimiters.Try the v0.8.3.b1 test version now available at the downloads page and confirm that it (a) fixes your tar scenario, and (b) still behaves correctly in your other scenarios.
Simply back up your existing
uru_rt
and extract the new version to the previous location. -
reporter Yes, that resolves the problem for me. It also looks like git bash on Windows uses
C:\Program Files\Git
as/
, so that directory should be safe from modification from other users on the same system too. -
repo owner Great. The fix is not currently working in my git bash on windows, so the v0.8.3 release will be delayed until I root cause.
-
repo owner -
assigned issue to
-
assigned issue to
-
reporter Okay, let me know if you need my help with anything else related to this fix.
-
repo owner Using
git-bash.exe
from Git for Windows v2.9.3.2 on Win8.1 x64, I get the following incorrect behavior.Uru test version
0.8.3.b1
adds the/_U1_:...:/_U2_
PATH hunk correctly but (a) a followinguru ls
does not indicate which ruby was added to PATH, and (b) uru does not appear able to remove the PATH hunk correctly whenuru nil
is executed or when uru attempts to switch to another ruby.Jon@BLACK MINGW64 ~/Documents $ git --version git version 2.9.3.windows.2 Jon@BLACK MINGW64 ~/Documents $ uru ver uru v0.8.3.b1 [windows/386 go1.7] Jon@BLACK MINGW64 ~/Documents $ uru ls 226p369-x32 : ruby 2.2.6p369 (2016-08-16 revision 55943) [i386-mingw32] 232p181-x32 : ruby 2.3.2p181 (2016-08-28 revision 56022) [i386-mingw32] jruby : jruby 9.1.2.0 (2.3.0) 2016-05-26 7357c8f Java HotSpot(TM) 64-Bit... Jon@BLACK MINGW64 ~/Documents $ uru 232 ---> now using ruby 2.3.2-p181 tagged as `232p181-x32` Jon@BLACK MINGW64 ~/Documents $ echo $PATH /_U1_:/C/Apps/rubies/ruby-2.3/bin:/_U2_:/C/Users/Jon/bin:/C/Apps/git/mingw64/bin:/C/Apps/git/usr/local/bin:/C/Apps/git/usr/bin:/C/Apps/git/usr/bin:/C/Apps/git/mingw64/bin:/C/Apps/git/usr/bin:/C/Users/Jon/bin:/C/Windows/system32:/C/Windows:/C/Windows/System32/Wbem:/C/Windows/System32/WindowsPowerShell/v1.0:/C/ProgramData/chocolatey/bin:/C/tools:/C/Apps/git/cmd:/C/Apps/Mercurial:/C/Program Files/Java/jdk1.8.0_102/bin:/C/Apps/git/usr/bin/vendor_perl:/C/Apps/git/usr/bin/core_perl Jon@BLACK MINGW64 ~/Documents $ uru ls 226p369-x32 : ruby 2.2.6p369 (2016-08-16 revision 55943) [i386-mingw32] 232p181-x32 : ruby 2.3.2p181 (2016-08-28 revision 56022) [i386-mingw32] jruby : jruby 9.1.2.0 (2.3.0) 2016-05-26 7357c8f Java HotSpot(TM) 64-Bit... Jon@BLACK MINGW64 ~/Documents $ ruby --version ruby 2.3.2p181 (2016-08-28 revision 56022) [i386-mingw32] Jon@BLACK MINGW64 ~/Documents $ uru nil Jon@BLACK MINGW64 ~/Documents $ echo $PATH /_U1_:/C/Apps/rubies/ruby-2.3/bin:/_U2_:/C/Users/Jon/bin:/C/Apps/git/mingw64/bin:/C/Apps/git/usr/local/bin:/C/Apps/git/usr/bin:/C/Apps/git/usr/bin:/C/Apps/git/mingw64/bin:/C/Apps/git/usr/bin:/C/Users/Jon/bin:/C/Windows/system32:/C/Windows:/C/Windows/System32/Wbem:/C/Windows/System32/WindowsPowerShell/v1.0:/C/ProgramData/chocolatey/bin:/C/tools:/C/Apps/git/cmd:/C/Apps/Mercurial:/C/Program Files/Java/jdk1.8.0_102/bin:/C/Apps/git/usr/bin/vendor_perl:/C/Apps/git/usr/bin/core_perl Jon@BLACK MINGW64 ~/Documents $ uru jr ---> now using jruby 9.1.2 tagged as `jruby` Jon@BLACK MINGW64 ~/Documents $ uru ls 226p369-x32 : ruby 2.2.6p369 (2016-08-16 revision 55943) [i386-mingw32] 232p181-x32 : ruby 2.3.2p181 (2016-08-28 revision 56022) [i386-mingw32] jruby : jruby 9.1.2.0 (2.3.0) 2016-05-26 7357c8f Java HotSpot(TM) 64-Bit... Jon@BLACK MINGW64 ~/Documents $ echo $PATH /_U1_:/C/Apps/rubies/jruby/bin:/_U2_:/C/Apps/git/_U1_:/C/Apps/rubies/ruby-2.3/bin:/C/Apps/git/_U2_:/C/Users/Jon/bin:/C/Apps/git/mingw64/bin:/C/Apps/git/usr/local/bin:/C/Apps/git/usr/bin:/C/Apps/git/usr/bin:/C/Apps/git/mingw64/bin:/C/Apps/git/usr/bin:/C/Users/Jon/bin:/C/Windows/system32:/C/Windows:/C/Windows/System32/Wbem:/C/Windows/System32/WindowsPowerShell/v1.0:/C/ProgramData/chocolatey/bin:/C/tools:/C/Apps/git/cmd:/C/Apps/Mercurial:/C/Program Files/Java/jdk1.8.0_102/bin:/C/Apps/git/usr/bin/vendor_perl:/C/Apps/git/usr/bin/core_perl Jon@BLACK MINGW64 ~/Documents $ jruby --version jruby 9.1.2.0 (2.3.0) 2016-05-26 7357c8f Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [mswin32-x86_64]
-
reporter Confirmed; I'm seeing the same issue. I wonder if that might be because git bash is presenting a different value of the PATH to uru than what git bash shows. Unix-style paths like
/bin
don't really exist on Windows, so git bash is probably translating that into something more "windowsy" before passing it to uru.For example:
$ uru 223 ---> now using ruby 2.2.3-p173 tagged as `223p173` $ echo $PATH /_U1_:/C/Ruby22-x64/bin:/_U2_:... $ ruby -e 'puts ENV["PATH"]' C:\Program Files\Git\_U1_;C:\Ruby22-x64\bin;C:\Program Files\Git\_U2;...
-
repo owner Thanks for checking, I was speculating the same thing re: git bash (aka msys2 cygwin fork) behavior.
That said, I've first got to spelunk the uru chunk removal code for bad assumptions/coding.
-
repo owner @Ajedi32 given msys2's munging of absolute PATHs as you've shown and I've documented in
#92, what do you think of this solution:...before adding
_U1_
and_U2_
relative canaries to PATH,uru
first checks for the presence of those relative dirs. If one exists, uru immediately exists with a useful error message, refusing to add_U1_
and_U2_
to PATH? -
reporter Assuming you're only checking when
uru
is first activated, that's not a secure solution since merely changing directories could change whether_U1_
and_U2_
exist, by virtue of the fact that they're relative paths. In particular, the scenario I outlined in my previous comment would not be prevented by that change.My recommendation would be to use a known absolute path for
_U1_
and_U2_
; maybe the same path uru is installed in. Something like"$(dirname `which uru_rt`)/_U1_"
and"$(dirname `which uru_rt`)/_U2_"
. The assumption being that anyone who can write to that directory would already have the ability to replaceuru_rt
with a malicious executable, and that users would be smart enough to not add untrusted executables to a location they know is on their PATH. -
repo owner @Ajedi32 I really like your dynamic canary idea, and have implemented a simpler variant in the new
0.8.3.rc1
downloads.They work for me on Win8.1 x64, and git-bash from GfW v2.10.2 x64....not yet tested on Ubuntu 16.10 or Fedora 24 x64. It's untested on OSX as I don't use that platform anymore.
-
repo owner - changed status to closed
Fix weakness with PATH canaries. Closes
#90,#92Uru's use of relative PATH canaries
_U1_
and_U2_
to sandbox PATH to enable easy activation and deactivation of registered rubies was a security weakness. This commit minimizes that weakness by using absolute PATH canaries/_U1_
and/_U2_
in Windows, Linux, and OSX environments. In MSYS2-based systems on Windows such as git-bash,U:\_U1_
andU:\_U2_
are used.→ <<cset cf4751fec569>>
-
reporter Thanks, I just tried the latest release candidate. Seems to have worked...
- Log in to comment
Using absolute PATH markers does not appear to solve your scenario.
For example, try something similar to the following after adding a local
bin
dir (e.g. -/home/you/bin
) to your PATH:It doesn't appear to matter whether an absolute path or relative
_U1_
path component is appended to PATH. In either case, the attacker could create the fake dir and drop the malicious exe in that dir. Regardless of whether the attacker pawnd your system or tricked you into running a script, the result is the same. You are in trouble because the malicious exe (appended to your PATH via either an absolute or relative path) now overide's a system command.