ârun any command which will pass untrusted data to commands which interpret arguments as commandsâ

Clash Royale CLAN TAG#URR8PPP
up vote
17
down vote
favorite
From findutils' manual:
For example constructs such as these two commands
# risky
find -exec sh -c "something " ;
find -execdir sh -c "something " ;
are very dangerous. The reason for this is that the âÂÂâ is expanded
to a filename which might contain a semicolon or other characters
special to the shell. If for example someone creates the file
/tmp/foo; rm -rf $HOMEthen the two commands above could delete
someoneâÂÂs home directory.
So for this reason do not run any command which will pass untrusted
data (such as the names of fi les) to commands which interpret
arguments as commands to be further interpreted (for example âÂÂshâÂÂ).
In the case of the shell, there is a clever workaround for this
problem:# safer
find -exec sh -c 'something "$@"' sh ;
find -execdir sh -c 'something "$@"' sh ;
This approach is not guaranteed to avoid every problem, but it is much
safer than substituting data of an attackerâÂÂs choice into the text of
a shell command.
- Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris
unquoted and therefore not treated as a single string? In the solution
find -exec sh -c 'something "$@"' sh ;,first
is replaced, but sinceis unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;","rm","-rf", and"$HOME"?why is
not escaped or quoted?
- Could you give other examples (still with
sh -c, or without it if
applicable; with or withoutfindwhich may be not necessary) where the same kind of problem and solution apply, and
which are minimal examples so that we can focus on the problem and
solution with little distraction as possible? See Ways to provide arguments to a command executed by `bash -c`
Thanks.
shell
add a comment |Â
up vote
17
down vote
favorite
From findutils' manual:
For example constructs such as these two commands
# risky
find -exec sh -c "something " ;
find -execdir sh -c "something " ;
are very dangerous. The reason for this is that the âÂÂâ is expanded
to a filename which might contain a semicolon or other characters
special to the shell. If for example someone creates the file
/tmp/foo; rm -rf $HOMEthen the two commands above could delete
someoneâÂÂs home directory.
So for this reason do not run any command which will pass untrusted
data (such as the names of fi les) to commands which interpret
arguments as commands to be further interpreted (for example âÂÂshâÂÂ).
In the case of the shell, there is a clever workaround for this
problem:# safer
find -exec sh -c 'something "$@"' sh ;
find -execdir sh -c 'something "$@"' sh ;
This approach is not guaranteed to avoid every problem, but it is much
safer than substituting data of an attackerâÂÂs choice into the text of
a shell command.
- Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris
unquoted and therefore not treated as a single string? In the solution
find -exec sh -c 'something "$@"' sh ;,first
is replaced, but sinceis unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;","rm","-rf", and"$HOME"?why is
not escaped or quoted?
- Could you give other examples (still with
sh -c, or without it if
applicable; with or withoutfindwhich may be not necessary) where the same kind of problem and solution apply, and
which are minimal examples so that we can focus on the problem and
solution with little distraction as possible? See Ways to provide arguments to a command executed by `bash -c`
Thanks.
shell
Related: unix.stackexchange.com/questions/156008
â Kusalananda
Jun 8 at 7:36
add a comment |Â
up vote
17
down vote
favorite
up vote
17
down vote
favorite
From findutils' manual:
For example constructs such as these two commands
# risky
find -exec sh -c "something " ;
find -execdir sh -c "something " ;
are very dangerous. The reason for this is that the âÂÂâ is expanded
to a filename which might contain a semicolon or other characters
special to the shell. If for example someone creates the file
/tmp/foo; rm -rf $HOMEthen the two commands above could delete
someoneâÂÂs home directory.
So for this reason do not run any command which will pass untrusted
data (such as the names of fi les) to commands which interpret
arguments as commands to be further interpreted (for example âÂÂshâÂÂ).
In the case of the shell, there is a clever workaround for this
problem:# safer
find -exec sh -c 'something "$@"' sh ;
find -execdir sh -c 'something "$@"' sh ;
This approach is not guaranteed to avoid every problem, but it is much
safer than substituting data of an attackerâÂÂs choice into the text of
a shell command.
- Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris
unquoted and therefore not treated as a single string? In the solution
find -exec sh -c 'something "$@"' sh ;,first
is replaced, but sinceis unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;","rm","-rf", and"$HOME"?why is
not escaped or quoted?
- Could you give other examples (still with
sh -c, or without it if
applicable; with or withoutfindwhich may be not necessary) where the same kind of problem and solution apply, and
which are minimal examples so that we can focus on the problem and
solution with little distraction as possible? See Ways to provide arguments to a command executed by `bash -c`
Thanks.
shell
From findutils' manual:
For example constructs such as these two commands
# risky
find -exec sh -c "something " ;
find -execdir sh -c "something " ;
are very dangerous. The reason for this is that the âÂÂâ is expanded
to a filename which might contain a semicolon or other characters
special to the shell. If for example someone creates the file
/tmp/foo; rm -rf $HOMEthen the two commands above could delete
someoneâÂÂs home directory.
So for this reason do not run any command which will pass untrusted
data (such as the names of fi les) to commands which interpret
arguments as commands to be further interpreted (for example âÂÂshâÂÂ).
In the case of the shell, there is a clever workaround for this
problem:# safer
find -exec sh -c 'something "$@"' sh ;
find -execdir sh -c 'something "$@"' sh ;
This approach is not guaranteed to avoid every problem, but it is much
safer than substituting data of an attackerâÂÂs choice into the text of
a shell command.
- Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris
unquoted and therefore not treated as a single string? In the solution
find -exec sh -c 'something "$@"' sh ;,first
is replaced, but sinceis unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;","rm","-rf", and"$HOME"?why is
not escaped or quoted?
- Could you give other examples (still with
sh -c, or without it if
applicable; with or withoutfindwhich may be not necessary) where the same kind of problem and solution apply, and
which are minimal examples so that we can focus on the problem and
solution with little distraction as possible? See Ways to provide arguments to a command executed by `bash -c`
Thanks.
shell
edited Jun 7 at 18:24
ilkkachu
47.5k668131
47.5k668131
asked Jun 7 at 14:28
Tim
22.5k61222401
22.5k61222401
Related: unix.stackexchange.com/questions/156008
â Kusalananda
Jun 8 at 7:36
add a comment |Â
Related: unix.stackexchange.com/questions/156008
â Kusalananda
Jun 8 at 7:36
Related: unix.stackexchange.com/questions/156008
â Kusalananda
Jun 8 at 7:36
Related: unix.stackexchange.com/questions/156008
â Kusalananda
Jun 8 at 7:36
add a comment |Â
4 Answers
4
active
oldest
votes
up vote
27
down vote
accepted
This isnâÂÂt really related to quoting, but rather to argument processing.
Consider the risky example:
find -exec sh -c "something " ;
This is parsed by the shell, and split into six words:
find,-exec,sh,-c,something(no quotes any more),;. ThereâÂÂs nothing to expand. The shell runsfindwith those six words as arguments.When
findfinds something to process, sayfoo; rm -rf $HOME, it replaceswithfoo; rm -rf $HOME, and runsshwith the argumentssh,-c, andsomething foo; rm -rf $HOME.shnow sees-c, and as a result parsessomething foo; rm -rf $HOME(the first non-option argument) and executes the result.
Now consider the safer variant:
find -exec sh -c 'something "$@"' sh ;
The shell runs
findwith the argumentsfind,-exec,sh,-c,something "$@",sh,,;.Now when
findfindsfoo; rm -rf $HOME, it replacesagain, and runsshwith the argumentssh,-c,something "$@",sh,foo; rm -rf $HOME.shsees-c, and parsessomething "$@"as the command to run, andshandfoo; rm -rf $HOMEas the positional parameters (starting from$0), expands"$@"tofoo; rm -rf $HOMEas a single value, and runssomethingwith the single argumentfoo; rm -rf $HOME.
You can see this by using printf. Create a new directory, enter it, and run
touch "hello; echo pwned"
Running the first variant as follows
find -exec sh -c "printf "Argument: %sn" " ;
produces
Argument: .
Argument: ./hello
pwned
whereas the second variant, run as
find -exec sh -c 'printf "Argument: %sn" "$@"' sh ;
produces
Argument: .
Argument: ./hello; echo pwned
In the safer variant, why isnot escaped or quoted?
â Tim
Jun 7 at 17:31
It generally doesnâÂÂt need to be quoted; it would only need to be quoted in a shell where it has some other meaning, and I donâÂÂt think thatâÂÂs the case with any of the main shells in use nowadays.
â Stephen Kitt
Jun 7 at 18:19
From gnu.org/software/findutils/manual/html_mono/â¦: "Both of these constructions (;and) need to be escaped (with a âÂÂâÂÂ) or quoted to protect them from expansion by the shell." Do you mean that it is incorrect for bash?
â Tim
Jun 7 at 18:40
2
I mean that it is incorrect for shells in general. See POSIX. That particular statement in thefindutilsmanual dates back to at least 1996... Of course it does no harm to quote, either as''or"", but it isnâÂÂt necessary.
â Stephen Kitt
Jun 7 at 19:11
@Tim You're experiencing a common situation where your intuition isn't yet accounting for the fact that there are two very different types of argument-processing going on here: when/how the shell parses arguments out of a line of text (which is where quoting matters) is different from raw operating system argument passing (where quotes are just regular characters). In the shell commandfind some/path -exec sh -c 'something "$@"' ;there's actually three layers of argument processing/passing, two of the shell variety and one of the basic raw operating system variety.
â mtraceur
Jun 7 at 22:03
 |Â
