Похоже, в bash существует уязвимость (CVE-2014-6271): атака с помощью внедрения кода специально созданных переменных среды Bash
Я пытаюсь понять, что происходит, но я не совсем уверен, что понимаю это. Как echo
выполнить в одинарных кавычках?
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
РЕДАКТИРОВАТЬ 1 : исправленная система выглядит следующим образом:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test
РЕДАКТИРОВАТЬ 2 : Существует связанная уязвимость / патч: CVE-2014-7169, который использует немного другой тест:
$ env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
непропатченный вывод :
vulnerable
bash: BASH_FUNC_x(): line 0: syntax error near unexpected token `)'
bash: BASH_FUNC_x(): line 0: `BASH_FUNC_x() () { :;}; echo vulnerable'
bash: error importing function definition for `BASH_FUNC_x'
test
частично (ранняя версия) исправленный вывод :
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test
исправлен вывод до CVE-2014-7169 включительно:
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test
РЕДАКТИРОВАТЬ 3 : история продолжается с:
bash
shellshock
vulnerability
jippie
источник
источник
vulnerable
появляется в выводе. Основная проблема заключается в том, что bash также выполняет синтаксический анализ и выполнение кода после определения функции. Посмотрите/bin/id
часть seclists.org/oss-sec/2014/q3/650 для другого примера.Ответы:
bash хранит экспортированные определения функций как переменные среды. Экспортируемые функции выглядят так:
То есть переменная окружения
foo
имеет буквальное содержимое:Когда запускается новый экземпляр bash, он ищет эти специально созданные переменные окружения и интерпретирует их как определения функций. Вы даже можете написать один и увидеть, что он все еще работает:
К сожалению, разбор определений функций из строк (переменных среды) может иметь более широкий эффект, чем предполагалось. В не исправленных версиях он также интерпретирует произвольные команды, которые появляются после завершения определения функции. Это связано с недостаточными ограничениями в определении приемлемых функционально-подобных строк в среде. Например:
Обратите внимание, что эхо за пределами определения функции было неожиданно выполнено во время запуска bash. Определение функции - это всего лишь шаг к выполнению оценки и эксплуатации, само определение функции и используемая переменная окружения являются произвольными. Оболочка просматривает переменные окружения, видит
foo
, как будто она соответствует ограничениям, которые она знает о том, как выглядит определение функции, и она оценивает строку, непреднамеренно выполняя также эхо (которое может быть любой командой, злонамеренной или нет).Это считается небезопасным, поскольку переменные, как правило, сами по себе не допускаются или не ожидают непосредственного вызова произвольного кода, содержащегося в них. Возможно, ваша программа устанавливает переменные окружения из ненадежного пользовательского ввода. Было бы весьма неожиданно, что этими переменными среды можно было манипулировать таким образом, чтобы пользователь мог выполнять произвольные команды без вашего явного намерения сделать это, используя эту переменную среды по такой причине, объявленной в коде.
Вот пример жизнеспособной атаки. Вы запускаете веб-сервер, который запускает уязвимую оболочку, где-то, как часть его жизни. Этот веб-сервер передает переменные среды в сценарий bash, например, если вы используете CGI, информация о HTTP-запросе часто включается в качестве переменных среды с веб-сервера. Например,
HTTP_USER_AGENT
может быть установлено содержимое вашего пользовательского агента. Это означает, что если вы подделаете свой пользовательский агент, чтобы он был похож на '() {:; }; echo foo ', когда этот сценарий оболочкиecho foo
будет запущен, будет выполнен. Опять же,echo foo
может быть что угодно, злое или нет.источник
export bar='() { echo "bar" ; }'; zsh -c bar
и он отображает,bar
а неzsh:1: command not found: bar
? Вы уверены, что не путаете оболочку, которую вы вызываете, с оболочкой, которую вы используете для настройки теста?Это может помочь в дальнейшей демонстрации того, что происходит:
Если вы запускаете уязвимую оболочку, то, когда вы запускаете новую подоболочку (здесь, просто используя оператор bash), вы увидите, что произвольный код (
echo "pwned"
) сразу же выполняется как часть его инициации. По-видимому, оболочка видит, что переменная окружения (dummy) содержит определение функции, и оценивает определение, чтобы определить эту функцию в ее окружении (обратите внимание, что она не выполняет функцию: это выдает «hi».)К сожалению, он не только оценивает определение функции, но и оценивает весь текст значения переменной среды, включая, возможно, вредоносные операторы, которые следуют за определением функции. Обратите внимание, что без начального определения функции переменная среды не будет оценена, она будет просто добавлена в среду в виде текстовой строки. Как отметил Крис Даун, это особый механизм для реализации импорта экспортируемых функций оболочки.
Мы можем увидеть функцию, которая была определена в новой оболочке (и помечена как экспортированная там), и мы можем выполнить ее. Кроме того, пустышка не была импортирована как текстовая переменная:
Ни создание этой функции, ни что-либо, что бы она делала, если бы она выполнялась, не является частью эксплойта - это всего лишь средство, с помощью которого эксплойт выполняется. Дело в том, что если злоумышленник может предоставить вредоносный код, которому предшествует минимальное и неважное определение функции, в текстовой строке, которая помещается в экспортированную переменную среды, то он будет выполняться при запуске подоболочки, что является обычным событием. во многих сценариях. Кроме того, он будет выполнен с правами скрипта.
источник
export
команда, а в другихenv
? я думалenv
, что используется для определения переменных среды, которые будут вызываться при запуске другой оболочки bash. тогда как это работаетexport
env
иexport
определения среды экспорта, чтобы они были доступны в подоболочке. Проблема заключается в том, как эти экспортированные определения импортируются в среду подоболочки, а именно в механизм, который импортирует определения функций.env
запускает команду с некоторыми опциями и установленными переменными среды. Обратите внимание , что в оригинальных примерах вопроса,env
устанавливаетx
в строку, и вызовыbash -c
с помощью команды для запуска. Если вы это сделаетеenv x='foo' vim
, Vim запустится, и там вы сможете вызвать его содержащую оболочку / окружение с помощью!echo $x
, и он напечатаетfoo
, но если вы затем выйдете иecho $x
, он не будет определен, так как он существовал только во время работы vim. черезenv
команду.export
Команда вместо устанавливает постоянные значения в текущей среде , так что подоболочка запустить позже будет использовать их.Я написал это как повторение превосходного ответа Криса Дауна в стиле учебника.
В bash вы можете использовать такие переменные оболочки
По умолчанию эти переменные не наследуются дочерними процессами.
Но если вы пометите их для экспорта, bash установит флаг, который означает, что они войдут в среду подпроцессов (хотя
envp
параметр не очень заметен,main
в вашей программе на С есть три параметра:main(int argc, char *argv[], char *envp[])
где последний массив указателей является массивом переменных оболочки с их определениями).Итак, давайте экспортировать
t
следующим образом:Принимая во внимание, что выше
t
было не определено в подоболочке, теперь оно появляется после того, как мы его экспортировали (используйте,export -n t
если вы хотите прекратить его экспорт).Но функции в bash - это другое животное. Вы объявляете их так:
И теперь вы можете просто вызвать функцию, вызвав ее, как если бы это была другая команда оболочки:
Еще раз, если вы создаете подоболочку, наша функция не экспортируется:
Мы можем экспортировать функцию с
export -f
:Вот сложная часть: экспортированная функция наподобие
fn
преобразуется в переменную окружения так же, как был описан наш экспорт переменной оболочкиt
. Этого не происходит, когдаfn
была локальная переменная, но после экспорта мы можем видеть ее как переменную оболочки. Однако вы также можете иметь обычную (то есть, не функциональную) переменную оболочки с тем же именем. Bash различает на основе содержимого переменной:Теперь мы можем использовать
env
для отображения всех переменных оболочки, помеченных для экспорта, и отображаются как обычные, такfn
и функцииfn
:Под-оболочка будет принимать оба определения: одно как обычная переменная, а другое как функция:
Вы можете определить,
fn
как мы делали выше, или напрямую как обычное присвоение переменной:Обратите внимание, что это необычная вещь! Обычно мы определяем функцию,
fn
как мы делали выше, с помощьюfn() {...}
синтаксиса. Но поскольку bash экспортирует его через среду, мы можем «сократить путь» прямо к обычному определению, приведенному выше. Обратите внимание, что (вопреки вашей интуиции, возможно) это не приводит к появлению новой функции,fn
доступной в текущей оболочке. Но если вы породите ** sub ** shell, то это произойдет.Давайте отменим экспорт функции
fn
и оставим новый обычныйfn
(как показано выше) без изменений.Теперь функция
fn
больше не экспортируется, но есть обычная переменнаяfn
, и она() { echo "direct" ; }
в ней содержится .Теперь, когда подоболочка видит обычную переменную, которая начинается с
()
нее, остальная часть интерпретируется как определение функции. Но это только тогда, когда начинается новая оболочка. Как мы видели выше, простое определение обычной переменной оболочки, начинающейся с()
, не приводит к тому, что она ведет себя как функция. Вы должны начать подоболочку.А теперь ошибка "Shellshock":
Как мы только что увидели, когда новая оболочка принимает определение обычной переменной, начиная с
()
нее, она интерпретируется как функция. Однако, если после закрывающей скобки задано больше данных, определяющих функцию, она также выполняет все, что там есть.Это требования, еще раз:
В этом случае уязвимый bash выполнит последние команды.
Пример:
Обычная экспортируемая переменная
ex
была передана в подоболочку, которая была интерпретирована как функция,ex
но завершающие команды были выполнены (this is bad
) как порожденная подоболочка.Объясняя гладкий однострочный тест
Популярный однострочный документ для тестирования уязвимости Shellshock - это тот, который упоминается в вопросе @ jippie:
Вот разбивка: во-первых,
:
в Bash это просто сокращение дляtrue
.true
и:
оба оценивают (как вы уже догадались) в bash:Во-вторых,
env
команда (также встроенная в bash) печатает переменные среды (как мы видели выше), но также может использоваться для запуска одной команды с экспортированной переменной (или переменными), заданной для этой команды, иbash -c
запускает одну команду из ее командная строка:Объединяя все эти вещи вместе, мы можем запустить bash как команду, дать ему какую-то глупую вещь (например
bash -c echo this is a test
) и экспортировать переменную, которая начинается с()
так, чтобы подоболочка интерпретировала ее как функцию. Если присутствует шеллшок, он также немедленно выполнит любые завершающие команды в подоболочке. Поскольку функция, которую мы передаем, не имеет отношения к нам (но должна анализировать!), Мы используем самую короткую допустимую возможную функцию:Функция
f
здесь просто выполняет:
команду, которая возвращает true и завершает работу. Теперь добавьте к этому некоторую «злую» команду и экспортируйте обычную переменную в подоболочку, и вы выиграете. Вот еще одна строка:Так
x
экспортируется как обычная переменная с простой допустимой функцией сecho vulnerable
прикрепленным до конца. Это передается в bash, и bash интерпретируетx
как функцию (о которой мы не заботимся), а затем, возможно, выполняетecho vulnerable
if shellshock.Мы могли бы немного укоротить одну строку, удалив
this is a test
сообщение:Это не беспокоит,
this is a test
но:
снова запускает команду без вывода сообщений. (Если вы отключите его,-c :
то будете сидеть в подоболочке и выходить вручную.) Возможно, наиболее удобной версией будет эта:источник
{ :;};
самом деле говорит. Это было бы хорошим дополнением к вашему ответу на мой взгляд. Можете объяснить, как вы переходите от своего примера к исходной команде в вопросе?Если вы можете передавать произвольные переменные окружения в программу, вы можете заставить ее делать что угодно, загружая библиотеки по вашему выбору. В большинстве случаев это не считается уязвимостью в программе, получающей эти переменные среды, а скорее в механизме, с помощью которого посторонний может передавать произвольные переменные среды.
Однако CVE-2014-6271 отличается.
Нет ничего плохого в наличии ненадежных данных в переменной среды. Нужно просто убедиться, что он не помещен ни в одну из переменных среды, которые могут изменить поведение программы. Поместив немного более абстрактно, для конкретного вызова вы можете создать белый список имен переменных среды, которые могут быть заданы напрямую посторонним.
Примером, который был предложен в контексте CVE-2014-6271, являются сценарии, используемые для анализа файлов журналов. У них может быть вполне законная потребность передавать ненадежные данные в переменных среды. Конечно, имя такой переменной среды выбирается таким образом, чтобы оно не оказывало негативного влияния.
Но вот что плохо в этой конкретной уязвимости bash. Его можно использовать через любое имя переменной. Если вы создадите переменную среды с именем
GET_REQUEST_TO_BE_PROCESSED_BY_MY_SCRIPT
, вы не ожидаете, что любая другая программа, кроме вашего собственного скрипта, будет интерпретировать содержимое этой переменной среды. Но, используя эту ошибку, каждая переменная среды становится вектором атаки.Обратите внимание, что это не означает, что имена переменных среды должны быть секретными. Знание имен переменных среды не облегчает атаку.
Если
program1
вызовы,program2
которые в свою очередь вызываютprogram3
, тоprogram1
могут передавать данныеprogram3
через переменные среды. Каждая программа имеет определенный список переменных среды, которые она устанавливает, и определенный список, на который она действует. Если вы выбрали имя, которое не было распознаноprogram2
, вы можете передавать данные из негоprogram1
в систему,program3
не беспокоясь о том, что это может иметь какие-либо неблагоприятные последствияprogram2
.Злоумышленник, зная точные имена переменных, экспортируемых с помощью,
program1
и имена переменных, с которыми он интерпретируется,program2
не может использовать эти знания для изменения поведения «program2», если нет совпадения между набором имен.Но это сломалось, если бы
program2
былbash
скрипт, потому что из-за этой ошибкиbash
каждая переменная среды интерпретировалась как код.источник
Это объясняется в статье, которую вы связали ...
Это означает, что bash, вызываемый с помощью,
-c "echo this is a test"
выполняет код в одинарных кавычках, когда он вызывается.Означает, что пример кода, который вы опубликовали, использует тот факт, что вызванный bash не прекращает оценку этой строки после выполнения присваивания. Назначение функции в этом случае.
На самом деле, особая вещь в фрагменте кода, который вы разместили, насколько я понимаю, заключается в том, что при использовании определения функции перед кодом, который мы хотим выполнить, можно обойти некоторые механизмы безопасности.
источник