Что означает env x = '() {:;}; команда «bash do and why is unecure?

По-видимому, существует уязвимость (CVE-2014-6271) в bash: Bash специально обработанная переменная кода для инъекций кода

Я пытаюсь понять, что происходит, но я не совсем уверен, что понимаю. Как выполнить echo, как это делается в одинарных кавычках?

 $ env x = '() {:;}; echo уязвим 'bash -c' echo это тест "
уязвимый
Это тест

РЕДАКТИРОВАТЬ 1 : исправленная система выглядит следующим образом:

 $ env x = '() {:;}; echo уязвим 'bash -c' echo это тест "
bash: warning: x: игнорирование попытки определения функции
bash: определение функции импорта ошибок для `x '
Это тест

РЕДАКТИРОВАТЬ 2 . Существует связанная с этим уязвимость /патч: CVE-2014-7169 который использует несколько другое испытание:

 $ env 'x = () {:;}; echo уязвим '' BASH_FUNC_x () = () {:;}; echo уязвимый 'bash -c "эхо-тест"

непроверенный вывод :

 уязвим
bash: BASH_FUNC_x (): строка 0: синтаксическая ошибка около неожиданного токена `) '
bash: BASH_FUNC_x (): строка 0: `BASH_FUNC_x () () {:;}; эхо уязвим "
bash: определение функции импорта ошибок для `BASH_FUNC_x '
контрольная работа

частично (ранняя версия) исправленный вывод :

 bash: warning: x: игнорирование попытки определения функции
bash: определение функции импорта ошибок для `x '
bash: определение функции импорта ошибок для `BASH_FUNC_x () '
контрольная работа

исправленный вывод до CVE-2014-7169 и включая его:

 bash: warning: x: игнорирование попытки определения функции
bash: определение функции импорта ошибок для `BASH_FUNC_x '
контрольная работа

ИЗМЕНИТЬ 3 : история продолжается:

228 голосов | спросил jippie 25 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 25 Sep 2014 00:02:16 +0400 2014, 00:02:16

5 ответов


194

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

 $ foo () {bar; }
$ export -f foo
$ env | grep -A1 foo
foo = () {bar
}

То есть переменная среды foo имеет литеральное содержимое:

 () {bar
}

Когда новый экземпляр bash запускается, он ищет эти специально созданные переменные среды и интерпретирует их как определения функций. Вы даже можете написать один и увидеть, что он все еще работает:

 $ export foo = '() {echo "Inside function"; }»
$ bash -c 'foo'
Внутренняя функция

К сожалению, синтаксический анализ определений функций из строк (переменные среды) может иметь более широкий эффект, чем предполагалось. В непроверенных версиях он также интерпретирует произвольные команды, которые возникают после завершения определения функции. Это связано с недостаточными ограничениями при определении приемлемых функционально-подобных строк в окружающей среде. Например:

 $ export foo = '() {echo "Inside function"; }; эхо "Выполненное эхо"
$ bash -c 'foo'
Выполненное эхо
Внутренняя функция

Обратите внимание, что эхо вне определения функции было неожиданно выполнено во время запуска bash. Определение функции - это всего лишь шаг, чтобы получить оценку и использование, само определение функции и используемая переменная среды произвольны. Оболочка рассматривает переменные среды, видит foo, который выглядит так, как будто он отвечает ограничениям, которые он знает о том, как выглядит определение функции, и оценивает строку, непреднамеренно также выполняет эхо (что может быть любая команда, злонамеренная или нет).

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

Вот пример жизнеспособной атаки. Вы запускаете веб-сервер, который запускает уязвимую оболочку где-то, как часть своей жизни. Этот веб-сервер передает переменные среды в сценарий bash, например, если вы используете CGI, информация о HTTP-запросе часто включается в качестве переменных среды с веб-сервера. Например, HTTP_USER_AGENT может быть настроен на содержимое вашего пользовательского агента. Это означает, что если вы обманываете свой пользовательский агент как нечто вроде '() {:; }; echo foo ', когда будет запущен этот сценарий оболочки, будет выполнен echo foo. Опять же, echo foo может быть любым, злонамеренным или нет.

ответил Chris Down 25 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 25 Sep 2014 00:10:51 +0400 2014, 00:10:51
83

Это может помочь еще раз продемонстрировать, что происходит:

$ export dummy = '() {echo "hi"; }; эхо "pwned" '
$ bash
Косоглазый
$

Если вы запускаете уязвимую оболочку, то при запуске новой подоболочки (здесь просто с помощью инструкции bash) вы увидите, что произвольный код (echo "pwned") является незамедлительно исполняемый как часть его инициирования. По-видимому, оболочка видит, что переменная окружения (фиктивная) содержит определение функции и оценивает определение, чтобы определить эту функцию в своей среде (обратите внимание, что она не выполняет функцию: она будет печатать «привет».)

К сожалению, он не просто оценивает определение функции, он оценивает весь текст значения переменной среды, включая, возможно, злонамеренные (-е) утверждения (ы), которые следуют определению функции. Обратите внимание, что без определения начальной функции переменная среды не будет оцениваться, она просто будет добавлена ​​в среду в виде текстовой строки. Как отметил Крис Даун, это особый механизм реализации импорта экспортированных функций оболочки.

Мы можем видеть функцию, которая была определена в новой оболочке (и что она была отмечена как экспортированная там), и мы можем ее выполнить. Кроме того, фиктивный файл не был импортирован как текстовая переменная:

$ declare -f
фиктивный ()
{
    эхо "привет"
}
declare -fx dummy
$ dummy
Здравствуй
$ echo $ dummy
$

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

ответил sdenham 25 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 25 Sep 2014 20:42:53 +0400 2014, 20:42:53
70

Я написал это как переработанную в стиле учебника превосходный ответ Криса Дауна выше.


В bash вы можете иметь переменные оболочки, подобные этому

$ t = "привет там"
$ echo $ t
всем привет
$

По умолчанию эти переменные не наследуются дочерними процессами.

$ bash
$ echo $ t

$ exit

Но если вы помечаете их для экспорта, bash установит флаг, который означает, что они перейдут в среду подпроцессов (хотя параметр envp не так много заметен, main в вашей программе C имеет три параметра: main (int argc, char * argv [], char * envp []), где последний массив указателей представляет собой массив переменных оболочки с их определениями) .

Итак, давайте экспортируем t следующим образом:

$ echo $ t
всем привет
$ export t
$ bash
$ echo $ t
всем привет
$ exit

В то время как выше t не был определен в подоболочке, теперь он появляется после его экспорта (используйте export -nt, если вы хотите остановить его экспорт).

Но функции в bash - это другое животное. Вы объявляете их следующим образом:

$ fn () {echo "test"; }

И теперь вы можете просто вызвать функцию, вызвав ее, как если бы это была другая команда оболочки:

$ fn
контрольная работа
$

Еще раз, если вы создаете подоболочку, наша функция не экспортируется:

$ bash
$ fn
fn: команда не найдена
$ exit

Мы можем экспортировать функцию с помощью export -f:

$ export -f fn
$ bash
$ fn
контрольная работа
$ exit

Вот сложная часть: экспортированная функция, такая как fn, преобразуется в переменную среды так же, как наш экспорт переменной оболочки t был выше. Этого не происходит, когда fn является локальной переменной, но после экспорта мы можем рассматривать его как переменную оболочки. Тем не менее, вы можете также иметь регулярную (то есть нефункцию) переменную оболочки с тем же именем. bash различает в зависимости от содержимого переменной:

$ echo $ fn

$ # Видите, ничего не было
$ export fn = regular
$ echo $ fn
регулярный
$

Теперь мы можем использовать env, чтобы показать все переменные оболочки, помеченные для экспорта, и как обычный fn, так и функция fn:

$ env
,
,
,
п = регулярный
fn = () {echo "test"
}
$

Под-оболочка будет глотать оба определения: одно как регулярная переменная и одно как функция:

$ bash
$ echo $ fn
регулярный
$ fn
контрольная работа
$ exit

Вы можете определить fn, как мы это делали выше, или непосредственно как назначение регулярной переменной:

$ fn = '() {echo "direct"; }»

Обратите внимание, что это очень необычная вещь! Обычно мы определяем функцию fn, как мы это делали выше, с синтаксисом fn () {...}. Но так как bash экспортирует его через окружающую среду, мы можем «коротко сократить» прямо к обычному определению выше. Обратите внимание, что (возможно, против вашей интуиции) это делает не результат в новой функции fn, доступной в текущей оболочке. Но если вы создадите ** суб ** оболочку, то она будет.

Отменим экспорт функции fn и оставьте новый обычный fn (как показано выше) неповрежденным.

$ export -nf fn

Теперь функция fn больше не экспортируется, но существует регулярная переменная fn, и она содержит () {echo "direct"; }.

Теперь, когда подоболочка видит регулярную переменную, начинающуюся с (), она интерпретирует остальное как определение функции. Но это только , когда начинается новая оболочка. Как мы видели выше, просто определение регулярной переменной оболочки, начинающейся с (), не приводит к тому, что она ведет себя как функция. Вы должны начать подоболочку.

И теперь ошибка «shellshock»:

Как мы только что видели, когда новая оболочка глотает определение регулярной переменной, начиная с (), она интерпретирует ее как функцию. Однако, если после закрывающей фигурной скобки, которая определяет эту функцию, она больше выполняет любые .

Это еще раз:

  1. Создается новый bash
  2. Передается переменная среды
  3. Эта переменная среды начинается с "()", а затем содержит тело функции внутри фигурных скобок, а затем имеет команды after

В этом случае уязвимое bash выполнит последние команды.

Пример:

$ export ex = '() {echo "function ex"; }; эхо "это плохо"; '
$ bash
это плохо
$ ex
функция ex
$

Регулярная экспортированная переменная ex была передана подселлем, которая была интерпретирована как функция ex, но завершающие команды выполнялись (это плохое ) по мере того, как подоболочка породила.


Объяснениегладкий однострочный тест

Популярным одним слоем для тестирования уязвимости Shellshock является тот, который указан в вопросе @ jippie:

env x = '() {:;}; echo уязвим 'bash -c' echo это тест "

Вот разбивка: сначала : в bash является просто сокращением для true. true и : оба оценивают (вы догадались) true, в bash:

$ if true; затем эхо да; фи
да
$ if:; затем эхо да; фи
да
$

Во-вторых, команда env (также встроенная в bash) печатает переменные среды (как мы видели выше), но также может использоваться для запуска отдельной команды с экспортированной переменной (или переменными) к этой команде, а bash -c запускает одну команду из командной строки:

$ bash -c 'echo hi'
Здравствуй
$ bash -c 'echo $ t'

$ env t = экспортировано bash -c 'echo $ t'
экспортируемый
$

Итак, сшивая все это вместе, мы можем запустить bash в качестве команды, дать ему некоторую фиктивную вещь (например, bash -c echo this is test) и экспортировать переменную, которая запускается с помощью (), поэтому подоболочка будет интерпретировать его как функцию. Если shellshock присутствует, он также незамедлительно выполнит любые завершающие команды в подоболочке. Поскольку функция, которую мы проходим, не имеет к нам отношения (но должна анализировать!), Мы используем кратчайшую допустимую функцию, которую можно вообразить:

$ f () {:;}
$ f
$

Функция f здесь просто выполняет команду :, которая возвращает true и завершает работу. Теперь добавьте к этой команде «зло» и экспортируйте регулярную переменную в подоболочку, и вы выиграете. Вот опять один лайнер:

$ env x = '() {:;}; echo уязвим 'bash -c' echo это тест "

Итак, x экспортируется как регулярная переменная с простой действительной функцией с echo уязвимым, прикрепленным к концу. Это передается bash, и bash интерпретирует x как функцию (которую мы не заботимся), а затем, возможно, выполняет echo уязвимый, если присутствует shellshock.

Мы могли бы немного сократить однострочный файл, удалив это тестовое сообщение:

$ env x = '() {:;}; echo уязвим 'bash -c:

Это не беспокоит , это тест, но снова запускает команду :. (Если вы оставите код -c:, тогда вы сядете в подоболочку и должны выйти из него вручную.) Возможно, наиболее удобной для пользователя версией будет следующая:

$ env x = '() {:;}; echo уязвимый «bash -c» echo Если вы видите слово «уязвимое» выше, вы уязвимы для shellshock »
ответил Fixee 26 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 26 Sep 2014 09:12:32 +0400 2014, 09:12:32
20

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

Однако CVE-2014-6271 отличается.

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

Пример, который был представлен в контексте CVE-2014-6271, - это скрипты, используемые для анализа лог-файлов. У них может быть очень законная потребность в передаче ненадежных данных в переменных среды. Разумеется, имя для такой переменной окружения выбирается таким образом, чтобы оно не оказывало негативного влияния.

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

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

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

Злоумышленник, зная точные имена переменных, экспортируемых с помощью program1, и имена переменных, которые интерпретируются program2, не могут использовать эти знания для изменения поведения «program2», если есть нет совпадения между набором имен.

Но это сломалось, если program2 был сценарием bash, потому что из-за этой ошибки bash интерпретирует каждую переменную среды как код.

ответил kasperd 25 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 25 Sep 2014 13:12:44 +0400 2014, 13:12:44
9

Это объясняется в статье, которую вы связали ...

  

вы можете создавать переменные среды со специально созданными значениями   перед вызовом оболочки bash. Эти переменные могут содержать код, который   выполняется как только вызывается оболочка.

Это означает, что bash, вызываемый с помощью -c "echo, это тест" выполняет код в одинарных кавычках при его вызове.

  

У Bash есть функции, хотя и в несколько ограниченной реализации, и   эти функции bash можно включить в переменные среды.   Этот недостаток запускается, когда дополнительный код добавляется в конец этих   (внутри переменной enivronment).

Обозначает, что приведенный вами пример кода использует тот факт, что вызываемый bash не останавливает оценку этой строки после выполнения задания. Назначение функции в этом случае.

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

ответил Bananguin 25 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 25 Sep 2014 00:16:11 +0400 2014, 00:16:11

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132