LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Security (http://www.linuxquestions.org/questions/linux-security-4/)
-   -   PATH, functions and security. Bash scripting best practices. (http://www.linuxquestions.org/questions/linux-security-4/path-functions-and-security-bash-scripting-best-practices-903048/)

KuimFieg 09-14-2011 03:57 PM

PATH, functions and security. Bash scripting best practices.
 
Hello all.
I've been using linux for a few years and really enjoy it. I'm a self learner.
I have written and am using quite a few home made scripts for different purposes. I sometimes come across bash scripts where commands are called via there full paths only.

For instance "ls" becomes :
Code:

LS="/bin/ls"
$LS /whatever/folder

I was wondering if there was a valid reason for this and what is it in detail. I guess the idea is to prevent PATH override but if a potential attacker has the ability to mess with you PATH variable, your system is already compromised so is this really worth it?

Further more, if this is really on issue, what about overriding commands with functions?

For example, this is what I get on Debian Squeeze:
Code:

user@sys:~$ cp --version
 cp (GNU coreutils) 8.5
 Copyright (C) 2010 Free Software Foundation, Inc.
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.

 Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering.

 user@sys:~$ cp() { echo "overriden"; }
 user@sys:~$ cp mbox mbox.bak
 overriden

Or worse :

Code:

user@sys:~$ /bin/ls --version
 ls (GNU coreutils) 8.5
 Copyright (C) 2010 Free Software Foundation, Inc.
 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
 This is free software: you are free to change and redistribute it.
 There is NO WARRANTY, to the extent permitted by law.
 
 Written by Richard M. Stallman and David MacKenzie.

 user@sys:~$ /bin/ls() { echo "cracked you!"; }
 /bin/ls() { echo "cracked you"; }
 user@sys:~$ /bin/ls -l
 cracked you

So is this really something to keep in mind when writing scripts. What are the "best practices"?
I've never seen any recommendations on that matter.

As I said my view is if a potential attacker can do this sort of thing, it's already too late. What do you think? Am I missing something ?

macemoneta 09-14-2011 04:11 PM

Full paths aren't to protect against attacks, they're used to protect against users. :)

For example, if a user creates a script or alias for 'ls', but hard-codes an option or number of parameters, another script invoking the user's 'ls' may fail or return incorrect results.

SL00b 09-14-2011 04:16 PM

Well, I'm not going to comment on industry practices, but I know why I use fully-qualified paths.

1) When I'm going to run my script from cron or init.d. Since these won't be launched by my shell, I can't presume my path will be valid. If I code the fully-qualified path, I know the script will work.

2) When I want the script to run against the correct directories no matter where I happen to be in the tree. This would be for commands that aren't in my path by design, input or output files, etc.

In other words, it's all about functionality. It has nothing to do with security.

KuimFieg 09-14-2011 04:50 PM

@macemoneta, ok I had not thought about aliases but I've just tested this on my system and PATH has precedence over user aliases.

@SL00b, PATH is defined /etc/crontab on my system, so this wouldn't be an issue. I realise one can also redefine the PATH variable at the beginning of a script.

I recall reading a while ago (can't remember where/who/what) that certain sysadmins wouldn't set PATH in order to prevent command overrides at the command prompt and forcing the users to invoke programs/scripts only via full paths. I guess there is a certain school of thought there, but thinking about it I realised this sort of practice is ineffective anyways.

Reuti 09-15-2011 04:52 AM

Quote:

Originally Posted by macemoneta (Post 4471848)
Full paths aren't to protect against attacks, they're used to protect against users. :)

Yep, and to have an option to adjust a script to the actual environment. Assume you have a script having:
Code:

MAKE=make
ECHO=echo

on AIX but you need the gmake instead, as the original make is different on AIX. In addition you don’t want any output during the build process. You can adjust:
Code:

MAKE=gmake
ECHO=:

Nevertheless, when you read the script you know exactly what the author intended to do when you see $MAKE and $ECHO. It’s more readable than having $PGM1, $PGM2 there.

Trickie 09-16-2011 05:54 AM

Some commands, using the same name, exist both as bash built-in commands, and standalone tools which usually reside in /usr/bin; "echo" is one example of this. One may prefer, for various reasons, *not* to use the bash built-in, in which case the absolute path name must be used in order to differentiate between the two.

Richard

zek 09-17-2011 02:17 PM

Note however that the standalone tool will execute much slower than the built-in. Be mindful when writing loops.

Code:

$ time for i in {1..5000} ; do /bin/echo > /dev/null ; done

real        0m8.465s
user        0m1.762s
sys        0m6.676s
$ time for i in {1..5000} ; do echo > /dev/null ; done

real        0m0.169s
user        0m0.105s
sys        0m0.064s


LQParsons 09-19-2011 08:34 AM

path to command to override other alias
 
Hi.
A common reason, in addition to the other ones given, to create a 'full path' in your script is sometimes a system administrator will have already redefined a command in a system .rc
For instance, said person thinks that removing a file should always be confirmed, so in a system file redefines for you:
Code:

  $ alias rm='rm -i'
now you, in your script, want to remove a file, so you do the normal
Code:

 
$ rm filename

#
# and get instead ...
#
$ rm -i

By defining commands in your shell script, you get what you ask for.

