Кавычка
16.4K subscribers
83 photos
2 videos
12 files
184 links
Практическая безопасность. Уязвимости и атаки на веб-приложения.

Чат @WebPwnChat

Только авторский контент, без репостов и рекламы (простите).

Вместо лайка:
https://t.iss.one/webpwn?boost

Платный канал:
https://t.iss.one/tribute/app?startapp=s2Vr
Download Telegram
#Burp

С тех пор, как Burp официально релизнул 2.x ветку, где добавил динамический анализ JS кода, многие стали жаловаться на большое потребление оперативной памяти и медленную скорость сканирования. Ну а как же иначе, ведь Burp 2.x теперь тащит с собой целый headless chrome через который и гоняет анализ JS.

Но не стоит отчаиваться, эти "тяжёлые" (и честно говоря, мало полезные) проверки можно отключить через настройки сканирования. Для этого в меню new scan, возникающем при запуске active scan необходимо перейти во вкладку Scan Configuration, создать новую конфигурацию кнопкой New и в выпадающем меню JavaScript Analysis отключить галочки по вкусу. Обязательно стоит отключить dynamic analysis techniques, за что ваша оперативная память скажет вам спасибо, но я лично отключаю их всех, если не преследую какой-то конкретной цели по анализу JS.

P.S. Если вы только что открыли для себя существования меню настроек сканирования, рекомендую задержаться в нём и посмотреть внимательно на предоставляемые возможности.
#Burp

Недавно команда PortSwigger обновила список топ 10 лучших плагинов для Burp. Подробнее можно ознакомиться тут https://portswigger.net/testers/penetration-testing-tools#the-top-10-burp-suite-extensions-for-pentesters.

На скромном третьем месте расположился плагин Turbo Intruder, на мой взгляд, самый гибкий и мощный плагин для Burp. Он позволяет проводить fuzzing на больших скоростях с интеграцией кастомной логики + отлично подходит для тестов race condition. Детали доступны по ссылке https://portswigger.net/research/turbo-intruder-embracing-the-billion-request-attack, а также среди примеров скриптов https://github.com/PortSwigger/turbo-intruder/tree/master/resources/examples.

Впрочем, работа с ним может показаться неудобной из-за необходимости писать скрипт во встроенном примитивном редакторе. Но есть изящный выход из ситуации, детали на скриншоте.
Stable Chrome 80 осталось ждать совсем недолго, релиз назначен на 4 февраля. В связи с этим тема флага SameSite=Lax для cookie опять начала будоражить умы человечества. Из-за этого многие не заметили другое, более тихое, нововведение. Теперь Referrer Policy будет выставляться по умолчанию в значение strict-origin-when-cross-origin. Это значит теперь можно забыть про утечку одноразовых ссылок восстановления и прочей чувствительной информации на сторонние ресурсы из URL через Referrer. Еще одной client-site багой стало меньше 😢

Детальней про Referrer фичу: https://www.chromestatus.com/feature/6251880185331712
Следить за жизнью релизов Chrome: https://www.chromestatus.com/features/schedule
Говорят, есть пять стадий понимания SSRF.

1) Отрицание
Это не бага, а фича!

2) Злость
Импакта нет и не будет!

3) Торг
Ну может быть, в редких случаях.

4) Депрессия
Всякие чуваки показывают трюки SSRF => RCE

5) Принятие
Ты сам проверяешь и пытаешься эксплуатировать эту багу.


Написал заметку о том, что можно выжать из Blind SSRF.
В #Burp Suite ты можешь сам показать, какой именно параметр (или путь, заголовок) ему нужно сканировать.
Для этого нужно зайти в инструмент Intruder, разметить наиболее интересные части HTTP-запроса, а потом отправить на скан.
Фишеры icloud и где они обитают

https://bo0om.ru/icloud-phishers
1) Год назад в багбаунти программу mailru заслали баг на 10 тысяч $, из публичного описания было понятно лишь то, что ликается какая-то рандомная память https://twitter.com/disclosedh1/status/1189553870801907713
2) Полгода назад samwcyo публикует статью, как ему заплатили 40 тысяч $ за похожую багу https://samcurry.net/filling-in-the-blanks-exploiting-null-byte-buffer-overflow-for-a-40000-bounty/. Т.е. где-то что-то подставил, а в ответ рандомные куски памяти. В 2019 то году!

-- Ни в первом, ни во втором случае было непонятно, из-за чего именно раскрывалась рандомная память сервера в ответе --

3) И вот вчера появились детали из-за чего был баг #1 и, возможно, баг #2. Причина - неожиданное поведение openResty, при помощи которого можно писать скрипты на Lua в Nginx. Ожидается, что Lua в данном случае - это memory-safe язык, и подобные уязвимости ему не грозят. Но это оказалось не так и из-за этого была уязвимость. Также по ходу расследования оказалось что и "чистый" Nginx к этому уязвим, но Nginx - запатчились, а openResty - нет. Детали теперь в описании https://hackerone.com/reports/513236

Представьте себе, это как на PHP бы функция header() при подстановке %00 начала бы отдавать в ответе случайную память на сервере.
Bitrix - популярная CMS для стран СНГ. Там есть достаточно неплохая встроенная защита, которую всё-таки можно обойти.
Обойти XSS WAF можно через нульбайт, в блоге deteact есть описание, почему это происходит.
А еще там есть смешная обходка для Open Redirect - некорректный парсинг урла, который проверяет вхождение домена в начале строки, который можно откинуть в basic auth.
В Gitlab недавно нашли способ чтения произвольных файлов, как следствие, это может привести к выполнению произвольного кода. Забавно, что репорт открыли достаточно быстро, еще не все успели обновиться.
Из привелегий - нужно иметь учетку (ну или открытую регистрацию), так что если у вас есть корпоративный gitlab, вы знаете, что делать.
А раз уж мы пошли по статьям, недавняя RCE в ClickHouse
SVG - забавная штука. Это формат графики, который представлен в виде XML файла. Поэтому в нем уже делали всякие атаки, типа XXE. С помощью него выполняются XSS атаки при открытии изображения в браузере. Но еще, он странно ведет себя как тег в html страницах.

Совсем недавно, Safari выполнял событие onload в любом элементе, которое находится в теге svg.

<svg><hello onload=alert(1337)>

А Firefox умеет выполнять тег <script>, даже если он не закрытый.

<svg><script href=data:,alert(1) />

На самом деле, при построении DOM-дерева он автоматически закрывает SVG, а для того, чтобы это был корректный XML - все теги внутри него (а еще, ты можешь заметить href, вместо src). Но это можно использовать для обхода некоторых видов защит.
Если у тебя доступен файл .env в Laravel, но его наличие не дает никаких преимуществ (порты закрыты, например) - можно посмотреть что там в админке.

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


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

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

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

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

Поэтому, подключать пользователя или нет, решает бэкэнд. Именно он должен определить, является ли пользователь и источник подключения легитимным. Обычно проверяют заголовок Origin или используют различные секреты (типа CSRF токена). Иногда это уже реализовано в библиотеках, но далеко не во всех. Еще забавно, что куки могут быть удалены, сессионный идентификатор может уже давно умереть, а подключение к вебсокету все еще работать.
🔥3
Иногда, для 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
1