Русский
Русский
English
Статистика
Реклама

Перевод В bash безобидная с виду конструкция var -eq 42 умеет выполнять и произвольный код

Знали ли вы о том, что следующий bash-скрипт способен выполнять произвольный код, который предоставит ему пользователь в ответ на запрос скрипта о вводе данных?



#!/bin/bashread -rp "Enter guess: " numif [[ $num -eq 42 ]]thenecho "Correct"elseecho "Wrong"fi

Вот пример:

$ ./myscriptEnter guess: 42Correct$ ./myscriptEnter guess: a[$(date >&2)]+42Sun Feb 4 19:06:19 PST 2018Correct

Это не некая новая находка, и не уязвимость, которая появилась в bash совсем недавно. Но это одна из тех проблем разработки bash-скриптов, о которой говорят очень и очень мало. Да и ksh ведёт себя так же, если принимать во внимание отсутствие read -p.

Оболочка выполняет вычисление выражений в арифметическом контексте в нескольких синтаксических конструкциях, в которых она ожидает увидеть целое число. Сюда входят $((here)), ((here)), ${var:here:here}, ${var[here]}, var[here]= ..; то же самое оболочка ожидает и в правой или левой части конструкции [[, используемой для сравнения чисел с применением операций -eq, -gt, -le и прочих подобных.

В этом контексте можно использовать или передавать в команду строковые литералы, вроде 1+1, которые будут обрабатываться как математические выражения. Например, команда var=1+1; echo $((var)) приведёт к выводу числа 2.

Но, как было показано, это не просто система вычисления арифметических выражений, работающая в стиле калькулятора bc. Всё это более тесно интегрировано с оболочкой: команда a=b; b=c+1; c=41; echo $((a)) выведет 42. Тут же можно вспомнить и операции с индексами массивов. Как целые числа интерпретируются и замены команд.

Обычно эту проблему считают малозначительной или попросту игнорируют. На неё не указывают при проведении код-ревью или при анализе кода неких примеров. На неё не обращают внимания даже те, кто хорошо о ней осведомлён. Было бы довольно-таки утомительно использовать для выполнения всех операций сравнения ${var//[!0-9-]/}, да и, в любом случае, часто это не имеет отношения к нашему вопросу

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

Исходный пример скорее представляет собой тот случай, когда можно говорить о том, что не каждый фрагмент программы, допускающий внедрение кода, может считаться брешью системы безопасности. Ведь в нашем случае того же эффекта можно добиться и гораздо проще всего лишь выполнив команду date, а не запуская перед этим ./myscript.

А теперь сравните это всё с отношением к eval.

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

Часто можно слышать, что eval это зло. Но почему-то никто никогда не говорит, что -eq это зло, или что конструкция $((foo+1)) считается опасной.

Почему существуют подобные двойные стандарты?

Я взял бы на себя смелость утверждать, что команда eval считается плохой не (только) потому, что она небезопасна, но и потому, что её считают примитивной и низкопробной. Безопасность это всего лишь самая простая причина советовать использовать что-то такое, что лучше eval.

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

А между тем арифметические контексты bash это удобные и полезные инструменты, которыми часто пользуются опытные разработчики скриптов, сознательно делая выбор в их пользу.

Вот пример скрипта. Если запустить его в виде ./myscript 1 он выдаст Foo, а если в виде ./myscript 2 он выдаст Bar. Вы, возможно, увидите тут шаблон именования переменных, характерный для новичков, когда после имени идёт цифра (а может, вы и сами когда-то создавали такие переменные):

#!/bin/bashvar1="Foo"var2="Bar"eval echo "\$var$1"

Если где-нибудь опубликовать этот пример к нему появится куча комментариев, авторы которых будут говорить о том, что это небезопасно, что ./myscript '1; rm -rf /' может привести к серьёзным проблемам В итоге автора кода призовут подумать о детях и переписать код с использованием массивов:

#!/bin/bashvar[1]="Foo"var[2]="Bar"echo "${var[$1]}"

Как уже было сказано, такая конструкция не намного безопаснее eval: команда ./myscript '1+a[$(rm -rf /)]' приведёт к столь же серьёзным проблемам, что и ./myscript '1; rm -rf /'. Правда, из-за того, что тут правильно используются подходящие возможности оболочки, большинство опытных программистов сочтёт этот код вполне приемлемым.

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

Просто стоит помнить о том, что существуют двойные стандарты.

Я, когда писал эту статью, не преследовал какой-то определённой цели. Я не могу сделать тут какого-то глубокомысленного вывода из вышесказанного. Поэтому обращаюсь к читателям. Что вы думаете обо всём этом? Может, нам стоит меньше нападать на eval и больше внимания уделять арифметическим контекстам? Может, стоит, в духе обмана детей ради их защиты, игнорировать проблему, а после того, как некто дорастёт до определённого уровня использования eval, серьёзно разговаривать с ним о внедрении кода? А может нам всем надо просто перейти на командную оболочку fish?


Источник: habr.com
К списку статей
Опубликовано: 14.05.2021 16:12:54
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании ruvds.com

Информационная безопасность

Системное администрирование

*nix

Linux

Ruvds_перевод

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru