Что делает ENV x = '() {:;}; управляйте, чтобы' удар сделал и почему это небезопасно?

Просто найдите свой файл и возвратите dirname:

find -name 'level.dat' -exec dirname {} \;
240
15.07.2015, 15:32
5 ответов

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

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

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

() {  bar
}

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

$ export foo='() { echo "Inside function"; }'
$ bash -c 'foo'
Inside function

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

$ export foo='() { echo "Inside function" ; }; echo "Executed echo"'
$ bash -c 'foo'
Executed echo
Inside function

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

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

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

208
27.01.2020, 19:27

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

$ export dummy='() { echo "hi"; }; echo "pwned"'
$ bash
pwned
$

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

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

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

$ declare -f
dummy ()
{
    echo "hi"
}
declare -fx dummy
$ dummy
hi
$echo $dummy
$

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

86
27.01.2020, 19:27

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

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

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

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

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

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

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

Злоумышленник, зная точные имена переменных, экспортируемых программой1 , и имена переменных, интерпретируемых программой2 , не может использовать это знание для изменения поведения 'program2`, если нет перекрытия между набором имен.

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

20
27.01.2020, 19:27

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

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

Это означает, что Bash, который называется с -C «ECHO, это тест» выполняет код в одном кавычках, когда он вызывает.

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

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

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

9
27.01.2020, 19:27

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


В bash вы можете иметь такие переменные оболочки

$ t="hi there"
$ echo $t
hi there
$

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

$ bash
$ echo $t

$ exit

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

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

$ echo $t
hi there
$ export t
$ bash
$ echo $t
hi there
$ exit

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

Но функции в bash - другое дело. Вы объявляете их так:

$ fn() { echo "test"; }

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

$ fn
test
$

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

$ bash
$ fn
fn: command not found
$ exit

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

$ export -f fn
$ bash
$ fn
test
$ exit

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

$ echo $fn

$ # See, nothing was there
$ export fn=regular
$ echo $fn
regular
$ 

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

$ env
.
.
.
fn=regular
fn=() {  echo "test"
}
$

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

$ bash
$ echo $fn
regular
$ fn
test
$ exit

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

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

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

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

$ export -nf fn

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

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

А теперь ошибка "shellshock":

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

Это требования, еще раз:

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

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

Пример:

$ export ex='() { echo "function ex" ; }; echo "this is bad"; '
$ bash
this is bad
$ ex
function ex
$

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


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

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

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

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

$ if true; then echo yes; fi
yes
$ if :; then echo yes; fi
yes
$

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

$ bash -c 'echo hi'
hi
$ bash -c 'echo $t'

$ env t=exported bash -c 'echo $t'
exported
$

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

$ f() { :;}
$ f
$ 

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

$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

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

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

$ env x='() { :;}; echo vulnerable' bash -c :

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

$ env x='() { :;}; echo vulnerable' bash -c "echo If you see the word vulnerable above, you are vulnerable to shellshock"
72
27.01.2020, 19:27

Теги

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