Как стать автором
Обновить

Уязвимость HTTPoxy позволяет перенаправлять http-запросы веб-приложений

Время на прочтение 3 мин
Количество просмотров 16K
Всего голосов 18: ↑17 и ↓1 +16
Комментарии 26

Комментарии 26

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

В shell-shock'е немного другое было. То есть в целом это «копаемся в старых программах и старых протоколах в поисках garbage in garbage out», но векторы атаки разные.

Плюс shell-shock глубже вошёл (благодаря dhcp).

Разумется другое, но суть ровно такая же: никто не проверяет данные, которые приходят снаружи. Такие же ошибки в SQL (попытка подставить параметры в код вместо того, чтобы использовать ?) — на каждом шагу.

Да. Смешивают источники — доверенные строки в коде с недоверенными строками со входа от пользователя.
А для чего вообще нужен заголовок Proxy? Какое его истинное предназначение?
А, всё, почитал источник и разобрался в чём суть уязвимости. Дело не в том, что именно Proxy превращается в HTTP_PROXY, а вообще любые заголовки превращаются в переменные окружения с префиксом «HTTP_».
НЛО прилетело и опубликовало эту надпись здесь
В общем и целом — да.
1. Дефолтный конфиг для fastcgi от nginx 1.8.1 не передает этот заголовок
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 описал?)
не баг, а фича
На сам деле вроде бы правильно заметили, что добавляется префикс HTTP
Это плохая фича. Точнее, плохой дизайн. Путать источники информации — это всё равно, что читать конфиги для софта из ../users/upload, а потом защищать Важные Конфиги от подмены.

Насчёт HTTP-префикса да, забавно. Получается, что эта «защита» ломается выставлением _PROXY. Плохо прочитал.
"_" (простите за нечаянный смайл ^_^') уже содержится в добавляемом префиксе, поэтому http-заголовок должен быть просто «Proxy».

И пожалуй да, проблема в архитектуре CGI
Нет. Вот если бы переменная называлась HTTP_LD_PRELOAD, то была бы новая CVE-шка.
С правами администратора или веб-сервера?
Кто исполняемый файл запускает, тот его переменные и контролирует. Именно потому у всякого рода sudo так строго с фильтрацией переменных окружения — чтобы не было эскалации привилегий.
Я к тому, что CGI выполняется же через web, следовательно права будут веб сервера, а не администратора?
Но этого достаточно например для того, чтобы стырить или испортить базу данных, к которой это CGI-приложение обращается.
Отлично же! Вот именно по этому я и шифрую свой трафик. А не потому, что…
И каким образом это вам помогает?

Скажем, ваш сайт использует API какого-то сервиса, который существует только по HTTP. Ну обратятся к вашему сервису по HTTPS, выставят заголовок Proxy, всё равно при обращении к HTTP API ваш сервис пойдёт по указанному в заголовке адресу.

Даже если API по HTTPS: как правило, для обращения к API используют что-то вроде curl, а он использует переменную HTTP_PROXY и по умолчанию на верификацию сертификата HTTPS-сервера кладёт болт, так что по адресу Proxy спокойно сможет сидеть MitM и ваш сайт это проглотит. Это браузеры показывают красное окошко с пугалками «идентификация сайта не удалась, открывать его может быть опасно», а тут-то это некому показывать.

Если эту верификацию затребовать, то да, при обращении к API через фейковый прокси получим ошибку вроде «API-сервер не отвечает, попробуйте позже», что хорошо.
Поясните в двух словах, если не сложно… может ли быть данная уязвимость опасна для Apache + PHP подключенного через php5_module?

Тестовый скрипт, выглядящий как:
<?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. Примером уязвимого кода может быть, например, такой:

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 библиотеки. Вообще интересно было бы краткий список наиболее часто используемых уязвимых библиотек.
так точно.
Список есть в принципе. Самые известные это наверное guzzle для php, и requests для питона.
Для python-requests уже давно придумали обход:

import requests
session = requests.Session()
session.trust_env = False
response = session.get('http://www.stackoverflow.com')

Но вообще, конечно, подстава.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий