PATH, functions and security. Bash scripting best practices.
Linux - SecurityThis forum is for all security related questions.
Questions, tips, system compromises, firewalls, etc. are all included here.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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 ?
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.
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.
@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.
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.
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.
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
Location: North of Boston, Mass (North Shore/Cape Ann)
Distribution: CentOS 7.0 (and kvm/qemu)
Posts: 91
Rep:
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
Last edited by LQParsons; 09-21-2011 at 09:44 AM.
Reason: correcting formatting errors
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...
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?
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:
You can simply type them yourself -- "[code] ... [/code]". (They are not case sensitive.)
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.
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.
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.
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.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.