Введение:
Всех приветствую! В последнее время, в отчетах компаний по безопасности, в баг баунти программах и прочих местах публичных “казней” уязвимостей все чаще стала светиться аббревиатура SSRF. Расшифровываются эти буквы как Server Side Request Forgery, или подделка запроса на серверной стороне. И если верить описанию – эта уязвимость может сыграть очень злую шутку с компаниями, которые хостят свои проекты не на сторонних сервисах, а на собственных серверах, которые связаны с внутренней сетью. Речь здесь конечно-же в первую очередь о компаниях, работа которых напрямую связана с их сайтами, т.е. крупные компании, которые имеют свой веб-продукт, требующий отдельной инфраструктуры. Эта уязвимость, судя из описания, может помочь атакующему просканировать внутреннюю сеть кампании, получить доступ к DMZ, использовать внутрение API-сервисы и т.д, то есть, получить возможность взаимодействовать с внутренней сетью компании.
Возможно вы заметили сходство названия с другой популярной уязвимостью – CSRF или Client Side Request Forgery, “подделка запроса на клиентской стороне”. Да, действительно, уязвимости по сути “две стороны одной медали”, но на практике они очень сильно различаются, начиная от причин возникновения, заканчивая методами раскрутки, эксплуатацией и профитом. Поэтому, о подделке запроса на клиентской стороне поговорим в другой раз, а сейчас обратим внимание на SSRF – что это, откуда появляется, для чего используется и т.д. Погнали!
Теория:
Итак, Server Side Request Forgery. Уязвимость, которая может послужить дверью во внутреннюю сеть проекта. Как это вообще выглядит в теории ? Представим следующюю картину:
У нас есть:
1 – атакующий. Непосредственно хакер, который хочет получить доступ к внутреней сети кампании.
2 – уязвимое приложение, в котором есть SSRF. В нашем случае оно послужит мостом между внешней сетью и внутренним периметром. Извне сервер доступен по доменному имени site-vuln.com, а его внутренний адрес – 192.168.1.1
3 – внутренний сервер компании, содержащий каку-либо чувствительную информацию. Например базу данных, или какой либо сервис управления сетью или контейнерами, например тот же kubernetes. Доступен только во внутреней сети по адресу 192.168.1.2, доступ во внешнюю не имеет.
Как мы видим, находится сервер 3 во внутреней сети и получить доступ к нему напрямую хакер с машины 1 не может. Но есть сервер 2, на котором крутится веб-приложение, доступное извне и этот сервер доступен как из внешней сети интернет, так и во внутреней сети кампании он тоже виден. Логично, что для того, чтобы попасть во внутреннюю сеть кампании, нужно скомпроментировать сервер с веб-приложением, после чего уже доступ во внутреннюю сеть кампании будет открыт. Есть масса способов взломать этот сервер, и не только по пути веб-уязвимостей, но конкретно сейчас мы говорим о SSRF. И в случае присутствия уязвимости в веб приложении, можно при ее помощи собрать очень много интересной информации о внутреннем периметре.
Для более полного понимания с точки зрения теории, добавим деталей .Предположим, на данном сервере, в качестве веб-приложения выступает какое-либо средство коммуникации – чат, мини социальная сеть, форум или что-то такое. А на сервере 3 крутится, например, база данных, к которой и подключается наше веб-приложение на сервере 2.
А теперь к самой уязвимости. Я буду использовать достаточно популярный пример, на котором обычно и обьясняют чем опасна уязвимость. Так как на нашем воображаемом сервере 2 развернут воображаемый чат, в нем есть воображаемая функция создания визитных карточек для URL =) Эта фишка сейчас активно так используется в разработке. Ее можно встретить в месенджерах, таких как телеграм и ватсап, социальных сетях по типу ВК, и даже на этом форуме эта фишка присутствует. Заключается она в том, что когда пользователь вбивает в сообщение ссылку на какой-либо внешний ресурс или, возможно внутреннюю страницу ресурса, на бэкенде формируется и прикрепляется к сообщению некая “визитная карточка”, которая содержит краткую информацию о ресурсе, на который ведет ссылка – иконка ресурса, название, краткая информация о том, куда ведет URL.
Более подробно остановимся на этой функции, так как в нашем примере именно она приведет к SSRF. Как вообще происходит процесс создания визитки ? Сначала бэкенд формирует запрос ко внешнему ресурсу, по адресу или доменному имени, указаному пользователем, и запрашивает с него всю необходимую информацию для создания визитки: иконку, краткое описание ресурса, название и т.д. После этого формируется визитка и прикрепляется к сообщению. То есть правильное использование будет выглядеть примерно так:
Однако, а что если для формирования визитки пользователь укажет не внешний адрес, а внутрений ? Например, как раз адрес внутреннего SQL-сервера – 192.168.1.2:
Да, пользователь не может знать наверняка адреса внутри периметра, но учитвая что для локальных сетей есть определенные диапазоны, угадать возможные адреса будет не так уж сложно. В итоге, наше веб-приложение образует запрос во внутренюю сеть, который и послужит отправной точкой для раскрутки и дальшнейшей атаки на внутрений периметр кампании. И в визитке, сформированой нашим бэкендом, может оказаться чувствительная информация о внутренем сервере. К чему это может привести ?Да к чему угодно, начиная от сканирования сети и заканчивая формированием произвольных TCP запросов, при помощи определенных протоколов. Но более подробно о том, как использовать уязвимость мы разберем чуть позже, сначала посмотрим как ее найти и как начать раскручивать. Об этом следующая часть статьи:
Поиск и эксплуатация:
Для примера я возьму уязвимое веб-приложение xvwa, которое содержит большое колчество уязвимостей и служит как раз для примеров и отработки навыков.
скачать исходики приложения можно тут:
https://github.com/s4n7h0/xvwa
либо взять готовую машину с vulnhub:
https://www.vulnhub.com/entry/xtreme-vulnerable-web-application-xvwa-1,209/
Ну и лабораторию я смоделирую таким же образом, как и в практическом примере – в ней будет три машины:
1. Моя основная машина, которая будет выступать в роли машины атакующего
2. Машина с XVWA. Она подключена и в сеть_1 и в сеть_2. Подразумевается что первый адапер моделирует подключение во внешнюю сеть, а второй – во внутреннюю.
3. Сервер, на котором крутятся какие-то сервисы. Выступает в роли жертвы, которую мы и будем пытаться скомпроментировать через вторую машину. Находится только в сети 2, из сети 1 доступ получить невозможно.
Приступим. Нас интересует раздел SSRF/XSPA:
На странице мы видим форму для ввода url изображения, которое впоследствии подгружается на страницу. Достаточно популярная практика, например, для подгрузки аватарок пользователей и дальнейшей их обработки. Попробуем загрузить какое-либо изображение со стороннего ресурса:
Как видим, лого загружается, все в порядке. Но что будет если попробовать передать не ссылку на внешний ресурс, а на внутренний ip-адрес ? Попробуем указать адрес сервера, который находится в нашей сети под адресом 192.168.1.7:
И получаем ошибку connection refused. И этого мы изначально и добивались, ведь текст ошибки говорит о том, что хост живой, просто невозможно подключится к веб-серверу на этом хосте, так как он не запущен на дефолтном порте 80. А если мы попробуем обратиться к IP-адресу сервера, которого нет в этой сети (хост мертвый, либо отсутствует), то получим уже другую ошибку – No route to host:
И вот таким нехитрым образом мы можем собрать информацию о том, какие хосты и под какими адресами находятся во внутренней сети кампании. А знание, как известно – сила. Эта информация может очень сильно помочь в дальнейшем взломе сети. Но мы можем пойти еще дальше и собрать информацию не только о хостах, но и о сервисах, которые на них крутятся. То есть, просканить порты. Вернемся к названию страницы – в нем помимо SSRF есть аббривиатура XSPA. Именно эта уязвимость нам и поможет в определеннии серисов. Что такое XSPA ?
XSPA - подвид уязвимости SSRF, который расшифровывается как Cross Site Port Attack. Этот подвид уязвимости, а точнее вектор атаки и позволяет в некоторых случаях помочь просканировать сеть на наличие хостов и открытых портов через SSRF. Именно это мы сейчас и попробуем сделать – просканировать вторую внутреннюю сеть через SSRF на наличие сервисов на открытых портах.
И ничего волшебного и супер-сложного для этого делать не придется: достаточно просто в url, после адреса, в стандартном формате через двоеточие указать еще и порт:
http://192.168.1.7:20/
И вот что мы получим, в том случае, если попробуем подключится на 80 порт и укажем несуществующее название файла:
Мы видим ошибку HTTP версии 1.1 и код ответа веб-сервера. Не особо много. Но если мы попробуем обратиться к дефолтному порту ssh – 22, то увидим уже следующее:
А это уже банер openssh, в котором указана версия протокола и ПО. Ценность такой информации для атакующего сложно переоценить.
А что еще можно сделать, имя в своем распоряжении такую уязвимость ? Об этом в следующих частях статьи.
Под капотом:
Уязвимый код, к слову, выглядит следующим образом:
Если вкратце – создается переменная image. Далее получается и проверяется на наличие POST-параметр img-url, в котором и передается ссылка. После этого при помощи функции file_get_contents() получается доступ к содержимому файла, рандомно устанавливается имя, и файл и имя ссылки выводится на страницу. И все, никаких проверок, плюс еще и вывод ошибок включен (первые две строки). А еще, если присмотрется к месту, где выводится введеная пользователем ссылка, то можно заметить XSS. Вообщем, если соберетесь писать что-то подобное – не надо так =)
Еще потенциальные места, где может обнаружится SSRF:
Помимо явных обращений по доменным именам и ссылкам, SSRF может обнаружится и в других местах. Вот список нескольких “мест” в веб-приложении, в которых может обнаружится уязвимость:
Векторы раскрутки:
Сканирование сети
Про этот вектор мы уже поговорили выше. Добавить к этому можно то, что далеко не всегда подобные ошибки будут появляться на странице. Поэтому, если у вас есть подозрения, что страница уязвима, проверяйте реакцию страницы на передачу внутренних адресов. Cтраница может, например, по странному реагировать на передачу адресов не живых хостов, скажем, просто не прогружатся. Ну или даже может быть такое, что информация о результате подключения записывается внутрь файла, который должен быть картинкой.(пример далее в эксплуатации “file-url”)В этом случае файл можно скачать и посмотреть содержимое при помощи блокнота, т.к. браузер такое прочеcть не в состоянии.
Получение доступа к метаинформации
В случае, если компания использует облачную инфраструктуру, такую как Azure или google cloud, то атакующий может получить доступ к чувствительной информации, которая находится на дефолтном для большинства “облаков” ip-адресе:
169.254.169.254
Там находятся файлы, которые опять же могут помочь скомпроментировать систему, такую как информация о хостах внутри сети, работающих службах, а так же, иногда сами разработчики скалдывают в это хранилище API-ключи или какие-то данные, которые лучше держать в секрете.
Просмотр локальных файлов через file://
Так же, в некоторых случаях можно просмотреть локальные файлы уязвимого сервера через схему URL file. Рассмотрим как это происходит все на том же примере:
Схема в URL в нашем случае выглядит следующим образом:
file://<путь к файлу>
Попробуем получить доступ к файлу /etc/passwd, который в пингвиньих системах содержит информацию о пользователях на сервере:
Как видим - никаких ошибок мы не получаем, и вроде как даже jpg файл был создан. А если он был создан, то попробуем посмотреть его содержимое. Браузер, к сожалению, показать содержимое не сможет, потому что обращается к файлу как к графическому изображению, а не как к текстовому файлу:
Пойдем другим путем. Скачаем созданый файл себе на машину при помощи wget:
И если мы попытаемся посмотреть содержимое при помощи дефолтной команды cat, мы увидим содержимое файла /etc/passwd.
Формирование произвольных запросов при помощи протокола gopher
Есть такой очень старый протокол – gopher. Этот протокол хоть как-то использовался еще в конце прошлого века, но впоследствии его вытеснил всем нам известный www. Изначально этот протокол задумывался как конкурент FTP, однако с развитием мировой паутины почти канул в лету. Но, не везде. В некоторых системах можно все еще встретить поддержку этого протокола, и если уязвимый сервер поддерживает gopher, то это дает очень большое пространство для маневров, ведь при помощи этого протокола можно захватить контроль практически над всем TCP-потоком и формировать запросы для разных протоколов, а не только для http. Как пример, вот так выглядит smtp запрос, сформированый при помощи gopher:
gopher://smtp/_<TCP-payload>
То есть, при создании ссылка формируется по следующему правилу:
gopher://<protocol>:<port>/x<url-encode payload>
где url-encode payload – это зашифрованый в URL TCP-пакет. То, есть, например в случае с smtp этот пакет выглядит так:
Протокол очень старый, и мало где поддерживается (например php его вообще не поддерживает, а java и asp.net поддерживают только в старых версиях). Но если вам повезло и вы обнаружили что в уязвимом сервисе пристуствует поддержка этого протокола, вы можете сформировать и отправить в сеть разные tcp-пакеты, что само по себе – очень полезная возможность, знать о которой стоит.
Ну а помочь с этим может инструмент gopherus (ставить на свой страх и риск):
github.com
Этот инструмент помогает сформировать различные полезные нагрузки для разных протоколов при помощи протокола gopher.
Формирование и выполнение произвольных HTTP-GET запросов
Наверное одна из самых безобидных фишек – формирование и отправка запросов от имени веб-сервера. Если мы можем заставить сервер отправить запрос во внутреннюю сеть по http, то логично что мы можем сформировать GET-запрос к какому-либо внутренему приложению. Приведу пример – на внутреннем сервере разверну простенькое веб-приложение, которое просто получает по GET-запросу параметр “test” и записывает его в файл text.txt на сервере. Изначально на сервере есть только скрипт, который доступен по дефолтному порту 80 и доступен сервер только из внутреней сети. Но если в поле URL мы подставим ссылку типа “http://192.168.1.7/index.php?test=i’m_in!” а затем снова проверим сервер, то увидим что запрос был выполнен и у нас появился файл test.txt, с содержимым, которое мы отправили в параметре test:
Почему эта фишка одна из самых безобидных ? Потому что на практике вам должно очень повезти, чтобы вы могли нормально ее применить. Внутри сети должен находится сервер с веб-приложением, принимающим по GET какие-либо данные, которые в дальнейшем как-то используются в системе, что мы можем этим воспользоваться. При этом вы должны знать об этом приложении, знать имя параметра и т.д. Вообщем, слишком много звезд должно сойтись, чтобы этот вектор можно было реально применить. Однако, знать о нем стоит.
Пару слов про обход защиты:
С первого взгляда уязвимость достаточно легко фиксится: нужно просто вбить локальные адреса в черный и список и на этом все. Однако, все не так просто. Если код просто будет проверять ip на то, попадает ли он в диапазон локальных адресов или нет – это изначально плохой метод защиты, который легко обходится. Есть достаточно много сопособов обойти такую защиту, вот некоторые из них:
Собственные DNS-записи
Первый, простой, логичный и вполне себе рабочий способ – создание собственной DNS-записи, с указанием локального адреса. Как известно – имя домена, это просто оболочка, за которой, как за записью в телефонной книге, скрывается адрес. Ничто не мешает хакеру купить дешевый домен с указанием локального адреса в качестве самой записи. Как итог – если на первом этапе пользовательская ссылка была проверена и вела она на внешний домен, то уже при обращении к домену, приложению будет передан локальный адрес. И если это не проверяется на сервере второй раз – то запрос будет отправлен во внутренюю сеть.
Редиректы через 301, 302, 303 и 307, 308 http-коды
Второй, не менее простой способ – редиректы. Те, кто хоть немного знакомы с HTTP протоколом знают, что там есть такая фишка как редиректы – когда при попытке обратиться к определенной странице или директории на сервере, веб-сервер выдает редиректный (301 или 302 для GET, и 307 для POST -запроса) код ответа, который подразумевает перенаправление в другое место. В ответе от веб-сервера есть заголовок, который и определяет куда перенаправить обратившегося.
А теперь представьте следующую ситуацию: сервер получает на обработку адрес, проверяет его. Видит, что адрес к локальным никак не относится и отправляет туда запрос на получение данных. А в ответ получает заголовок с кодом редиректа на локальный адрес. И, как правило, о проверке адреса в таких ситуациях разработчики уже не думают и запрос спокойно летит в сеть.
Альтернативное представление локальных адресов
Еще один способ – альтернативная запись ip-адресов. Мы привыкли видеть ip-адреса в виде дестяичных значений по четыре блока (октета), в диапазоне от 0 до 255. Однако есть другие виды записи адресов, что вполне себе поддерживается разными технологиями. Вот некоторые примеры:
1. Исключение нулей из адреса.
В некоторых случаях, нули в адресе можно опустить, превратив таким образом, например, адрес 127.0.0.1 в 127.1
2. Запись в других системах счисления.
Октеты так же могут быть записаны в 8-ричной и 16-ричной системах счисления. Таким образом адрес 192.168.1.7 в 8-ричной системе будет выглядеть как 300.250.1.7 или 00c0.00a8.0001.0007 в 16-ричной. Так же, эти системы счисления можно сочетать, записав часть октетов в 16-ричной, часть в 8-ричной, а часть в 10-тичной системах счилсения.
3. Запись одним числом.
Так же, адрес можно представить в виде одного числа, не разделяя его на октеты. Высчитывается такой адрес следующим образом:
(1)*256^3+(2)*256^2+(3)*256^1+(4)*256^0
где (1),(2) и т.д. - номера октетов. То есть для адреса 192.168.1.7 подобный числовой адрес вычисляется так:
192*256^3+168*256^2+1*256^1+7*156^0 = 3232235783
И ссылка будет уже выглядеть так: http://3232235783
И уже это число можно по аналогии перевести в 8ричную или 16-ричную системы счисления, и это тоже будет работать
Таким образом, систему защиты, проверяющую адреса на “локальность” можно легко обойти при помощи одной из вышеупомянутых техник. Поэтому действительно правильным методом защиты будет комплексная защита – ограничение поддерживаемых схем и допустимых портов, тщательная проверка передаваемого адреса, минимизация взаимодействия потенциально уязвимых серверов с инфраструктурой и т.д.
Заключение:
SSRF – достаточно опасная уязвимость. Хотя она напрямую и не позволяет захватить контроль над сервером или данными, но она может помочь раздобыть очень важную информацию о внутренем периметре и на основе уже этих знаний разработать полноценный план атаки на сеть. А как показывает практика внутрение сети защищают обычно куда хуже, чем следовало бы. Там и аккаунты без паролей, и машины с устаревшим ПО, и разные раздолбайски настроеные сервисы. Поэтому, SSRF может стать той самой открытой форточкой, через которую атакующий сможет собрать кучу ценной информации, чтобы впоследствии нагнуть всю сеть.
А я на этом с темой SSRF заканчиваю, всем добра!
© Urob0ros, специально для форума xss.pro
Всех приветствую! В последнее время, в отчетах компаний по безопасности, в баг баунти программах и прочих местах публичных “казней” уязвимостей все чаще стала светиться аббревиатура SSRF. Расшифровываются эти буквы как Server Side Request Forgery, или подделка запроса на серверной стороне. И если верить описанию – эта уязвимость может сыграть очень злую шутку с компаниями, которые хостят свои проекты не на сторонних сервисах, а на собственных серверах, которые связаны с внутренней сетью. Речь здесь конечно-же в первую очередь о компаниях, работа которых напрямую связана с их сайтами, т.е. крупные компании, которые имеют свой веб-продукт, требующий отдельной инфраструктуры. Эта уязвимость, судя из описания, может помочь атакующему просканировать внутреннюю сеть кампании, получить доступ к DMZ, использовать внутрение API-сервисы и т.д, то есть, получить возможность взаимодействовать с внутренней сетью компании.
Возможно вы заметили сходство названия с другой популярной уязвимостью – CSRF или Client Side Request Forgery, “подделка запроса на клиентской стороне”. Да, действительно, уязвимости по сути “две стороны одной медали”, но на практике они очень сильно различаются, начиная от причин возникновения, заканчивая методами раскрутки, эксплуатацией и профитом. Поэтому, о подделке запроса на клиентской стороне поговорим в другой раз, а сейчас обратим внимание на SSRF – что это, откуда появляется, для чего используется и т.д. Погнали!
Теория:
Итак, Server Side Request Forgery. Уязвимость, которая может послужить дверью во внутреннюю сеть проекта. Как это вообще выглядит в теории ? Представим следующюю картину:
У нас есть:
1 – атакующий. Непосредственно хакер, который хочет получить доступ к внутреней сети кампании.
2 – уязвимое приложение, в котором есть SSRF. В нашем случае оно послужит мостом между внешней сетью и внутренним периметром. Извне сервер доступен по доменному имени site-vuln.com, а его внутренний адрес – 192.168.1.1
3 – внутренний сервер компании, содержащий каку-либо чувствительную информацию. Например базу данных, или какой либо сервис управления сетью или контейнерами, например тот же kubernetes. Доступен только во внутреней сети по адресу 192.168.1.2, доступ во внешнюю не имеет.
Как мы видим, находится сервер 3 во внутреней сети и получить доступ к нему напрямую хакер с машины 1 не может. Но есть сервер 2, на котором крутится веб-приложение, доступное извне и этот сервер доступен как из внешней сети интернет, так и во внутреней сети кампании он тоже виден. Логично, что для того, чтобы попасть во внутреннюю сеть кампании, нужно скомпроментировать сервер с веб-приложением, после чего уже доступ во внутреннюю сеть кампании будет открыт. Есть масса способов взломать этот сервер, и не только по пути веб-уязвимостей, но конкретно сейчас мы говорим о SSRF. И в случае присутствия уязвимости в веб приложении, можно при ее помощи собрать очень много интересной информации о внутреннем периметре.
Для более полного понимания с точки зрения теории, добавим деталей .Предположим, на данном сервере, в качестве веб-приложения выступает какое-либо средство коммуникации – чат, мини социальная сеть, форум или что-то такое. А на сервере 3 крутится, например, база данных, к которой и подключается наше веб-приложение на сервере 2.
А теперь к самой уязвимости. Я буду использовать достаточно популярный пример, на котором обычно и обьясняют чем опасна уязвимость. Так как на нашем воображаемом сервере 2 развернут воображаемый чат, в нем есть воображаемая функция создания визитных карточек для URL =) Эта фишка сейчас активно так используется в разработке. Ее можно встретить в месенджерах, таких как телеграм и ватсап, социальных сетях по типу ВК, и даже на этом форуме эта фишка присутствует. Заключается она в том, что когда пользователь вбивает в сообщение ссылку на какой-либо внешний ресурс или, возможно внутреннюю страницу ресурса, на бэкенде формируется и прикрепляется к сообщению некая “визитная карточка”, которая содержит краткую информацию о ресурсе, на который ведет ссылка – иконка ресурса, название, краткая информация о том, куда ведет URL.
Более подробно остановимся на этой функции, так как в нашем примере именно она приведет к SSRF. Как вообще происходит процесс создания визитки ? Сначала бэкенд формирует запрос ко внешнему ресурсу, по адресу или доменному имени, указаному пользователем, и запрашивает с него всю необходимую информацию для создания визитки: иконку, краткое описание ресурса, название и т.д. После этого формируется визитка и прикрепляется к сообщению. То есть правильное использование будет выглядеть примерно так:
Однако, а что если для формирования визитки пользователь укажет не внешний адрес, а внутрений ? Например, как раз адрес внутреннего SQL-сервера – 192.168.1.2:
Да, пользователь не может знать наверняка адреса внутри периметра, но учитвая что для локальных сетей есть определенные диапазоны, угадать возможные адреса будет не так уж сложно. В итоге, наше веб-приложение образует запрос во внутренюю сеть, который и послужит отправной точкой для раскрутки и дальшнейшей атаки на внутрений периметр кампании. И в визитке, сформированой нашим бэкендом, может оказаться чувствительная информация о внутренем сервере. К чему это может привести ?Да к чему угодно, начиная от сканирования сети и заканчивая формированием произвольных TCP запросов, при помощи определенных протоколов. Но более подробно о том, как использовать уязвимость мы разберем чуть позже, сначала посмотрим как ее найти и как начать раскручивать. Об этом следующая часть статьи:
Поиск и эксплуатация:
Для примера я возьму уязвимое веб-приложение xvwa, которое содержит большое колчество уязвимостей и служит как раз для примеров и отработки навыков.
скачать исходики приложения можно тут:
https://github.com/s4n7h0/xvwa
либо взять готовую машину с vulnhub:
https://www.vulnhub.com/entry/xtreme-vulnerable-web-application-xvwa-1,209/
Ну и лабораторию я смоделирую таким же образом, как и в практическом примере – в ней будет три машины:
1. Моя основная машина, которая будет выступать в роли машины атакующего
2. Машина с XVWA. Она подключена и в сеть_1 и в сеть_2. Подразумевается что первый адапер моделирует подключение во внешнюю сеть, а второй – во внутреннюю.
3. Сервер, на котором крутятся какие-то сервисы. Выступает в роли жертвы, которую мы и будем пытаться скомпроментировать через вторую машину. Находится только в сети 2, из сети 1 доступ получить невозможно.
Приступим. Нас интересует раздел SSRF/XSPA:
На странице мы видим форму для ввода url изображения, которое впоследствии подгружается на страницу. Достаточно популярная практика, например, для подгрузки аватарок пользователей и дальнейшей их обработки. Попробуем загрузить какое-либо изображение со стороннего ресурса:
Как видим, лого загружается, все в порядке. Но что будет если попробовать передать не ссылку на внешний ресурс, а на внутренний ip-адрес ? Попробуем указать адрес сервера, который находится в нашей сети под адресом 192.168.1.7:
И получаем ошибку connection refused. И этого мы изначально и добивались, ведь текст ошибки говорит о том, что хост живой, просто невозможно подключится к веб-серверу на этом хосте, так как он не запущен на дефолтном порте 80. А если мы попробуем обратиться к IP-адресу сервера, которого нет в этой сети (хост мертвый, либо отсутствует), то получим уже другую ошибку – No route to host:
И вот таким нехитрым образом мы можем собрать информацию о том, какие хосты и под какими адресами находятся во внутренней сети кампании. А знание, как известно – сила. Эта информация может очень сильно помочь в дальнейшем взломе сети. Но мы можем пойти еще дальше и собрать информацию не только о хостах, но и о сервисах, которые на них крутятся. То есть, просканить порты. Вернемся к названию страницы – в нем помимо SSRF есть аббривиатура XSPA. Именно эта уязвимость нам и поможет в определеннии серисов. Что такое XSPA ?
XSPA - подвид уязвимости SSRF, который расшифровывается как Cross Site Port Attack. Этот подвид уязвимости, а точнее вектор атаки и позволяет в некоторых случаях помочь просканировать сеть на наличие хостов и открытых портов через SSRF. Именно это мы сейчас и попробуем сделать – просканировать вторую внутреннюю сеть через SSRF на наличие сервисов на открытых портах.
И ничего волшебного и супер-сложного для этого делать не придется: достаточно просто в url, после адреса, в стандартном формате через двоеточие указать еще и порт:
http://192.168.1.7:20/
И вот что мы получим, в том случае, если попробуем подключится на 80 порт и укажем несуществующее название файла:
Мы видим ошибку HTTP версии 1.1 и код ответа веб-сервера. Не особо много. Но если мы попробуем обратиться к дефолтному порту ssh – 22, то увидим уже следующее:
А это уже банер openssh, в котором указана версия протокола и ПО. Ценность такой информации для атакующего сложно переоценить.
А что еще можно сделать, имя в своем распоряжении такую уязвимость ? Об этом в следующих частях статьи.
Под капотом:
Уязвимый код, к слову, выглядит следующим образом:
PHP:
<?php
error_reporting(E_ALL);
ini_set('display_errors',1);
$image = "";
if(isset($_POST['img_url'])){
$remote_content = file_get_contents($_POST['img_url']);
$filename = "./images/".rand()."img1.jpg";
file_put_contents($filename, $remote_content);
echo $_POST['img_url']."<br>";
$image = "<img src=\"".$filename."\" width=\"100\" height=\$
}
echo $image;
?>
Если вкратце – создается переменная image. Далее получается и проверяется на наличие POST-параметр img-url, в котором и передается ссылка. После этого при помощи функции file_get_contents() получается доступ к содержимому файла, рандомно устанавливается имя, и файл и имя ссылки выводится на страницу. И все, никаких проверок, плюс еще и вывод ошибок включен (первые две строки). А еще, если присмотрется к месту, где выводится введеная пользователем ссылка, то можно заметить XSS. Вообщем, если соберетесь писать что-то подобное – не надо так =)
Еще потенциальные места, где может обнаружится SSRF:
Помимо явных обращений по доменным именам и ссылкам, SSRF может обнаружится и в других местах. Вот список нескольких “мест” в веб-приложении, в которых может обнаружится уязвимость:
- SSRF через XXE ( XML External Entity )
- Webhooks
- Работа с видео и графикой.
Векторы раскрутки:
Сканирование сети
Про этот вектор мы уже поговорили выше. Добавить к этому можно то, что далеко не всегда подобные ошибки будут появляться на странице. Поэтому, если у вас есть подозрения, что страница уязвима, проверяйте реакцию страницы на передачу внутренних адресов. Cтраница может, например, по странному реагировать на передачу адресов не живых хостов, скажем, просто не прогружатся. Ну или даже может быть такое, что информация о результате подключения записывается внутрь файла, который должен быть картинкой.(пример далее в эксплуатации “file-url”)В этом случае файл можно скачать и посмотреть содержимое при помощи блокнота, т.к. браузер такое прочеcть не в состоянии.
Получение доступа к метаинформации
В случае, если компания использует облачную инфраструктуру, такую как Azure или google cloud, то атакующий может получить доступ к чувствительной информации, которая находится на дефолтном для большинства “облаков” ip-адресе:
169.254.169.254
Там находятся файлы, которые опять же могут помочь скомпроментировать систему, такую как информация о хостах внутри сети, работающих службах, а так же, иногда сами разработчики скалдывают в это хранилище API-ключи или какие-то данные, которые лучше держать в секрете.
Просмотр локальных файлов через file://
Так же, в некоторых случаях можно просмотреть локальные файлы уязвимого сервера через схему URL file. Рассмотрим как это происходит все на том же примере:
Схема в URL в нашем случае выглядит следующим образом:
file://<путь к файлу>
Попробуем получить доступ к файлу /etc/passwd, который в пингвиньих системах содержит информацию о пользователях на сервере:
Как видим - никаких ошибок мы не получаем, и вроде как даже jpg файл был создан. А если он был создан, то попробуем посмотреть его содержимое. Браузер, к сожалению, показать содержимое не сможет, потому что обращается к файлу как к графическому изображению, а не как к текстовому файлу:
Пойдем другим путем. Скачаем созданый файл себе на машину при помощи wget:
И если мы попытаемся посмотреть содержимое при помощи дефолтной команды cat, мы увидим содержимое файла /etc/passwd.
Формирование произвольных запросов при помощи протокола gopher
Есть такой очень старый протокол – gopher. Этот протокол хоть как-то использовался еще в конце прошлого века, но впоследствии его вытеснил всем нам известный www. Изначально этот протокол задумывался как конкурент FTP, однако с развитием мировой паутины почти канул в лету. Но, не везде. В некоторых системах можно все еще встретить поддержку этого протокола, и если уязвимый сервер поддерживает gopher, то это дает очень большое пространство для маневров, ведь при помощи этого протокола можно захватить контроль практически над всем TCP-потоком и формировать запросы для разных протоколов, а не только для http. Как пример, вот так выглядит smtp запрос, сформированый при помощи gopher:
gopher://smtp/_<TCP-payload>
То есть, при создании ссылка формируется по следующему правилу:
gopher://<protocol>:<port>/x<url-encode payload>
где url-encode payload – это зашифрованый в URL TCP-пакет. То, есть, например в случае с smtp этот пакет выглядит так:
MAIL FROM:hacker@test.com
RCPT To:admin@test.com
DATA
From:hacker@test.com
Subject:admin
Message:You have been hacked !
.Протокол очень старый, и мало где поддерживается (например php его вообще не поддерживает, а java и asp.net поддерживают только в старых версиях). Но если вам повезло и вы обнаружили что в уязвимом сервисе пристуствует поддержка этого протокола, вы можете сформировать и отправить в сеть разные tcp-пакеты, что само по себе – очень полезная возможность, знать о которой стоит.
Ну а помочь с этим может инструмент gopherus (ставить на свой страх и риск):
tarunkant/Gopherus
This tool generates gopher link for exploiting SSRF and gaining RCE in various servers - tarunkant/Gopherus
Этот инструмент помогает сформировать различные полезные нагрузки для разных протоколов при помощи протокола gopher.
Формирование и выполнение произвольных HTTP-GET запросов
Наверное одна из самых безобидных фишек – формирование и отправка запросов от имени веб-сервера. Если мы можем заставить сервер отправить запрос во внутреннюю сеть по http, то логично что мы можем сформировать GET-запрос к какому-либо внутренему приложению. Приведу пример – на внутреннем сервере разверну простенькое веб-приложение, которое просто получает по GET-запросу параметр “test” и записывает его в файл text.txt на сервере. Изначально на сервере есть только скрипт, который доступен по дефолтному порту 80 и доступен сервер только из внутреней сети. Но если в поле URL мы подставим ссылку типа “http://192.168.1.7/index.php?test=i’m_in!” а затем снова проверим сервер, то увидим что запрос был выполнен и у нас появился файл test.txt, с содержимым, которое мы отправили в параметре test:
Почему эта фишка одна из самых безобидных ? Потому что на практике вам должно очень повезти, чтобы вы могли нормально ее применить. Внутри сети должен находится сервер с веб-приложением, принимающим по GET какие-либо данные, которые в дальнейшем как-то используются в системе, что мы можем этим воспользоваться. При этом вы должны знать об этом приложении, знать имя параметра и т.д. Вообщем, слишком много звезд должно сойтись, чтобы этот вектор можно было реально применить. Однако, знать о нем стоит.
Пару слов про обход защиты:
С первого взгляда уязвимость достаточно легко фиксится: нужно просто вбить локальные адреса в черный и список и на этом все. Однако, все не так просто. Если код просто будет проверять ip на то, попадает ли он в диапазон локальных адресов или нет – это изначально плохой метод защиты, который легко обходится. Есть достаточно много сопособов обойти такую защиту, вот некоторые из них:
Собственные DNS-записи
Первый, простой, логичный и вполне себе рабочий способ – создание собственной DNS-записи, с указанием локального адреса. Как известно – имя домена, это просто оболочка, за которой, как за записью в телефонной книге, скрывается адрес. Ничто не мешает хакеру купить дешевый домен с указанием локального адреса в качестве самой записи. Как итог – если на первом этапе пользовательская ссылка была проверена и вела она на внешний домен, то уже при обращении к домену, приложению будет передан локальный адрес. И если это не проверяется на сервере второй раз – то запрос будет отправлен во внутренюю сеть.
Редиректы через 301, 302, 303 и 307, 308 http-коды
Второй, не менее простой способ – редиректы. Те, кто хоть немного знакомы с HTTP протоколом знают, что там есть такая фишка как редиректы – когда при попытке обратиться к определенной странице или директории на сервере, веб-сервер выдает редиректный (301 или 302 для GET, и 307 для POST -запроса) код ответа, который подразумевает перенаправление в другое место. В ответе от веб-сервера есть заголовок, который и определяет куда перенаправить обратившегося.
А теперь представьте следующую ситуацию: сервер получает на обработку адрес, проверяет его. Видит, что адрес к локальным никак не относится и отправляет туда запрос на получение данных. А в ответ получает заголовок с кодом редиректа на локальный адрес. И, как правило, о проверке адреса в таких ситуациях разработчики уже не думают и запрос спокойно летит в сеть.
Альтернативное представление локальных адресов
Еще один способ – альтернативная запись ip-адресов. Мы привыкли видеть ip-адреса в виде дестяичных значений по четыре блока (октета), в диапазоне от 0 до 255. Однако есть другие виды записи адресов, что вполне себе поддерживается разными технологиями. Вот некоторые примеры:
1. Исключение нулей из адреса.
В некоторых случаях, нули в адресе можно опустить, превратив таким образом, например, адрес 127.0.0.1 в 127.1
2. Запись в других системах счисления.
Октеты так же могут быть записаны в 8-ричной и 16-ричной системах счисления. Таким образом адрес 192.168.1.7 в 8-ричной системе будет выглядеть как 300.250.1.7 или 00c0.00a8.0001.0007 в 16-ричной. Так же, эти системы счисления можно сочетать, записав часть октетов в 16-ричной, часть в 8-ричной, а часть в 10-тичной системах счилсения.
3. Запись одним числом.
Так же, адрес можно представить в виде одного числа, не разделяя его на октеты. Высчитывается такой адрес следующим образом:
(1)*256^3+(2)*256^2+(3)*256^1+(4)*256^0
где (1),(2) и т.д. - номера октетов. То есть для адреса 192.168.1.7 подобный числовой адрес вычисляется так:
192*256^3+168*256^2+1*256^1+7*156^0 = 3232235783
И ссылка будет уже выглядеть так: http://3232235783
И уже это число можно по аналогии перевести в 8ричную или 16-ричную системы счисления, и это тоже будет работать
Таким образом, систему защиты, проверяющую адреса на “локальность” можно легко обойти при помощи одной из вышеупомянутых техник. Поэтому действительно правильным методом защиты будет комплексная защита – ограничение поддерживаемых схем и допустимых портов, тщательная проверка передаваемого адреса, минимизация взаимодействия потенциально уязвимых серверов с инфраструктурой и т.д.
Заключение:
SSRF – достаточно опасная уязвимость. Хотя она напрямую и не позволяет захватить контроль над сервером или данными, но она может помочь раздобыть очень важную информацию о внутренем периметре и на основе уже этих знаний разработать полноценный план атаки на сеть. А как показывает практика внутрение сети защищают обычно куда хуже, чем следовало бы. Там и аккаунты без паролей, и машины с устаревшим ПО, и разные раздолбайски настроеные сервисы. Поэтому, SSRF может стать той самой открытой форточкой, через которую атакующий сможет собрать кучу ценной информации, чтобы впоследствии нагнуть всю сеть.
А я на этом с темой SSRF заканчиваю, всем добра!
© Urob0ros, специально для форума xss.pro