Comments 26
Откровенно говоря, после shellshock я ожидал пачки подобных уязвимостей. Странно что так долго копались.
В shell-shock'е немного другое было. То есть в целом это «копаемся в старых программах и старых протоколах в поисках garbage in garbage out», но векторы атаки разные.
Плюс shell-shock глубже вошёл (благодаря dhcp).
Плюс shell-shock глубже вошёл (благодаря dhcp).
Разумется другое, но суть ровно такая же: никто не проверяет данные, которые приходят снаружи. Такие же ошибки в SQL (попытка подставить параметры в код вместо того, чтобы использовать ?) — на каждом шагу.
А для чего вообще нужен заголовок Proxy? Какое его истинное предназначение?
1. Дефолтный конфиг для fastcgi от nginx 1.8.1 не передает этот заголовок
2. В php 7.0.9 пофиксили: www.php.net/ChangeLog-7.php#7.0.9
2. В php 7.0.9 пофиксили: www.php.net/ChangeLog-7.php#7.0.9
Вся проблема в модели CGI.
CGI подразумевает, что мы получаем хидеры от запросов пользователей как переменные среды окружения. В то же самое время весь остальной софт считает, что переменные среды окружения — это довренная информация, которая используется администраторами (и локальными пользователями запускающими софт).
Давайте я вам сейча ещё более страшную уязвимость назову такого типа:
LD_PRELOAD.
И я не шучу. Добиваемся, чтобы наша so-шка оказалась в указанном месте на сервере, выставляем LD_PRELOAD в заголовках запроса, после чего наша so'шка выполняется с правами администратора.
(Интересно, апач и остальные LD_PRELOAD фильтруют или я только что новую CVE'шку с remote code execution описал?)
CGI подразумевает, что мы получаем хидеры от запросов пользователей как переменные среды окружения. В то же самое время весь остальной софт считает, что переменные среды окружения — это довренная информация, которая используется администраторами (и локальными пользователями запускающими софт).
Давайте я вам сейча ещё более страшную уязвимость назову такого типа:
LD_PRELOAD.
И я не шучу. Добиваемся, чтобы наша so-шка оказалась в указанном месте на сервере, выставляем LD_PRELOAD в заголовках запроса, после чего наша so'шка выполняется с правами администратора.
(Интересно, апач и остальные LD_PRELOAD фильтруют или я только что новую CVE'шку с remote code execution описал?)
не баг, а фича
На сам деле вроде бы правильно заметили, что добавляется префикс HTTP
На сам деле вроде бы правильно заметили, что добавляется префикс HTTP
Это плохая фича. Точнее, плохой дизайн. Путать источники информации — это всё равно, что читать конфиги для софта из ../users/upload, а потом защищать Важные Конфиги от подмены.
Насчёт HTTP-префикса да, забавно. Получается, что эта «защита» ломается выставлением _PROXY. Плохо прочитал.
Насчёт HTTP-префикса да, забавно. Получается, что эта «защита» ломается выставлением _PROXY. Плохо прочитал.
Нет. Вот если бы переменная называлась HTTP_LD_PRELOAD, то была бы новая CVE-шка.
С правами администратора или веб-сервера?
Кто исполняемый файл запускает, тот его переменные и контролирует. Именно потому у всякого рода sudo так строго с фильтрацией переменных окружения — чтобы не было эскалации привилегий.
Отлично же! Вот именно по этому я и шифрую свой трафик. А не потому, что…
И каким образом это вам помогает?
Скажем, ваш сайт использует API какого-то сервиса, который существует только по HTTP. Ну обратятся к вашему сервису по HTTPS, выставят заголовок Proxy, всё равно при обращении к HTTP API ваш сервис пойдёт по указанному в заголовке адресу.
Даже если API по HTTPS: как правило, для обращения к API используют что-то вроде curl, а он использует переменную HTTP_PROXY и по умолчанию на верификацию сертификата HTTPS-сервера кладёт болт, так что по адресу Proxy спокойно сможет сидеть MitM и ваш сайт это проглотит. Это браузеры показывают красное окошко с пугалками «идентификация сайта не удалась, открывать его может быть опасно», а тут-то это некому показывать.
Если эту верификацию затребовать, то да, при обращении к API через фейковый прокси получим ошибку вроде «API-сервер не отвечает, попробуйте позже», что хорошо.
Скажем, ваш сайт использует API какого-то сервиса, который существует только по HTTP. Ну обратятся к вашему сервису по HTTPS, выставят заголовок Proxy, всё равно при обращении к HTTP API ваш сервис пойдёт по указанному в заголовке адресу.
Даже если API по HTTPS: как правило, для обращения к API используют что-то вроде curl, а он использует переменную HTTP_PROXY и по умолчанию на верификацию сертификата HTTPS-сервера кладёт болт, так что по адресу Proxy спокойно сможет сидеть MitM и ваш сайт это проглотит. Это браузеры показывают красное окошко с пугалками «идентификация сайта не удалась, открывать его может быть опасно», а тут-то это некому показывать.
Если эту верификацию затребовать, то да, при обращении к API через фейковый прокси получим ошибку вроде «API-сервер не отвечает, попробуйте позже», что хорошо.
Поясните в двух словах, если не сложно… может ли быть данная уязвимость опасна для Apache + PHP подключенного через php5_module?
Тестовый скрипт, выглядящий как:
Показывает что переменная HTTP_PROXY все-таки устанавливается при наличии заголовка Proxy в HTTP запросе от пользователя. Ради интереса попробовал поднять тестовый proxy сервер и передать его в заголовке Proxy в HTTP запросе скрипту, в котором осуществлялся GET-запрос через file_get_contents и с помощью curl_exec в PHP. В обоих случаях несмотря на то что в $_SERVER[«HTTP_PROXY»] содержался IP: порт Proxy запрос не пошел через него. Т.е. получается что $_SERVER[«HTTP_PROXY»] PHP при формировании исходящих запросов игнорировал.
В итоге получили, что любой пользователь извне может изменить значение $_SERVER[«HTTP_PROXY»], но исходящие запросы все равно не используют Proxy прописанный там. Стоит ли последовать рекомендациям, подключив mod_headers, чтобы вырезать заголовок Proxy или можно считать что система не подвержена данной уязвимости?
p.s. Или же речь идет только о CGI?
Тестовый скрипт, выглядящий как:
<?php var_dump($_SERVER["HTTP_PROXY"]); ?>
Показывает что переменная HTTP_PROXY все-таки устанавливается при наличии заголовка Proxy в HTTP запросе от пользователя. Ради интереса попробовал поднять тестовый proxy сервер и передать его в заголовке Proxy в HTTP запросе скрипту, в котором осуществлялся GET-запрос через file_get_contents и с помощью curl_exec в PHP. В обоих случаях несмотря на то что в $_SERVER[«HTTP_PROXY»] содержался IP: порт Proxy запрос не пошел через него. Т.е. получается что $_SERVER[«HTTP_PROXY»] PHP при формировании исходящих запросов игнорировал.
В итоге получили, что любой пользователь извне может изменить значение $_SERVER[«HTTP_PROXY»], но исходящие запросы все равно не используют Proxy прописанный там. Стоит ли последовать рекомендациям, подключив mod_headers, чтобы вырезать заголовок Proxy или можно считать что система не подвержена данной уязвимости?
p.s. Или же речь идет только о CGI?
Дело не в $_SERVER, а в $_ENV. Если значение попадёт в $_ENV, значит теоретически уязвимость имеется.
через прокси будет работать библиотеки, берущие прокси из HTTP_PROXY, а не сам php.
Спасибо, уже разобрался… в результате получается что getenv('http_proxy') = $_SERVER[«HTTP_PROXY»]… ну а далее действительно все что использует http_proxy из переменных окружения начинает работать через Proxy. Примером уязвимого кода может быть, например, такой:
Аналогично и использующие переменную среды HTTP_PROXY библиотеки. Вообще интересно было бы краткий список наиболее часто используемых уязвимых библиотек.
function autoDetectProxySettings() {
if (($httpProxy = getenv('http_proxy')) || ($httpProxy = getenv('HTTP_PROXY'))) {
return $httpProxy;
}
}
...
// ну а далее ...
$httpProxy = autoDetectProxySettings();
$ch = curl_init("http://server.url/secret_api");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if (isset($httpProxy)) { curl_setopt($ch, CURLOPT_PROXY, $httpProxy); }
$result = curl_exec($ch);
Аналогично и использующие переменную среды HTTP_PROXY библиотеки. Вообще интересно было бы краткий список наиболее часто используемых уязвимых библиотек.
Для python-requests уже давно придумали обход:
import requests
session = requests.Session()
session.trust_env = False
response = session.get('http://www.stackoverflow.com')
Но вообще, конечно, подстава.
import requests
session = requests.Session()
session.trust_env = False
response = session.get('http://www.stackoverflow.com')
Но вообще, конечно, подстава.
Sign up to leave a comment.
Уязвимость HTTPoxy позволяет перенаправлять http-запросы веб-приложений