Всегда ли безопасно использовать `eval echo`?

20

Использование evalчасто не рекомендуется, потому что это позволяет выполнять произвольный код. Однако, если мы используем eval echo, то похоже, что остальная часть строки станет аргументом, echoпоэтому она должна быть безопасной. Я прав в этом?

Cyker
источник
1
не всегда безопасно, вы можете обернуть вилочную бомбу или мерзкий гм -fR *
μολὼν.λαβέ
Возможно, это всего лишь мысленный эксперимент, но если вы на самом деле думали сделать это, чтобы передать ему несколько аргументов, например -n, вы можете просто сделать это с помощью переменной без кавычек, например, echo $argumentsили если $argumentsэто массив echo "${arguments[@]}". Использование eval echoбессмысленно, даже если это было безопасно.
JoL

Ответы:

40

контрпример:

DANGEROUS=">foo"
eval echo $DANGEROUS

Произвольные аргументы to echoмогли бы сделать что-то более гнусное, чем создание файла с именем "foo".

Celada
источник
6
Также: DANGEROUS="hello;ls"для произвольных команд вместо ls.
Кусалананда
2
Также: DANGEROUS='$(ls)'(может потребоваться больше экранирования).
wizzwizz4
Будет eval echo '"'"$DANGEROUS"'"'работать? Похоже на goo.gl/L2pPQP
Исмаэль Мигель
@IsmaelMiguel Это не работает для примеров wizzwizz, Cyker или sorontar или для чего-либо с двойными кавычками в строке (например DANGEROUS='">foo"').
Гордон Дэвиссон
Штопать. Хотя я нашел кое-что, что немного помогло
Исмаэль Мигель
26

@Celada предоставила отличный ответ. Чтобы продемонстрировать evalдействительно зло, вот нечто более гнусное, чем создание файла с именем "foo" :

DANGEROUS='$(rm foo)'
eval echo "$DANGEROUS"

И, конечно, может быть что-то более гнусное, чем нечто более гнусное, чем создание файла с именем «foo» .

Cyker
источник
8
+1 за демонстрацию того, что цитирование переменной как, "$THIS"а не просто как $THIS, даже не помогает!
Селада
Отправка дополнительной пары цитат, кажется, помогает. Нечто подобное eval echo '"'"$DANGEROUS"'"'. Попробуйте это на goo.gl/L2pPQP
Исмаэль Мигель
На самом деле, ваш пример не так уж и страшен >foo, потому что «создание файла с именем« foo »» не обязательно все, что >fooделает. Единственное реальное отличие вашего примера в том, что он не оставляет пустой файл. Содержание все еще ушло.
flarn2006
12

Нет, это не всегда безопасно. Eval может выполнить любую команду.

Безопасная команда, подобная этой (дата не выполняется, поскольку она находится в одинарных кавычках):

$ echo '$(date)'
$(date)

Становится опасным, если используется с eval:

$ eval echo '$(date)'
Sat Dec 24 22:55:55 UTC 2016

Конечно, датой может быть любая команда.

Один из способов улучшить это - дополнительно процитировать аргументы в eval:

$ eval echo '\$(date)'
$(date)

Но обычно сложно правильно дважды цитировать выражение.

И становится невозможным контролировать правильное цитирование, если выражение может быть установлено внешним злоумышленником, например:

$ var='$(date);echo Hello!'
$ eval echo "$var"
Sat Dec 24 23:01:48 UTC 2016
Hello!
sorontar
источник
1

Хотя это правда, что evalвсегда нужно подходить с осторожностью, eval echoконструкция не всегда бессмысленна и может использоваться безопасно. Недавно я нуждался в этом, чтобы оценить несколько расширений фигурных скобок в том порядке, в котором они мне нужны.

bash делает несколько расширений скобок слева направо, так

xargs -I_ cat _/{11..15}/{8..5}.jpg

расширяется до

xargs -I_ cat _/11/8.jpg _/11/7.jpg _/11/6.jpg _/11/5.jpg _/12/8.jpg _/12/7.jpg _/12/6.jpg _/12/5.jpg _/13/8.jpg _/13/7.jpg _/13/6.jpg _/13/5.jpg _/14/8.jpg _/14/7.jpg _/14/6.jpg _/14/5.jpg _/15/8.jpg _/15/7.jpg _/15/6.jpg _/15/5.jpg

но мне нужно было сделать второе расширение скобки первым, давая

xargs -I_ cat _/11/8.jpg _/12/8.jpg _/13/8.jpg _/14/8.jpg _/15/8.jpg _/11/7.jpg _/12/7.jpg _/13/7.jpg _/14/7.jpg _/15/7.jpg _/11/6.jpg _/12/6.jpg _/13/6.jpg _/14/6.jpg _/15/6.jpg _/11/5.jpg _/12/5.jpg _/13/5.jpg _/14/5.jpg _/15/5.jpg

Лучшее, что я мог придумать, чтобы сделать это, было

xargs -I_ cat $(eval echo _/'{11..15}'/{8..5}.jpg)

Это работает, потому что одинарные кавычки защищают первый набор фигурных скобок от раскрытия во время синтаксического анализа evalкомандной строки, оставляя их для раскрытия посредством подоболочки, вызываемой eval.

Может быть какая-то хитрая схема с использованием вложенных фигурных скобок, которая позволяет этому происходить за один шаг, но если это так, я слишком стар и глуп, чтобы это увидеть. Есть и другие оболочки, bashкоторые позволяют более аккуратные способы достижения такого рода вещей. Но в любом случае такое использование evalбезопасно, поскольку все его аргументы - это фиксированные строки, которые не содержат раскрытия параметров.

flabdablet
источник
Здесь вам не нужно echo и подстановка команд (которая также зависит от $ IFS). Вы могли бы сделатьeval xargs -I_ cat _/'{11..15}'/{8..5}.jpg
Стефан Chazelas
Это тоже работает, но делает процесс subshell порожденным eval, пока процесс xargs не будет завершен; версия eval echo заставляет эту оболочку исчезнуть еще до запуска xargs. Это, вероятно, важно только для тех, кто такой же анальный, как и я, о том, что отображается в представлениях дерева htop и журналах set -x :-)
flabdablet