show 5 more comments
up vote
3
down vote
Part 1:
find just uses text replacement.
Yes, if you did it unquoted, like this:
find . -type f -exec sh -c "echo " ;
and an attacker was able to create a file called ; echo owned, then it would exec
sh -c "echo ; echo owned"
which would result in the shell running echo then echo owned.
But if you added quotes, the attacker could just end your quotes then put the malicious command after it by creating a file called '; echo owned:
find . -type f -exec sh -c "echo ''" ;
which would result in the shell running echo '', echo owned.
(if you swapped the double quotes for single quotes, the attacker could use the other type of quotes too.)
Part 2:
In find -exec sh -c 'something "$@"' sh ;, the is not initially interpreted by the shell, it's executed directly with execve, so adding shell quotes wouldn't help.
find -exec sh -c 'something "$@"' sh "" ;
has no effect, since the shell strips the double quotes before running find.
find -exec sh -c 'something "$@"' sh "''" ;
adds quotes that the shell doesn't treat specially, so in most cases it just means the command won't do what you want.
Having it expand to /tmp/foo;, rm, -rf, $HOME shouldn't be a problem, because those are arguments to something, and something probably doesn't treat its arguments as commands to execute.
Part 3:
I assume similar considerations apply for anything that takes untrusted input and runs it as (part of) a command, for example xargs and parallel.
xargsis only dangerous if-Ior-Jis used. In normal operation it's only appending arguments to the end of the list, just as-exec ... +does.
â Charles Duffy
Jun 7 at 15:55
1
(parallel, by contrast, runs a shell by default without explicit request from the user, increasing the vulnerable surface; this is a matter that's been the subject of much discussion; see unix.stackexchange.com/questions/349483/⦠for an explanation, and the included link to lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html).
â Charles Duffy
Jun 7 at 16:02
@CharlesDuffy You mean "decreasing the vulnerable surface". The attack illustrated by OP does indeed not work by default with GNU Parallel.
â Ole Tange
Jun 8 at 7:22
1
Yes, I know you need it for parity across SSH -- if you didn't spawn a remoteparallel"receiver" process on the other end of any socket, able to do a direct shell-lessexecv. Which is exactly what I would have done, if in your shoes implementing the tool. Having a noninteractive program behave differently based on the current value ofSHELLis hardly least-astonishment.
â Charles Duffy
Jun 8 at 12:07
1
Yes -- I hold that pipes and redirections should be impossible unless the user explicitly starts a shell, at which point they get only the explicit behavior of the shell they explicitly started. If one can expect only what anexecvprovides, that's simpler and less astonishing, and a rule that doesn't change across locations/runtime environments.
â Charles Duffy
Jun 8 at 13:01
 |Â
show 2 more comments
up vote
3
down vote
1. Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris unquoted and therefore not treated as a single string?
In a sense, but quoting cannot help here. The filename that gets replaced in place of can contain any characters, including quotes. Whatever form of quoting was used, the filename could contain the same, and "break out" of the quoting.
2. ... but since
is unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;", "rm", "-rf", and "$HOME"?
No. "$@" expands to the positional parameters, as separate words, and doesn't split them further. Here, is an argument to find in itself, and find passes the current filename also as a distinct argument to sh. It's directly available as a variable in the shell script, it's not processed as a shell command itself.
... why is
not escaped or quoted?
It doesn't need to be, in most shells. If you run fish, it needs to be: fish -c 'echo ' prints an empty line. But it doesn't matter if you quote it, the shell will just remove the quotes.
3. Could you give other examples...
Any time you expand a filename (or another uncontrolled string) as-is inside a string that's taken as some kind of code(*), there's a possibility of arbitrary command execution.
For example, this expands $f directly the Perl code, and will cause problems if a filename contains a double quote. The quote in the filename will end the quote in the Perl code, and the rest of the filename can contain any Perl code:
touch '"; print "HELLO";"'
for f in ./*; do
perl -le "print "size: " . -s "$f""
done
(The filename has to be a bit weird since Perl parses the whole code up front, before running any of it. So we'll have to avoid a parse error.)
While this passes it safely through an argument:
for f in ./*; do
perl -le 'print "size: " . -s $ARGV[0]' "$f"
done
(It doesn't make sense to run another shell directly from a shell, but if you do, it's similar to the find -exec sh ... case)
(* some kind of code includes SQL, so obligatory XKCD: https://xkcd.com/327/ plus explanation:
https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )
add a comment |Â
up vote
1
down vote
Your concern is precisely the reason why GNU Parallel quotes input:
touch "hello; echo pwned"
find . -print0 | parallel -0 printf "Argument: %s\n"
This will not run echo pwned.
It will run a shell, so that if you extend your command, you will not suddenly get a surprise:
# This _could_ be run without spawining a shell
parallel "grep -E 'a|bc' " ::: foo
# This cannot
parallel "grep -E 'a|bc' | wc" ::: foo
For further details on the spawning-a-shell issue see: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell
1
...that said,find . -print0 | xargs -0 printf "Argument: %sn"is just as safe (or rather, moreso, since with-print0one handles filenames with newlines correctly); parallel's quoting is a workaround for a problem that doesn't exist at all when no shell is present.
â Charles Duffy
Jun 8 at 12:05
But as soon as you add| wcto the command you need to jump through hoops to make it safe. GNU Parallel is safe by default.
â Ole Tange
Jun 9 at 14:27
ITYM: it tries to cover for every quirk of the shell language by the complicated process of carefully quoting everything. That's not nearly as safe as properly storing data in variables, not intermixed with code. Now, if it were to automatically convert thatfoo |ÃÂ wcintosh -c 'foo "$1" |ÃÂ wcsh `, that might be different.
â ilkkachu
Jun 10 at 9:00
add a comment |Â
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
27
down vote
accepted
This isnâÂÂt really related to quoting, but rather to argument processing.
Consider the risky example:
find -exec sh -c "something " ;
This is parsed by the shell, and split into six words:
find,-exec,sh,-c,something(no quotes any more),;. ThereâÂÂs nothing to expand. The shell runsfindwith those six words as arguments.When
findfinds something to process, sayfoo; rm -rf $HOME, it replaceswithfoo; rm -rf $HOME, and runsshwith the argumentssh,-c, andsomething foo; rm -rf $HOME.shnow sees-c, and as a result parsessomething foo; rm -rf $HOME(the first non-option argument) and executes the result.
Now consider the safer variant:
find -exec sh -c 'something "$@"' sh ;
The shell runs
findwith the argumentsfind,-exec,sh,-c,something "$@",sh,,;.Now when
findfindsfoo; rm -rf $HOME, it replacesagain, and runsshwith the argumentssh,-c,something "$@",sh,foo; rm -rf $HOME.shsees-c, and parsessomething "$@"as the command to run, andshandfoo; rm -rf $HOMEas the positional parameters (starting from$0), expands"$@"tofoo; rm -rf $HOMEas a single value, and runssomethingwith the single argumentfoo; rm -rf $HOME.
You can see this by using printf. Create a new directory, enter it, and run
touch "hello; echo pwned"
Running the first variant as follows
find -exec sh -c "printf "Argument: %sn" " ;
produces
Argument: .
Argument: ./hello
pwned
whereas the second variant, run as
find -exec sh -c 'printf "Argument: %sn" "$@"' sh ;
produces
Argument: .
Argument: ./hello; echo pwned
In the safer variant, why isnot escaped or quoted?
â Tim
Jun 7 at 17:31
It generally doesnâÂÂt need to be quoted; it would only need to be quoted in a shell where it has some other meaning, and I donâÂÂt think thatâÂÂs the case with any of the main shells in use nowadays.
â Stephen Kitt
Jun 7 at 18:19
From gnu.org/software/findutils/manual/html_mono/â¦: "Both of these constructions (;and) need to be escaped (with a âÂÂâÂÂ) or quoted to protect them from expansion by the shell." Do you mean that it is incorrect for bash?
â Tim
Jun 7 at 18:40
2
I mean that it is incorrect for shells in general. See POSIX. That particular statement in thefindutilsmanual dates back to at least 1996... Of course it does no harm to quote, either as''or"", but it isnâÂÂt necessary.
â Stephen Kitt
Jun 7 at 19:11
@Tim You're experiencing a common situation where your intuition isn't yet accounting for the fact that there are two very different types of argument-processing going on here: when/how the shell parses arguments out of a line of text (which is where quoting matters) is different from raw operating system argument passing (where quotes are just regular characters). In the shell commandfind some/path -exec sh -c 'something "$@"' ;there's actually three layers of argument processing/passing, two of the shell variety and one of the basic raw operating system variety.
â mtraceur
Jun 7 at 22:03
 |Â
show 5 more comments
up vote
27
down vote
accepted
This isnâÂÂt really related to quoting, but rather to argument processing.
Consider the risky example:
find -exec sh -c "something " ;
This is parsed by the shell, and split into six words:
find,-exec,sh,-c,something(no quotes any more),;. ThereâÂÂs nothing to expand. The shell runsfindwith those six words as arguments.When
findfinds something to process, sayfoo; rm -rf $HOME, it replaceswithfoo; rm -rf $HOME, and runsshwith the argumentssh,-c, andsomething foo; rm -rf $HOME.shnow sees-c, and as a result parsessomething foo; rm -rf $HOME(the first non-option argument) and executes the result.
Now consider the safer variant:
find -exec sh -c 'something "$@"' sh ;
The shell runs
findwith the argumentsfind,-exec,sh,-c,something "$@",sh,,;.Now when
findfindsfoo; rm -rf $HOME, it replacesagain, and runsshwith the argumentssh,-c,something "$@",sh,foo; rm -rf $HOME.shsees-c, and parsessomething "$@"as the command to run, andshandfoo; rm -rf $HOMEas the positional parameters (starting from$0), expands"$@"tofoo; rm -rf $HOMEas a single value, and runssomethingwith the single argumentfoo; rm -rf $HOME.
You can see this by using printf. Create a new directory, enter it, and run
touch "hello; echo pwned"
Running the first variant as follows
find -exec sh -c "printf "Argument: %sn" " ;
produces
Argument: .
Argument: ./hello
pwned
whereas the second variant, run as
find -exec sh -c 'printf "Argument: %sn" "$@"' sh ;
produces
Argument: .
Argument: ./hello; echo pwned
In the safer variant, why isnot escaped or quoted?
â Tim
Jun 7 at 17:31
It generally doesnâÂÂt need to be quoted; it would only need to be quoted in a shell where it has some other meaning, and I donâÂÂt think thatâÂÂs the case with any of the main shells in use nowadays.
â Stephen Kitt
Jun 7 at 18:19
From gnu.org/software/findutils/manual/html_mono/â¦: "Both of these constructions (;and) need to be escaped (with a âÂÂâÂÂ) or quoted to protect them from expansion by the shell." Do you mean that it is incorrect for bash?
â Tim
Jun 7 at 18:40
2
I mean that it is incorrect for shells in general. See POSIX. That particular statement in thefindutilsmanual dates back to at least 1996... Of course it does no harm to quote, either as''or"", but it isnâÂÂt necessary.
â Stephen Kitt
Jun 7 at 19:11
@Tim You're experiencing a common situation where your intuition isn't yet accounting for the fact that there are two very different types of argument-processing going on here: when/how the shell parses arguments out of a line of text (which is where quoting matters) is different from raw operating system argument passing (where quotes are just regular characters). In the shell commandfind some/path -exec sh -c 'something "$@"' ;there's actually three layers of argument processing/passing, two of the shell variety and one of the basic raw operating system variety.
â mtraceur
Jun 7 at 22:03
 |Â
show 5 more comments
up vote
27
down vote
accepted
up vote
27
down vote
accepted
This isnâÂÂt really related to quoting, but rather to argument processing.
Consider the risky example:
find -exec sh -c "something " ;
This is parsed by the shell, and split into six words:
find,-exec,sh,-c,something(no quotes any more),;. ThereâÂÂs nothing to expand. The shell runsfindwith those six words as arguments.When
findfinds something to process, sayfoo; rm -rf $HOME, it replaceswithfoo; rm -rf $HOME, and runsshwith the argumentssh,-c, andsomething foo; rm -rf $HOME.shnow sees-c, and as a result parsessomething foo; rm -rf $HOME(the first non-option argument) and executes the result.
Now consider the safer variant:
find -exec sh -c 'something "$@"' sh ;
The shell runs
findwith the argumentsfind,-exec,sh,-c,something "$@",sh,,;.Now when
findfindsfoo; rm -rf $HOME, it replacesagain, and runsshwith the argumentssh,-c,something "$@",sh,foo; rm -rf $HOME.shsees-c, and parsessomething "$@"as the command to run, andshandfoo; rm -rf $HOMEas the positional parameters (starting from$0), expands"$@"tofoo; rm -rf $HOMEas a single value, and runssomethingwith the single argumentfoo; rm -rf $HOME.
You can see this by using printf. Create a new directory, enter it, and run
touch "hello; echo pwned"
Running the first variant as follows
find -exec sh -c "printf "Argument: %sn" " ;
produces
Argument: .
Argument: ./hello
pwned
whereas the second variant, run as
find -exec sh -c 'printf "Argument: %sn" "$@"' sh ;
produces
Argument: .
Argument: ./hello; echo pwned
This isnâÂÂt really related to quoting, but rather to argument processing.
Consider the risky example:
find -exec sh -c "something " ;
This is parsed by the shell, and split into six words:
find,-exec,sh,-c,something(no quotes any more),;. ThereâÂÂs nothing to expand. The shell runsfindwith those six words as arguments.When
findfinds something to process, sayfoo; rm -rf $HOME, it replaceswithfoo; rm -rf $HOME, and runsshwith the argumentssh,-c, andsomething foo; rm -rf $HOME.shnow sees-c, and as a result parsessomething foo; rm -rf $HOME(the first non-option argument) and executes the result.
Now consider the safer variant:
find -exec sh -c 'something "$@"' sh ;
The shell runs
findwith the argumentsfind,-exec,sh,-c,something "$@",sh,,;.Now when
findfindsfoo; rm -rf $HOME, it replacesagain, and runsshwith the argumentssh,-c,something "$@",sh,foo; rm -rf $HOME.shsees-c, and parsessomething "$@"as the command to run, andshandfoo; rm -rf $HOMEas the positional parameters (starting from$0), expands"$@"tofoo; rm -rf $HOMEas a single value, and runssomethingwith the single argumentfoo; rm -rf $HOME.
You can see this by using printf. Create a new directory, enter it, and run
touch "hello; echo pwned"
Running the first variant as follows
find -exec sh -c "printf "Argument: %sn" " ;
produces
Argument: .
Argument: ./hello
pwned
whereas the second variant, run as
find -exec sh -c 'printf "Argument: %sn" "$@"' sh ;
produces
Argument: .
Argument: ./hello; echo pwned
edited Jun 9 at 7:33
answered Jun 7 at 14:58
Stephen Kitt
139k22301363
139k22301363
In the safer variant, why isnot escaped or quoted?
â Tim
Jun 7 at 17:31
It generally doesnâÂÂt need to be quoted; it would only need to be quoted in a shell where it has some other meaning, and I donâÂÂt think thatâÂÂs the case with any of the main shells in use nowadays.
â Stephen Kitt
Jun 7 at 18:19
From gnu.org/software/findutils/manual/html_mono/â¦: "Both of these constructions (;and) need to be escaped (with a âÂÂâÂÂ) or quoted to protect them from expansion by the shell." Do you mean that it is incorrect for bash?
â Tim
Jun 7 at 18:40
2
I mean that it is incorrect for shells in general. See POSIX. That particular statement in thefindutilsmanual dates back to at least 1996... Of course it does no harm to quote, either as''or"", but it isnâÂÂt necessary.
â Stephen Kitt
Jun 7 at 19:11
@Tim You're experiencing a common situation where your intuition isn't yet accounting for the fact that there are two very different types of argument-processing going on here: when/how the shell parses arguments out of a line of text (which is where quoting matters) is different from raw operating system argument passing (where quotes are just regular characters). In the shell commandfind some/path -exec sh -c 'something "$@"' ;there's actually three layers of argument processing/passing, two of the shell variety and one of the basic raw operating system variety.
â mtraceur
Jun 7 at 22:03
 |Â
show 5 more comments
In the safer variant, why isnot escaped or quoted?
â Tim
Jun 7 at 17:31
It generally doesnâÂÂt need to be quoted; it would only need to be quoted in a shell where it has some other meaning, and I donâÂÂt think thatâÂÂs the case with any of the main shells in use nowadays.
â Stephen Kitt
Jun 7 at 18:19
From gnu.org/software/findutils/manual/html_mono/â¦: "Both of these constructions (;and) need to be escaped (with a âÂÂâÂÂ) or quoted to protect them from expansion by the shell." Do you mean that it is incorrect for bash?
â Tim
Jun 7 at 18:40
2
I mean that it is incorrect for shells in general. See POSIX. That particular statement in thefindutilsmanual dates back to at least 1996... Of course it does no harm to quote, either as''or"", but it isnâÂÂt necessary.
â Stephen Kitt
Jun 7 at 19:11
@Tim You're experiencing a common situation where your intuition isn't yet accounting for the fact that there are two very different types of argument-processing going on here: when/how the shell parses arguments out of a line of text (which is where quoting matters) is different from raw operating system argument passing (where quotes are just regular characters). In the shell commandfind some/path -exec sh -c 'something "$@"' ;there's actually three layers of argument processing/passing, two of the shell variety and one of the basic raw operating system variety.
â mtraceur
Jun 7 at 22:03
In the safer variant, why is
not escaped or quoted?â Tim
Jun 7 at 17:31
In the safer variant, why is
not escaped or quoted?â Tim
Jun 7 at 17:31
It generally doesnâÂÂt need to be quoted; it would only need to be quoted in a shell where it has some other meaning, and I donâÂÂt think thatâÂÂs the case with any of the main shells in use nowadays.
â Stephen Kitt
Jun 7 at 18:19
It generally doesnâÂÂt need to be quoted; it would only need to be quoted in a shell where it has some other meaning, and I donâÂÂt think thatâÂÂs the case with any of the main shells in use nowadays.
â Stephen Kitt
Jun 7 at 18:19
From gnu.org/software/findutils/manual/html_mono/â¦: "Both of these constructions (
; and ) need to be escaped (with a âÂÂâÂÂ) or quoted to protect them from expansion by the shell." Do you mean that it is incorrect for bash?â Tim
Jun 7 at 18:40
From gnu.org/software/findutils/manual/html_mono/â¦: "Both of these constructions (
; and ) need to be escaped (with a âÂÂâÂÂ) or quoted to protect them from expansion by the shell." Do you mean that it is incorrect for bash?â Tim
Jun 7 at 18:40
2
2
I mean that it is incorrect for shells in general. See POSIX. That particular statement in the
findutils manual dates back to at least 1996... Of course it does no harm to quote , either as '' or "", but it isnâÂÂt necessary.â Stephen Kitt
Jun 7 at 19:11
I mean that it is incorrect for shells in general. See POSIX. That particular statement in the
findutils manual dates back to at least 1996... Of course it does no harm to quote , either as '' or "", but it isnâÂÂt necessary.â Stephen Kitt
Jun 7 at 19:11
@Tim You're experiencing a common situation where your intuition isn't yet accounting for the fact that there are two very different types of argument-processing going on here: when/how the shell parses arguments out of a line of text (which is where quoting matters) is different from raw operating system argument passing (where quotes are just regular characters). In the shell command
find some/path -exec sh -c 'something "$@"' ; there's actually three layers of argument processing/passing, two of the shell variety and one of the basic raw operating system variety.â mtraceur
Jun 7 at 22:03
@Tim You're experiencing a common situation where your intuition isn't yet accounting for the fact that there are two very different types of argument-processing going on here: when/how the shell parses arguments out of a line of text (which is where quoting matters) is different from raw operating system argument passing (where quotes are just regular characters). In the shell command
find some/path -exec sh -c 'something "$@"' ; there's actually three layers of argument processing/passing, two of the shell variety and one of the basic raw operating system variety.â mtraceur
Jun 7 at 22:03
 |Â
show 5 more comments
up vote
3
down vote
Part 1:
find just uses text replacement.
Yes, if you did it unquoted, like this:
find . -type f -exec sh -c "echo " ;
and an attacker was able to create a file called ; echo owned, then it would exec
sh -c "echo ; echo owned"
which would result in the shell running echo then echo owned.
But if you added quotes, the attacker could just end your quotes then put the malicious command after it by creating a file called '; echo owned:
find . -type f -exec sh -c "echo ''" ;
which would result in the shell running echo '', echo owned.
(if you swapped the double quotes for single quotes, the attacker could use the other type of quotes too.)
Part 2:
In find -exec sh -c 'something "$@"' sh ;, the is not initially interpreted by the shell, it's executed directly with execve, so adding shell quotes wouldn't help.
find -exec sh -c 'something "$@"' sh "" ;
has no effect, since the shell strips the double quotes before running find.
find -exec sh -c 'something "$@"' sh "''" ;
adds quotes that the shell doesn't treat specially, so in most cases it just means the command won't do what you want.
Having it expand to /tmp/foo;, rm, -rf, $HOME shouldn't be a problem, because those are arguments to something, and something probably doesn't treat its arguments as commands to execute.
Part 3:
I assume similar considerations apply for anything that takes untrusted input and runs it as (part of) a command, for example xargs and parallel.
xargsis only dangerous if-Ior-Jis used. In normal operation it's only appending arguments to the end of the list, just as-exec ... +does.
â Charles Duffy
Jun 7 at 15:55
1
(parallel, by contrast, runs a shell by default without explicit request from the user, increasing the vulnerable surface; this is a matter that's been the subject of much discussion; see unix.stackexchange.com/questions/349483/⦠for an explanation, and the included link to lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html).
â Charles Duffy
Jun 7 at 16:02
@CharlesDuffy You mean "decreasing the vulnerable surface". The attack illustrated by OP does indeed not work by default with GNU Parallel.
â Ole Tange
Jun 8 at 7:22
1
Yes, I know you need it for parity across SSH -- if you didn't spawn a remoteparallel"receiver" process on the other end of any socket, able to do a direct shell-lessexecv. Which is exactly what I would have done, if in your shoes implementing the tool. Having a noninteractive program behave differently based on the current value ofSHELLis hardly least-astonishment.
â Charles Duffy
Jun 8 at 12:07
1
Yes -- I hold that pipes and redirections should be impossible unless the user explicitly starts a shell, at which point they get only the explicit behavior of the shell they explicitly started. If one can expect only what anexecvprovides, that's simpler and less astonishing, and a rule that doesn't change across locations/runtime environments.
â Charles Duffy
Jun 8 at 13:01
 |Â
show 2 more comments
up vote
3
down vote
Part 1:
find just uses text replacement.
Yes, if you did it unquoted, like this:
find . -type f -exec sh -c "echo " ;
and an attacker was able to create a file called ; echo owned, then it would exec
sh -c "echo ; echo owned"
which would result in the shell running echo then echo owned.
But if you added quotes, the attacker could just end your quotes then put the malicious command after it by creating a file called '; echo owned:
find . -type f -exec sh -c "echo ''" ;
which would result in the shell running echo '', echo owned.
(if you swapped the double quotes for single quotes, the attacker could use the other type of quotes too.)
Part 2:
In find -exec sh -c 'something "$@"' sh ;, the is not initially interpreted by the shell, it's executed directly with execve, so adding shell quotes wouldn't help.
find -exec sh -c 'something "$@"' sh "" ;
has no effect, since the shell strips the double quotes before running find.
find -exec sh -c 'something "$@"' sh "''" ;
adds quotes that the shell doesn't treat specially, so in most cases it just means the command won't do what you want.
Having it expand to /tmp/foo;, rm, -rf, $HOME shouldn't be a problem, because those are arguments to something, and something probably doesn't treat its arguments as commands to execute.
Part 3:
I assume similar considerations apply for anything that takes untrusted input and runs it as (part of) a command, for example xargs and parallel.
xargsis only dangerous if-Ior-Jis used. In normal operation it's only appending arguments to the end of the list, just as-exec ... +does.
â Charles Duffy
Jun 7 at 15:55
1
(parallel, by contrast, runs a shell by default without explicit request from the user, increasing the vulnerable surface; this is a matter that's been the subject of much discussion; see unix.stackexchange.com/questions/349483/⦠for an explanation, and the included link to lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html).
â Charles Duffy
Jun 7 at 16:02
@CharlesDuffy You mean "decreasing the vulnerable surface". The attack illustrated by OP does indeed not work by default with GNU Parallel.
â Ole Tange
Jun 8 at 7:22
1
Yes, I know you need it for parity across SSH -- if you didn't spawn a remoteparallel"receiver" process on the other end of any socket, able to do a direct shell-lessexecv. Which is exactly what I would have done, if in your shoes implementing the tool. Having a noninteractive program behave differently based on the current value ofSHELLis hardly least-astonishment.
â Charles Duffy
Jun 8 at 12:07
1
Yes -- I hold that pipes and redirections should be impossible unless the user explicitly starts a shell, at which point they get only the explicit behavior of the shell they explicitly started. If one can expect only what anexecvprovides, that's simpler and less astonishing, and a rule that doesn't change across locations/runtime environments.
â Charles Duffy
Jun 8 at 13:01
 |Â
show 2 more comments
up vote
3
down vote
up vote
3
down vote
Part 1:
find just uses text replacement.
Yes, if you did it unquoted, like this:
find . -type f -exec sh -c "echo " ;
and an attacker was able to create a file called ; echo owned, then it would exec
sh -c "echo ; echo owned"
which would result in the shell running echo then echo owned.
But if you added quotes, the attacker could just end your quotes then put the malicious command after it by creating a file called '; echo owned:
find . -type f -exec sh -c "echo ''" ;
which would result in the shell running echo '', echo owned.
(if you swapped the double quotes for single quotes, the attacker could use the other type of quotes too.)
Part 2:
In find -exec sh -c 'something "$@"' sh ;, the is not initially interpreted by the shell, it's executed directly with execve, so adding shell quotes wouldn't help.
find -exec sh -c 'something "$@"' sh "" ;
has no effect, since the shell strips the double quotes before running find.
find -exec sh -c 'something "$@"' sh "''" ;
adds quotes that the shell doesn't treat specially, so in most cases it just means the command won't do what you want.
Having it expand to /tmp/foo;, rm, -rf, $HOME shouldn't be a problem, because those are arguments to something, and something probably doesn't treat its arguments as commands to execute.
Part 3:
I assume similar considerations apply for anything that takes untrusted input and runs it as (part of) a command, for example xargs and parallel.
Part 1:
find just uses text replacement.
Yes, if you did it unquoted, like this:
find . -type f -exec sh -c "echo " ;
and an attacker was able to create a file called ; echo owned, then it would exec
sh -c "echo ; echo owned"
which would result in the shell running echo then echo owned.
But if you added quotes, the attacker could just end your quotes then put the malicious command after it by creating a file called '; echo owned:
find . -type f -exec sh -c "echo ''" ;
which would result in the shell running echo '', echo owned.
(if you swapped the double quotes for single quotes, the attacker could use the other type of quotes too.)
Part 2:
In find -exec sh -c 'something "$@"' sh ;, the is not initially interpreted by the shell, it's executed directly with execve, so adding shell quotes wouldn't help.
find -exec sh -c 'something "$@"' sh "" ;
has no effect, since the shell strips the double quotes before running find.
find -exec sh -c 'something "$@"' sh "''" ;
adds quotes that the shell doesn't treat specially, so in most cases it just means the command won't do what you want.
Having it expand to /tmp/foo;, rm, -rf, $HOME shouldn't be a problem, because those are arguments to something, and something probably doesn't treat its arguments as commands to execute.
Part 3:
I assume similar considerations apply for anything that takes untrusted input and runs it as (part of) a command, for example xargs and parallel.
answered Jun 7 at 15:39
Mikel
37.4k995121
37.4k995121
xargsis only dangerous if-Ior-Jis used. In normal operation it's only appending arguments to the end of the list, just as-exec ... +does.
â Charles Duffy
Jun 7 at 15:55
1
(parallel, by contrast, runs a shell by default without explicit request from the user, increasing the vulnerable surface; this is a matter that's been the subject of much discussion; see unix.stackexchange.com/questions/349483/⦠for an explanation, and the included link to lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html).
â Charles Duffy
Jun 7 at 16:02
@CharlesDuffy You mean "decreasing the vulnerable surface". The attack illustrated by OP does indeed not work by default with GNU Parallel.
â Ole Tange
Jun 8 at 7:22
1
Yes, I know you need it for parity across SSH -- if you didn't spawn a remoteparallel"receiver" process on the other end of any socket, able to do a direct shell-lessexecv. Which is exactly what I would have done, if in your shoes implementing the tool. Having a noninteractive program behave differently based on the current value ofSHELLis hardly least-astonishment.
â Charles Duffy
Jun 8 at 12:07
1
Yes -- I hold that pipes and redirections should be impossible unless the user explicitly starts a shell, at which point they get only the explicit behavior of the shell they explicitly started. If one can expect only what anexecvprovides, that's simpler and less astonishing, and a rule that doesn't change across locations/runtime environments.
â Charles Duffy
Jun 8 at 13:01
 |Â
show 2 more comments
xargsis only dangerous if-Ior-Jis used. In normal operation it's only appending arguments to the end of the list, just as-exec ... +does.
â Charles Duffy
Jun 7 at 15:55
1
(parallel, by contrast, runs a shell by default without explicit request from the user, increasing the vulnerable surface; this is a matter that's been the subject of much discussion; see unix.stackexchange.com/questions/349483/⦠for an explanation, and the included link to lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html).
â Charles Duffy
Jun 7 at 16:02
@CharlesDuffy You mean "decreasing the vulnerable surface". The attack illustrated by OP does indeed not work by default with GNU Parallel.
â Ole Tange
Jun 8 at 7:22
1
Yes, I know you need it for parity across SSH -- if you didn't spawn a remoteparallel"receiver" process on the other end of any socket, able to do a direct shell-lessexecv. Which is exactly what I would have done, if in your shoes implementing the tool. Having a noninteractive program behave differently based on the current value ofSHELLis hardly least-astonishment.
â Charles Duffy
Jun 8 at 12:07
1
Yes -- I hold that pipes and redirections should be impossible unless the user explicitly starts a shell, at which point they get only the explicit behavior of the shell they explicitly started. If one can expect only what anexecvprovides, that's simpler and less astonishing, and a rule that doesn't change across locations/runtime environments.
â Charles Duffy
Jun 8 at 13:01
xargs is only dangerous if -I or -J is used. In normal operation it's only appending arguments to the end of the list, just as -exec ... + does.â Charles Duffy
Jun 7 at 15:55
xargs is only dangerous if -I or -J is used. In normal operation it's only appending arguments to the end of the list, just as -exec ... + does.â Charles Duffy
Jun 7 at 15:55
1
1
(
parallel, by contrast, runs a shell by default without explicit request from the user, increasing the vulnerable surface; this is a matter that's been the subject of much discussion; see unix.stackexchange.com/questions/349483/⦠for an explanation, and the included link to lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html).â Charles Duffy
Jun 7 at 16:02
(
parallel, by contrast, runs a shell by default without explicit request from the user, increasing the vulnerable surface; this is a matter that's been the subject of much discussion; see unix.stackexchange.com/questions/349483/⦠for an explanation, and the included link to lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html).â Charles Duffy
Jun 7 at 16:02
@CharlesDuffy You mean "decreasing the vulnerable surface". The attack illustrated by OP does indeed not work by default with GNU Parallel.
â Ole Tange
Jun 8 at 7:22
@CharlesDuffy You mean "decreasing the vulnerable surface". The attack illustrated by OP does indeed not work by default with GNU Parallel.
â Ole Tange
Jun 8 at 7:22
1
1
Yes, I know you need it for parity across SSH -- if you didn't spawn a remote
parallel "receiver" process on the other end of any socket, able to do a direct shell-less execv. Which is exactly what I would have done, if in your shoes implementing the tool. Having a noninteractive program behave differently based on the current value of SHELL is hardly least-astonishment.â Charles Duffy
Jun 8 at 12:07
Yes, I know you need it for parity across SSH -- if you didn't spawn a remote
parallel "receiver" process on the other end of any socket, able to do a direct shell-less execv. Which is exactly what I would have done, if in your shoes implementing the tool. Having a noninteractive program behave differently based on the current value of SHELL is hardly least-astonishment.â Charles Duffy
Jun 8 at 12:07
1
1
Yes -- I hold that pipes and redirections should be impossible unless the user explicitly starts a shell, at which point they get only the explicit behavior of the shell they explicitly started. If one can expect only what an
execv provides, that's simpler and less astonishing, and a rule that doesn't change across locations/runtime environments.â Charles Duffy
Jun 8 at 13:01
Yes -- I hold that pipes and redirections should be impossible unless the user explicitly starts a shell, at which point they get only the explicit behavior of the shell they explicitly started. If one can expect only what an
execv provides, that's simpler and less astonishing, and a rule that doesn't change across locations/runtime environments.â Charles Duffy
Jun 8 at 13:01
 |Â
show 2 more comments
up vote
3
down vote
1. Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris unquoted and therefore not treated as a single string?
In a sense, but quoting cannot help here. The filename that gets replaced in place of can contain any characters, including quotes. Whatever form of quoting was used, the filename could contain the same, and "break out" of the quoting.
2. ... but since
is unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;", "rm", "-rf", and "$HOME"?
No. "$@" expands to the positional parameters, as separate words, and doesn't split them further. Here, is an argument to find in itself, and find passes the current filename also as a distinct argument to sh. It's directly available as a variable in the shell script, it's not processed as a shell command itself.
... why is
not escaped or quoted?
It doesn't need to be, in most shells. If you run fish, it needs to be: fish -c 'echo ' prints an empty line. But it doesn't matter if you quote it, the shell will just remove the quotes.
3. Could you give other examples...
Any time you expand a filename (or another uncontrolled string) as-is inside a string that's taken as some kind of code(*), there's a possibility of arbitrary command execution.
For example, this expands $f directly the Perl code, and will cause problems if a filename contains a double quote. The quote in the filename will end the quote in the Perl code, and the rest of the filename can contain any Perl code:
touch '"; print "HELLO";"'
for f in ./*; do
perl -le "print "size: " . -s "$f""
done
(The filename has to be a bit weird since Perl parses the whole code up front, before running any of it. So we'll have to avoid a parse error.)
While this passes it safely through an argument:
for f in ./*; do
perl -le 'print "size: " . -s $ARGV[0]' "$f"
done
(It doesn't make sense to run another shell directly from a shell, but if you do, it's similar to the find -exec sh ... case)
(* some kind of code includes SQL, so obligatory XKCD: https://xkcd.com/327/ plus explanation:
https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )
add a comment |Â
up vote
3
down vote
1. Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris unquoted and therefore not treated as a single string?
In a sense, but quoting cannot help here. The filename that gets replaced in place of can contain any characters, including quotes. Whatever form of quoting was used, the filename could contain the same, and "break out" of the quoting.
2. ... but since
is unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;", "rm", "-rf", and "$HOME"?
No. "$@" expands to the positional parameters, as separate words, and doesn't split them further. Here, is an argument to find in itself, and find passes the current filename also as a distinct argument to sh. It's directly available as a variable in the shell script, it's not processed as a shell command itself.
... why is
not escaped or quoted?
It doesn't need to be, in most shells. If you run fish, it needs to be: fish -c 'echo ' prints an empty line. But it doesn't matter if you quote it, the shell will just remove the quotes.
3. Could you give other examples...
Any time you expand a filename (or another uncontrolled string) as-is inside a string that's taken as some kind of code(*), there's a possibility of arbitrary command execution.
For example, this expands $f directly the Perl code, and will cause problems if a filename contains a double quote. The quote in the filename will end the quote in the Perl code, and the rest of the filename can contain any Perl code:
touch '"; print "HELLO";"'
for f in ./*; do
perl -le "print "size: " . -s "$f""
done
(The filename has to be a bit weird since Perl parses the whole code up front, before running any of it. So we'll have to avoid a parse error.)
While this passes it safely through an argument:
for f in ./*; do
perl -le 'print "size: " . -s $ARGV[0]' "$f"
done
(It doesn't make sense to run another shell directly from a shell, but if you do, it's similar to the find -exec sh ... case)
(* some kind of code includes SQL, so obligatory XKCD: https://xkcd.com/327/ plus explanation:
https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )
add a comment |Â
up vote
3
down vote
up vote
3
down vote
1. Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris unquoted and therefore not treated as a single string?
In a sense, but quoting cannot help here. The filename that gets replaced in place of can contain any characters, including quotes. Whatever form of quoting was used, the filename could contain the same, and "break out" of the quoting.
2. ... but since
is unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;", "rm", "-rf", and "$HOME"?
No. "$@" expands to the positional parameters, as separate words, and doesn't split them further. Here, is an argument to find in itself, and find passes the current filename also as a distinct argument to sh. It's directly available as a variable in the shell script, it's not processed as a shell command itself.
... why is
not escaped or quoted?
It doesn't need to be, in most shells. If you run fish, it needs to be: fish -c 'echo ' prints an empty line. But it doesn't matter if you quote it, the shell will just remove the quotes.
3. Could you give other examples...
Any time you expand a filename (or another uncontrolled string) as-is inside a string that's taken as some kind of code(*), there's a possibility of arbitrary command execution.
For example, this expands $f directly the Perl code, and will cause problems if a filename contains a double quote. The quote in the filename will end the quote in the Perl code, and the rest of the filename can contain any Perl code:
touch '"; print "HELLO";"'
for f in ./*; do
perl -le "print "size: " . -s "$f""
done
(The filename has to be a bit weird since Perl parses the whole code up front, before running any of it. So we'll have to avoid a parse error.)
While this passes it safely through an argument:
for f in ./*; do
perl -le 'print "size: " . -s $ARGV[0]' "$f"
done
(It doesn't make sense to run another shell directly from a shell, but if you do, it's similar to the find -exec sh ... case)
(* some kind of code includes SQL, so obligatory XKCD: https://xkcd.com/327/ plus explanation:
https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )
1. Is the cause of the problem in
find -exec sh -c "something " ;that the replacement foris unquoted and therefore not treated as a single string?
In a sense, but quoting cannot help here. The filename that gets replaced in place of can contain any characters, including quotes. Whatever form of quoting was used, the filename could contain the same, and "break out" of the quoting.
2. ... but since
is unquoted, doesn't"$@"also have the same problem as the original command? For example,"$@"will be expanded to"/tmp/foo;", "rm", "-rf", and "$HOME"?
No. "$@" expands to the positional parameters, as separate words, and doesn't split them further. Here, is an argument to find in itself, and find passes the current filename also as a distinct argument to sh. It's directly available as a variable in the shell script, it's not processed as a shell command itself.
... why is
not escaped or quoted?
It doesn't need to be, in most shells. If you run fish, it needs to be: fish -c 'echo ' prints an empty line. But it doesn't matter if you quote it, the shell will just remove the quotes.
3. Could you give other examples...
Any time you expand a filename (or another uncontrolled string) as-is inside a string that's taken as some kind of code(*), there's a possibility of arbitrary command execution.
For example, this expands $f directly the Perl code, and will cause problems if a filename contains a double quote. The quote in the filename will end the quote in the Perl code, and the rest of the filename can contain any Perl code:
touch '"; print "HELLO";"'
for f in ./*; do
perl -le "print "size: " . -s "$f""
done
(The filename has to be a bit weird since Perl parses the whole code up front, before running any of it. So we'll have to avoid a parse error.)
While this passes it safely through an argument:
for f in ./*; do
perl -le 'print "size: " . -s $ARGV[0]' "$f"
done
(It doesn't make sense to run another shell directly from a shell, but if you do, it's similar to the find -exec sh ... case)
(* some kind of code includes SQL, so obligatory XKCD: https://xkcd.com/327/ plus explanation:
https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )
answered Jun 7 at 19:35
ilkkachu
47.5k668131
47.5k668131
add a comment |Â
add a comment |Â
up vote
1
down vote
Your concern is precisely the reason why GNU Parallel quotes input:
touch "hello; echo pwned"
find . -print0 | parallel -0 printf "Argument: %s\n"
This will not run echo pwned.
It will run a shell, so that if you extend your command, you will not suddenly get a surprise:
# This _could_ be run without spawining a shell
parallel "grep -E 'a|bc' " ::: foo
# This cannot
parallel "grep -E 'a|bc' | wc" ::: foo
For further details on the spawning-a-shell issue see: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell
1
...that said,find . -print0 | xargs -0 printf "Argument: %sn"is just as safe (or rather, moreso, since with-print0one handles filenames with newlines correctly); parallel's quoting is a workaround for a problem that doesn't exist at all when no shell is present.
â Charles Duffy
Jun 8 at 12:05
But as soon as you add| wcto the command you need to jump through hoops to make it safe. GNU Parallel is safe by default.
â Ole Tange
Jun 9 at 14:27
ITYM: it tries to cover for every quirk of the shell language by the complicated process of carefully quoting everything. That's not nearly as safe as properly storing data in variables, not intermixed with code. Now, if it were to automatically convert thatfoo |ÃÂ wcintosh -c 'foo "$1" |ÃÂ wcsh `, that might be different.
â ilkkachu
Jun 10 at 9:00
add a comment |Â
up vote
1
down vote
Your concern is precisely the reason why GNU Parallel quotes input:
touch "hello; echo pwned"
find . -print0 | parallel -0 printf "Argument: %s\n"
This will not run echo pwned.
It will run a shell, so that if you extend your command, you will not suddenly get a surprise:
# This _could_ be run without spawining a shell
parallel "grep -E 'a|bc' " ::: foo
# This cannot
parallel "grep -E 'a|bc' | wc" ::: foo
For further details on the spawning-a-shell issue see: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell
1
...that said,find . -print0 | xargs -0 printf "Argument: %sn"is just as safe (or rather, moreso, since with-print0one handles filenames with newlines correctly); parallel's quoting is a workaround for a problem that doesn't exist at all when no shell is present.
â Charles Duffy
Jun 8 at 12:05
But as soon as you add| wcto the command you need to jump through hoops to make it safe. GNU Parallel is safe by default.
â Ole Tange
Jun 9 at 14:27
ITYM: it tries to cover for every quirk of the shell language by the complicated process of carefully quoting everything. That's not nearly as safe as properly storing data in variables, not intermixed with code. Now, if it were to automatically convert thatfoo |ÃÂ wcintosh -c 'foo "$1" |ÃÂ wcsh `, that might be different.
â ilkkachu
Jun 10 at 9:00
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Your concern is precisely the reason why GNU Parallel quotes input:
touch "hello; echo pwned"
find . -print0 | parallel -0 printf "Argument: %s\n"
This will not run echo pwned.
It will run a shell, so that if you extend your command, you will not suddenly get a surprise:
# This _could_ be run without spawining a shell
parallel "grep -E 'a|bc' " ::: foo
# This cannot
parallel "grep -E 'a|bc' | wc" ::: foo
For further details on the spawning-a-shell issue see: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell
Your concern is precisely the reason why GNU Parallel quotes input:
touch "hello; echo pwned"
find . -print0 | parallel -0 printf "Argument: %s\n"
This will not run echo pwned.
It will run a shell, so that if you extend your command, you will not suddenly get a surprise:
# This _could_ be run without spawining a shell
parallel "grep -E 'a|bc' " ::: foo
# This cannot
parallel "grep -E 'a|bc' | wc" ::: foo
For further details on the spawning-a-shell issue see: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell
edited Jun 8 at 12:54
answered Jun 8 at 7:28
Ole Tange
11.2k1343101
11.2k1343101
1
...that said,find . -print0 | xargs -0 printf "Argument: %sn"is just as safe (or rather, moreso, since with-print0one handles filenames with newlines correctly); parallel's quoting is a workaround for a problem that doesn't exist at all when no shell is present.
â Charles Duffy
Jun 8 at 12:05
But as soon as you add| wcto the command you need to jump through hoops to make it safe. GNU Parallel is safe by default.
â Ole Tange
Jun 9 at 14:27
ITYM: it tries to cover for every quirk of the shell language by the complicated process of carefully quoting everything. That's not nearly as safe as properly storing data in variables, not intermixed with code. Now, if it were to automatically convert thatfoo |ÃÂ wcintosh -c 'foo "$1" |ÃÂ wcsh `, that might be different.
â ilkkachu
Jun 10 at 9:00
add a comment |Â
1
...that said,find . -print0 | xargs -0 printf "Argument: %sn"is just as safe (or rather, moreso, since with-print0one handles filenames with newlines correctly); parallel's quoting is a workaround for a problem that doesn't exist at all when no shell is present.
â Charles Duffy
Jun 8 at 12:05
But as soon as you add| wcto the command you need to jump through hoops to make it safe. GNU Parallel is safe by default.
â Ole Tange
Jun 9 at 14:27
ITYM: it tries to cover for every quirk of the shell language by the complicated process of carefully quoting everything. That's not nearly as safe as properly storing data in variables, not intermixed with code. Now, if it were to automatically convert thatfoo |ÃÂ wcintosh -c 'foo "$1" |ÃÂ wcsh `, that might be different.
â ilkkachu
Jun 10 at 9:00
1
1
...that said,
find . -print0 | xargs -0 printf "Argument: %sn" is just as safe (or rather, moreso, since with -print0 one handles filenames with newlines correctly); parallel's quoting is a workaround for a problem that doesn't exist at all when no shell is present.â Charles Duffy
Jun 8 at 12:05
...that said,
find . -print0 | xargs -0 printf "Argument: %sn" is just as safe (or rather, moreso, since with -print0 one handles filenames with newlines correctly); parallel's quoting is a workaround for a problem that doesn't exist at all when no shell is present.â Charles Duffy
Jun 8 at 12:05
But as soon as you add
| wc to the command you need to jump through hoops to make it safe. GNU Parallel is safe by default.â Ole Tange
Jun 9 at 14:27
But as soon as you add
| wc to the command you need to jump through hoops to make it safe. GNU Parallel is safe by default.â Ole Tange
Jun 9 at 14:27
ITYM: it tries to cover for every quirk of the shell language by the complicated process of carefully quoting everything. That's not nearly as safe as properly storing data in variables, not intermixed with code. Now, if it were to automatically convert that
foo |àwc into sh -c 'foo "$1" |àwc sh `, that might be different.â ilkkachu
Jun 10 at 9:00
ITYM: it tries to cover for every quirk of the shell language by the complicated process of carefully quoting everything. That's not nearly as safe as properly storing data in variables, not intermixed with code. Now, if it were to automatically convert that
foo |àwc into sh -c 'foo "$1" |àwc sh `, that might be different.â ilkkachu
Jun 10 at 9:00
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f448443%2frun-any-command-which-will-pass-untrusted-data-to-commands-which-interpret-argu%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Related: unix.stackexchange.com/questions/156008
â Kusalananda
Jun 8 at 7:36