Re: bash - safely pass untrusted strings?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



Benjamin Smith wrote:
On Tuesday 26 February 2008, Les Mikesell wrote:
WHY THE @!#! NOT?!?!?
The shell is 'supposed' to be run by a user that is allowed to run any command he wants, and permission/trust issues are handled by the login/authentication process that happens before you get to the shell. If you give the shell a bad command under your own account, it's not supposed to second guess what you wanted.

I'm not asking for this. I'm only asking for the option to be able to trust that a parameter is... a parameter. EG:

You can, but you have to know how many times shells will parse it. One layer of quoting is removed each time. Things inside single quotes are literal, double quotes still do variable expansion.


file: script1.sh #! /bin/bash script2.sh $1 exit 0; file: script2.sh #! /bin/bash echo $1; $ script1.sh "this\ parameter"; I get output of "this"! script2 gets two parameters! I want a way for 1 parameter to STAY 1 parameter upon request, so that script2.sh would output "this parameter", like

One layer of quotes for each time it is parsed... The first is on the initial command line, so if you want to hold it together, put double quotes around "$1".


file:script1.sh #! /bin/bash PassToShell2=escapethis $1; script2.sh $PassToShell; exit 0;
Bash is used, extensively in many cases, to deal with untrusted data.
Why?

How about an installer script? How about a magical script copied from TLDP to rename all files in pwd?

These things run with the permissions of the user running them. Why should they be concerned about that person giving them untrusted embedded commands that they could just as easily run directly?

This can include random file names in user home directories, parameters on various scripts, etc. It's highly sensitive to being passed characters that have, over the past NN years, resulted in quite a number of security holes and problems.
If it hurts, don't do it. Build your own argument list and exec programs directly if you want to avoid shell command line parsing.

So, I'm supposed to know the contents of a user's home directory? And code for these in advance?

Code so you don't let the shell parse their names. It doesn't have to if you just want to hand them to some other program.

Yet there exists NO MECHANISM for simply ensuring that a given argument is
an
escaped string?
What does that mean? If you can define it you can make it happen, but who knows what characters at what depth of quoting will have some special meaning?

Can I define it? Thought I did that already:
http://us.php.net/manual/en/function.escapeshellarg.php

Can you pass that via ssh to some other system(s) and have i/o redirection or variable expansions happen in the right places?

Or its perl equivalent: http://search.cpan.org/~gaas/URI-1.35/URI/Escape.pm

See how I'd like to see it in implementation in above example, "passToShell2"

What's the point? If you are in the shell already it's too late. If you are in some other program and don't want shell metacharacter processing to happen, don't feed it to the shell in the first place.

How many "homebrew" ISP or hosting administration scripts could be
compromised
by simply putting a file in your home directory called ";rm -rf /" ?
Probably none that are still in business.

Google "bash howto" for lots of vulnerable and problematic examples. Here's a beaut that fails if you have a file called "-a" in the pwd, see "File re-namer". It's a renamer that doesn't, if the file contains any spaces, dashes, etc.

There are any number of ways to do things wrong. I don't need to look up more of them.


http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-12.html#ss12.1

Here's what I get:
mv: invalid option -- a
Try `mv --help' for more information.

Most programs accept -- as an option to end option parsing. But if you don't want this effect, don't start your filenames with a -.


Or with a file with a space: echo "blah" > "d"; echo "blah" > "d foo"; The TLDP's example doesn't move file "d foo". I get: mv: cannot stat `d': No such file or directory
mv: cannot stat `foo': No such file or directory

If you don't want the shell to split on spaces you can tell it not to. Or you can quote filenames correctly. Or not put spaces in filenames.

So I ask again: This doesn't strike you as fundamentally borkeD? The emperor wears no clothes!

No, it works the way I'd want it to work most of the time. And for the exceptions, you use quotes in the right places the right number of times.

This doesn't strike you as fundamentally borkeD?
No, if you stop bad things from happening, you'll also stop good things.

Yes. But you don't have to stop the good things.

You don't like the fact that the shell does things like splitting on white space?


I think the *OPTION* of saying "parameter 1 is STILL parameter 1" is a good thing. If you want to leave things be, so be it. See my above example.

You can't do that without knowing at what point you want it to stop being an opaque blob.

The problem is that you aren't using the shell as intended. If you run it under your own user id, it does exactly what you tell it to do and there is no element of trust involved.

The problem, as I see it, is that the shell provides access variables without any means of preserving them as variables across calls and incantations.

It does.  You just have to know when it should and when it shouldn't

Errr what??? Php has about the worst security history of any program around.

Thanks for confusing the issue with a red herring. Or should I ignore the buggy and probably vulnerable TLDP example above? Maybe a google search for "bash escape vulnerability" might illuminate the issue I speak of?

No, you should just learn to use quotes. Or bypass shell processing.

This just blows my mind....
What would you like your computer to prevent you from doing to yourself?

I hate to belabor it: give me the OPTION to trust that I can keep a single parameter as a single parameter across incantations and calls. If I'm looping thru a listing files, I should be able to trust that my $FILENAME variable contains the name of... a file!

A file can be be named pretty much anything, so what does that mean? All you can do is make sure it is quoted as many times as you let the shell parse it.

If I want to pass parameter 1 of my script to another script, that other script should be ABLE get my parameter 1 as... parameter 1!

OK - quote it.

A simple call that lets me take a string and get a passable parameter would suffice.

But in shell, such a call would parse whatever you give it - and the parsing would follow the same rules as every other parsing operation...

You want to apply scripts that break with a space in a file name? Great. Have at it. I don't want to detract from your ability to make an alphabet soup of your directories with borken examples from TLDP, and all the goodness that implies to you. But I think admins the world over would like it if a simple, one-liner could be added to ensure that a single parameter remains a single parameter!

Am I being unclear?

You want the shell to not be the shell, I think. Everything the shell does, it does the same way, which is why we like it in the first place. You can't tell it to do something without parsing the command and its arguments.

--
  Les Mikesell
    lesmikesell@xxxxxxxxx
_______________________________________________
CentOS mailing list
CentOS@xxxxxxxxxx
http://lists.centos.org/mailman/listinfo/centos

[Index of Archives]     [CentOS]     [CentOS Announce]     [CentOS Development]     [CentOS ARM Devel]     [CentOS Docs]     [CentOS Virtualization]     [Carrier Grade Linux]     [Linux Media]     [Asterisk]     [DCCP]     [Netdev]     [Xorg]     [Linux USB]
  Powered by Linux