Issue
I'm trying to better understand how use of eval
can be evil. I've been reading BashFAQ/048 and I found the following example I can't wrap my head around: Say we have a script foo
that does option parsing the following way:
for i; do
case $i in
--test-*)
shift
name=${i#--}
eval "$name=\$name"
;;
esac
done
Why is the following example code injection?
./foo --test-'; ls -l /etc/passwd;x='
I thought that with this input, name would become -'; ls -l /etc/passwd;x='
; at the first parsing of the input, we would have the string -'; ls -l /etc/passwd;x='=$name
passed to eval
, which would just throw the error: bash: eval: -': invalid option
. So how is this example supposed to print detailed information on the /etc/passwd
file?
Solution
${i#--}
just removes the --
prefix from $i
, so the value of name
is
test-; ls -l /etc/passwd;x=
When this is substituted into the eval
argument, you get
test-; ls -l /etc/passwd;x==$name
eval
then executes this as a command line. test-
will get an error because there's no such command. ls -l /etc/passwd
will execute that command. And x==$name
sets the variable x
to =
followed by the value of $name
, i.e.
=test-; ls -l /etc/passwd;x=
Notice that the '
characters are not included. They're parsed by the original shell when you invoke the foo
script, not passed literally into the script. So the value of $i
doesn't contain those quotes and they're not in the command executed by eval
. This allows the ;
to be treated as a command separator. The quotes are needed in the original command to prevent the ;
from being parsed when calling foo
.
The easy way to tell what an eval
command will do is replace eval
with echo
. Then it will print the command it would have executed.
Answered By - Barmar Answer Checked By - David Marino (WPSolving Volunteer)