btw, when I think certain commands should not be used, I make a new command name, such as
Code:

$ alias rmi='rm -i'
that way I get what I want and I don't screw up folk who disagree with me.

Enjoy.
-doug

chrism01 09-19-2011 09:01 PM

Although all processes have an idea of PATH, the content may not be what you want eg cron deliberately sets a minimal or non-path, because it can be invoked by any user for any purpose, so the less 'assumptions' the better.
Note also that on some systems you may have multiple 'versions' of a cmd eg on Solaris there are binaries derived from Unix System V and some from the UCB (Berkely; see *BSD systems).
cron is a basic tool on all *nix.
As above, aliases come into play, as do symbolic links ....

One thing I always do for prodn scripts is to specify the shebang line eg '#!/bin/bash' as otherwise it will be called via the default shell of whatever env it happens to be in...

Reuti 09-20-2011 04:00 AM

Quote:

Originally Posted by chrism01 (Post 4476664)
One thing I always do for prodn scripts is to specify the shebang line eg '#!/bin/bash' as otherwise it will be called via the default shell of whatever env it happens to be in...

Good note: where is the default shell defined? Even when I change my interactive shell with chsh to be csh and login again, scripts are still interpreted by the bash on openSUSE (ones without the shebang). Where is it defined?

archtoad6 09-20-2011 09:25 AM

KuimFieg & LQParsons,

Welcome to LQ. I hope your time here helps you as much as mine has helped me.

In order to help us better help you, please put code, command line output, config files, etc. inside [CODE] tags, aka "Code:" blocks.
In case your're not familiar with them, there are 2 ways to generate "Code:" tags:
  1. You can simply type them yourself -- "[code] ... [/code]". (They are not case sensitive.)

  2. You can also click on the '#' icon above the text entry window. If you highlight the code, command line output, config files, etc. before you click the '#' icon, your code will get put inside a "Code:" block. The '#' icon is available when you start your post by clicking the "Post Reply" button or use the "Go Advanced" button under the Quick Reply window; it is not currently available in the Quick Reply window itself.

The [CODE] tags will make your posts easier to read, & that will get you more, faster, better answers. -- Again, help us help you.
BTW, You can edit your post(s) to do this retroactively. Please do so soon.

Thank you, & for the 2nd time, welcome.

KuimFieg 09-22-2011 04:16 PM

Thanks for all the answers. I wasn't really aware of bash built-ins being faster.

Quote:

Originally Posted by LQParsons
For instance, said person thinks that removing a file should always be confirmed, so in a system file redefines for you: ...
By defining commands in your shell script, you get what you ask for.

I don't think this is correct since:
Code:

alias rm='rm -i' && echo -e '#!/bin/bash -x\nrm "$1"' > rm_test.sh && chmod 755 rm_test.sh && touch remove_me && ./rm_test.sh remove_me
Returns : "+ rm remove_me". It seems aliases are accessible only via interactive shells

Quote:

Originally Posted by Reuti (Post 4476953)
Good note: where is the default shell defined?

If you have a local account:
Code:

user@sys:~# grep $(id -un) /etc/passwd
user:x:1000:1000:Gecos:/home/user:/bin/bash


Reuti 09-22-2011 04:58 PM

Quote:

Originally Posted by KuimFieg (Post 4479571)
Code:

user@sys:~# grep $(id -un) /etc/passwd
user:x:1000:1000:Gecos:/home/user:/bin/bash


This is the login shell, but not the one used to interpret the scripts. Example:
Code:

$ ssh pc15370
Last login: Thu Sep 22 23:27:44 2011 from blabla
Have a lot of fun...
reuti@pc15370:~> getent passwd reuti
reuti:x:1000:100:Reuti:/home/reuti:/bin/bash
reuti@pc15370:~> chsh
Changing login shell for reuti.
Password:
Enter the new value, or press return for the default.
        Login Shell [/bin/bash]: /bin/tcsh
Shell changed.
reuti@pc15370:~> getent passwd reuti
reuti:x:1000:100:Reuti:/home/reuti:/bin/tcsh
reuti@pc15370:~> exit
logout
Connection to pc15370 closed.
$ ssh pc15370
Last login: Thu Sep 22 23:27:54 2011 from blabla
Have a lot of fun...
/home/reuti> echo $SHELL
/bin/tcsh
/home/reuti> cat where.sh
pstree -u reuti
/home/reuti> chmod +x where.sh
/home/reuti> ./where.sh
sshd───tcsh───sh───pstree

There is a sh popping up in the process chain. So the question is still there: if there is no shebang, where is it defined which shell will be used to interpet the script?

While I think about it: the shell will fork, the forked process will call execvp or alike. And indeed there inside they use the defined _PATH_BSHELL constant (defined in paths.h as /bin/sh). So it’s hardcoded in glibc.

I leave it here, in case someone wonders about it too.

chrism01 09-23-2011 12:39 AM

Given that I work on various flavours of *nix, I just take the 'practical' definition ie the default is whatever you get if you DON'T explicitly define it yourself :)
Basically never 'assume' ...
https://secure.wikimedia.org/wikiped...Don%27t_assume

Also, others may have a hand in setting the env where your script ends up running.


All times are GMT -5. The time now is 01:15 AM.