Из руководства по findutils:
Например, такие конструкции, как эти две команды
# risky find -exec sh -c "something {}" \; find -execdir sh -c "something {}" \;
очень опасны Причина этого заключается в том, что символ {{} расширяется до имени файла, которое может содержать точку с запятой или другие символы, специальные для оболочки. Если, например, кто-то создает файл,
/tmp/foo; rm -rf $HOME
две вышеуказанные команды могут удалить чей-то домашний каталог.Поэтому по этой причине не запускайте команды, которые передадут недоверенные данные (например, имена файлов) командам, которые интерпретируют аргументы как команды для дальнейшей интерпретации (например, 'sh').
В случае с оболочкой есть умное решение этой проблемы:
# safer find -exec sh -c 'something "$@"' sh {} \; find -execdir sh -c 'something "$@"' sh {} \;
Этот подход не гарантирует избежание любой проблемы, но он намного безопаснее, чем подстановка данных по выбору злоумышленника в текст команды оболочки.
- Является ли причиной проблемы
find -exec sh -c "something {}" \;
то, что замена для{}
не заключена в кавычки и поэтому не рассматривается как одна строка? В решении
find -exec sh -c 'something "$@"' sh {} \;
,first
{}
заменяется, но поскольку{}
он не"$@"
заключен в кавычки, не имеет ли он той же проблемы, что и исходная команда? Например,"$@"
будет расширена"/tmp/foo;"
,"rm"
,"-rf"
и"$HOME"
?почему
{}
не избежал или не цитируется?
- Не могли бы вы привести другие примеры (все еще с
sh -c
или без него, если это применимо; с или без,find
которые могут быть необязательны), где применяются те же виды проблем и решений, и которые являются минимальными примерами, чтобы мы могли сосредоточиться на проблеме и решении с как можно меньше отвлекаться? См. Способы предоставления аргументов для команды, выполняемой `bash -c`
Благодарю.
Ответы:
Это на самом деле не связано с цитированием, а скорее с обработкой аргументов.
Рассмотрим рискованный пример:
Это обрабатывается интерпретатором, и разбит на шесть слов:
find
,-exec
,sh
,-c
,something {}
(без кавычек больше),;
. Там нет ничего, чтобы расширяться. Оболочка работаетfind
с этими шестью словами в качестве аргументов.Когда
find
что - то находит в процессе, скажемfoo; rm -rf $HOME
, он заменяет{}
сfoo; rm -rf $HOME
, и работаетsh
с аргументамиsh
,-c
иsomething foo; rm -rf $HOME
.sh
теперь видит-c
, и в результате анализируетsomething foo; rm -rf $HOME
( первый аргумент без опций ) и выполняет результат.Теперь рассмотрим более безопасный вариант:
Оболочка работает
find
с аргументамиfind
,-exec
,sh
,-c
,something "$@"
,sh
,{}
,;
.Теперь , когда
find
находкиfoo; rm -rf $HOME
, он заменяет{}
снова, и работаетsh
с аргументамиsh
,-c
,something "$@"
,sh
,foo; rm -rf $HOME
.sh
видит-c
и анализируетsomething "$@"
как команду для запускаsh
иfoo; rm -rf $HOME
как позиционные параметры ( начиная с$0
), расширяется"$@"
доfoo; rm -rf $HOME
единого значения и запускаетсяsomething
с одним аргументомfoo; rm -rf $HOME
.Вы можете увидеть это с помощью
printf
. Создайте новый каталог, введите его и запуститеЗапуск первого варианта выполняется следующим образом
производит
тогда как второй вариант запускается как
производит
источник
{}
не экранированы или не указаны?;
и{}
) должны быть экранированы (с помощью« \ ») или заключены в кавычки, чтобы защитить их от расширения оболочкой». Вы имеете в виду, что это неправильно для Баш?findutils
руководстве датируется как минимум 1996 годом ... Конечно, цитировать{}
, как'{}'
или"{}"
, не вредно, но в этом нет необходимости.find some/path -exec sh -c 'something "$@"' {} \;
на самом деле есть три уровня обработки / передачи аргументов, два варианта оболочки и один базовый вариант операционной системы.Часть 1:
find
просто использует замену текста.Да, если вы сделали это без кавычек, вот так:
и злоумышленник смог создать файл с именем
; echo owned
, то он будет выполнятьчто привело бы к оболочке работает
echo
тогдаecho owned
.Но если вы добавили кавычки, злоумышленник может просто завершить ваши кавычки, а затем поместить вредоносную команду после нее, создав файл с именем
'; echo owned
:что приведет в управлении оболочки
echo ''
,echo owned
.(Если вы заменили двойные кавычки на одинарные кавычки, злоумышленник также может использовать кавычки другого типа.)
Часть 2:
В
find -exec sh -c 'something "$@"' sh {} \;
,{}
оболочка изначально не интерпретируется оболочкой, она выполняется напрямуюexecve
, поэтому добавление кавычек оболочки не поможет.не имеет никакого эффекта, так как оболочка удаляет двойные кавычки перед запуском
find
.добавляет кавычки, которые оболочка не обрабатывает специально, поэтому в большинстве случаев это просто означает, что команда не будет делать то, что вы хотите.
Имея это расширяться
/tmp/foo;
,rm
,-rf
,$HOME
не должно быть проблемой, потому что те аргументыsomething
, и ,something
вероятно , не относится к его аргументы как команды для выполнения.Часть 3:
Я предполагаю, что аналогичные соображения применимы ко всему, что принимает ненадежный ввод и выполняет его как (часть) команды, например
xargs
иparallel
.источник
xargs
опасно только если-I
или-J
используется. В обычной работе это только добавление аргументов в конец списка, как это-exec ... {} +
делается.parallel
отличие от этого, по умолчанию оболочка запускается без явного запроса пользователя, что увеличивает уязвимую поверхность; этот вопрос был предметом многочисленных дискуссий; для объяснения см. unix.stackexchange.com/questions/349483/… и включенная ссылка на lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html ).parallel
процесс "приемника" на другом конце любого сокета, способный выполнять прямую работу без оболочкиexecv
. Именно это я и сделал бы, если бы на вашем месте внедрял инструмент. То, что неинтерактивная программа ведет себя по-разному в зависимости от текущей стоимости,SHELL
едва ли удивительно.execv
, что предоставляет, это проще и менее удивительно, и правило, которое не меняется в разных местах / средах выполнения.В некотором смысле, но цитирование здесь не может помочь . Имя файла, которое заменяется вместо,
{}
может содержать любые символы, включая кавычки . Независимо от того, какая форма цитирования использовалась, имя файла может содержать одно и то же, и «прерывать» цитирование.Номер
"$@"
распространяется на позиционные параметры, как отдельные слова, и не разделяет их дальше. Здесь{}
он является аргументом самого поfind
себе иfind
передает текущее имя файла также в качестве отдельного аргументаsh
. Он непосредственно доступен как переменная в сценарии оболочки, он не обрабатывается как сама команда оболочки.Так не должно быть в большинстве оболочек. Если вы запускаете
fish
, это должно быть:fish -c 'echo {}'
печатает пустую строку. Но это не имеет значения, если вы цитируете это, оболочка просто удалит кавычки.Каждый раз, когда вы раскрываете имя файла (или другую неконтролируемую строку) как есть внутри строки, которая воспринимается как некоторый код (*) , существует вероятность выполнения произвольной команды.
Например, это расширяет
$f
непосредственно код Perl и вызовет проблемы, если имя файла содержит двойные кавычки. Кавычка в имени файла заканчивает кавычку в коде Perl, а остальная часть имени файла может содержать любой код Perl:(Имя файла должно быть немного странным, так как Perl анализирует весь код заранее, прежде чем запускать какой-либо из них. Поэтому мы должны избегать ошибки разбора.)
Пока это безопасно проходит через аргумент:
(Не имеет смысла запускать другую оболочку непосредственно из оболочки, но если вы это сделаете, это похоже на
find -exec sh ...
случай)(* некоторый код включает в себя SQL, поэтому обязательно XKCD: https://xkcd.com/327/ плюс объяснение: https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )
источник
Ваша проблема как раз и является причиной, по которой GNU Parallel вводит кавычки:
Это не будет работать
echo pwned
.Он запустит оболочку, так что если вы расширите свою команду, вы не получите неожиданный сюрприз:
Дополнительные сведения о проблеме spawning-a-shell см. По адресу : https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell.
источник
find . -print0 | xargs -0 printf "Argument: %s\n"
так же безопасно (или, скорее, более того, так как с-print0
одной обрабатывает имена файлов с новой строки правильно); Цитирование параллельного интерфейса - это обходной путь для проблемы, которой вообще не существует, когда нет оболочки.| wc
команду, вам нужно прыгать через обручи, чтобы сделать ее безопасной. GNU Parallel по умолчанию безопасен.foo {} | wc
вsh -c 'foo "$1" | wc
sh {} `, это могло бы быть иначе.