|
|
|||||||||||||||||||||||||||||
|
Анатомия атаки: Как я взломал StackOverflowИсточник: habrahabr truezemez
Почти два года назад я наткнулся на довольно значительную уязвимость в сети сайтов StackExchange. Я говорю "наткнулся" потому, что я не пытался взломать сайт. Обстоятельства приоткрыли мне дверь. Сама уязвимость является довольно интересной, и содержит урок для всех, кто создает и занимается поддержкой сайтов или серверной инфраструктуры. Итак, вот история о том, как я взломал StackOverflow … Исходные данныеВ то время я работал в небольшой компании, где имелся фаервол с совершенно драконовскими ограничениями. Он резал все заголовки запросов и ответов, не соответствующие спецификации HTTP/1.1 (и даже резал валидные HTTP/1.1 заголовки). Это играло злую шутку с сайтами, которые полагаются на такие вещи, как X-Requested-With . Поэтому, для своих "внешних похождений", я настроил прокси.
У меня было несколько серверов в то время, так что я просто поставил на одном из них Squid. Так как я кое-что соображал, я разрешил подключения к прокси только с Для тех из вас, кто хочет мне сказать, что я поступил плохо, я хочу обратить ваше внимание на то, что у меня была возможность сделать это. И не просто возможность, мне открыто было сказано использовать прокси, так как мы должны были работать с некоторыми сайтами, которые не работали через наш фаервол. Так что я не делал ничего "неправильного".
АтакаВ то время я часто бывал в чате StackOverflow. Тогда он еще только появился, и в нем была парочка багов. В один прекрасный день сайт начал показывать мне стек вызовов. Я не придал этому значения, так как часто встречался с этим по всему интернету. Вообще-то, почти каждый раз, когда я получал сообщение об ошибке на сайте, написанном на ASP.NET, я видел стек вызовов. И тут я заметил новый пункт меню в чате. Этот новый пункт меню назывался "Admin". Чисто из любопытства, я нажал на ссылку, полагая, что мне будет отказано в доступе. То, что произошло дальше, удивило меня. Я получил полный доступ ко всему. У меня была консоль разработчика, где я мог видеть кто что делает. У меня был интерфейс для работы с базой данных, где я мог напрямую запрашивать что угодно из любой базы данных. Я получил полные админские права.
Что произошло дальшеСледующее, что я сделал - сразу сообщил об этом модератору. Через несколько минут я был в приватном чате с модератором, а также двумя разработчиками. Причина была найдена приблизительно в течение 10 минут. Еще через 10 минут проблема была решена поверхностно. На полное исправление ушла пара часов. Они отлично сработали. У меня до сих пор лежит лог того чата, и я хочу сказать, что эти разработчики заслуживают всяческих похвал. Они ответили быстро и профессионально. И решили проблему в кратчайшие сроки.
УязвимостьЕсли вы сообразительны, то, скорее всего, догадались, что произошло. Так как я выходил через прокси, к моим запросам добавлялся заголовок X-Forwarded-For . Значением этого заголовка был IP с которого запрашивался прокси-сервер. Но, так как я подключался к прокси через SSH туннель, IP был локальный. Так что Squid добавил X-Forwarded-For: 127.0.0.1 …
Но самое интересное было то, что показывал ASP в логах. Когда они посмотрели дампы моих запросов, там красовалась запись
ВыводыНикогда не полагайтесь на X-Forwarded-For , как мы видим - это не безопасно. Всегда используйтеREMOTE_ADDR . Здесь стоит задуматься, нужна ли вам вообще защита, основанная на IP. Или, по крайней мере, не стоит на нее полностью полагаться, а использовать лишь как дополнительную меру.
Интересно отметить, что разработчики действительно использовали надлежащую проверку заголовков. Суть в том, что вы никогда не должны слепо доверять вашей инфраструктуре. Эта дыра появилась из-за разницы конфигурации между сервером и приложением. Такие мелочи случаются каждый день. Приложение предполагает одно, а сервер - другое. Проблема в том, что такое доверие может полностью подорвать безопасность. В этом случае, разработчики доверяли значению Команда StackOverflow великолепно решила этот вопрос. Быстро, отзывчиво и разумно. Они попросили меня о помощи (которую я с удовольствием предоставил), и вели себя профессионально и уважительно. Они проделали фантастическую работу. Мы все должны извлечь урок. Реагировать на сообщения о уязвимостях серьезно. Решать вопрос профессионально и быстро.
Что касается PHPСамое интересное здесь то, что приложения, написанные на PHP, могут иметь такую же уязвимость. Смотрим Symfony2 Request class. Выглядит отлично. Пока вы не заметите, что он использует статическую переменную, чтобы определить, следует ли доверять прокси. Это означает, что если любая часть вашего приложения захочет получить заголовки от прокси (например, для записи в лог), все ваше приложение после этого будет получать загловоки именно от прокси. Чтобы увидеть, подвержен ли ваш код подобной уязвимости, поищите в нем вызов $request->trustProxy() . Также обратите внимание, что обратного механизма нет. Вы не можете "перестать доверять" прокси. Я думаю, это большой архитектурный просчет…
Zend Framework 2 поступает аналогично. Он имеет класс, который ведет себя похожим образом (в плане получения IP). Интересно, что в Zend Framework 1 способ получения IP-адреса был адекватным. Вызывающий код должен явно указывать что он хочет получить, а по-умолчанию должен быть безопасный вариант.
ЗаключениеЭта проблема стала результатом сочетания двух мелких просчетов. По отдельности их очень легко упустить из виду. Но если они сойдутся определенным образом, вы получите очень серьезную угрозу безопасности. И самый большой урок в том, что вы действительно не можете доверять чему-либо за пределами вашего приложения. Если вы можете обойти это (например, не доверяя заголовкам и переменным, вроде REMOTE_ADDR ), то вы можете сделать ваше приложение более безопасным. Но, прежде всего, думайте о коде, который вы пишете и о системах, которые вы строите. И поддерживайте их.
Ссылки по теме
|
|