3

You know this sudo stuff:

Defaults env_reset

which makes environment injection impossible. I was wandering if this functionality can be obtained from bash script directly, 'from inside'?

At least part of it can, that is for sure. Example:

#!/usr/bin/env php
<?php
//...

// sanitizes $PATH
putenv("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"); 

// unsets $LD_LIBRARY_PATH, as it should be in Ubuntu
putenv('LD_LIBRARY_PATH');
//...

Can we do env_reset in running script like sudo does and how?

EDIT:

I'm not looking for the way to do it 'from outside' like env -i command but from inside of script itself. My intention is to ensure security no matter who (what user) and how(under which circumstances, i.e. env variables) runs it.

  • Possible duplicate of How to run a program in a clean environment in bash? – Kusalananda Feb 2 '17 at 14:45
  • @Kusalananda why duplicate? I'm not after empty environment nor the way to do it 'from outside' like env -i. – Miloš Đakonović Feb 2 '17 at 14:50
  • the php script might be a little distracting, if you're asking about bash; the syntax for clearing an environment will differ among scripting languages. For reference, sudo's environment handling – Jeff Schaller Feb 2 '17 at 15:00
  • What are the security concerns? If you want to be sure of getting a clean environment, then env -i bash --norc --noprofile will give you that. Apart from that, just list the environment variables and unset them, one by one. – Kusalananda Feb 2 '17 at 15:14
5

bash itself uses some environment variables. By the time bash is started and ready to interpret its first command, it's already too late, a malicious environment can have had bash do damage already.

You need the environment to have been sanitized before bash is called. You can wipe the environment with the clearenv() C function on most systems or you could just call execve() on your script and pass an empty list in the envp parameter.

Even with a script that contains:

#! /bin/bash -
:

(: being a special builtin), if the environment contains SHELLOPTS=xtrace PS4='$(reboot)', the reboot command will be invoked upon :.

If bash is dynamically linked, LD_PRELOAD/LD_LIBRARY_PATH can make bash run arbitrary code as soon as it's invoked.

bash also honours the locale's charset for its parsing, so with LOCPATH and LC_* variables, you can have even the #! /bin/bash - line invoke arbitrary code (by making #!/bina characters blanks for instance).

See also:

env SHELLOPTS=noexec any-bash-script

That stops bash from doing anything.

Those are just a few examples.

Also note that the environment variables are not the only things that a command inherits on startup and that may affect its behaviour (like arguments, umask, limits, current working directory, open file descriptors, signal disposition, controlling terminal...).

1

You can find your exports with export -p or simply export, and replace the declare -x with declare +x on each line to unexport it:

eval "$(export|sed s/-/+/)"

If you put this at the beginning of your script, then no environment variables will be passed through to the programs it executes unless you explicitly export them yourself. You'll probably want to export locale and TZ variables, and TERM, and more...

  • No, even eval "$(export)" is an arbitrary command injection vulnerability. Try env -i '$(reboot)=x' bash -c export for instance. – Stéphane Chazelas Feb 2 '17 at 17:49
  • That part was fixed in bash-4.4 though. – Stéphane Chazelas Feb 2 '17 at 17:55
  • My bash correctly quotes its declare -x output, so that's not an issue. I do like the PS4 attack in your answer, @Stéphane - very clever! – Toby Speight Feb 2 '17 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.