Кавычка
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
Если вы когда-нибудь сталкивались с SSTI в Jinja2, то вы наверняка гуглили RCE payload и находили что-то монструозное вроде этого:

{{''.__class__.mro()[1].__subclasses__()[46]('touch /tmp/rce',shell=True)}}

Этот пейлоад достает класс Popen по индексу из наследников object и исполняет команду. Он не очень-то удобен: индекс Popen (который в примере равен 46) различается от сетапа к сетапу, поэтому его нужно подбирать.

К счастью, всё можно сделать гораздо проще:

{{lipsum.__globals__["__builtins__"].eval("<python code>")}}

Здесь мы используем встроенную в Jinja функцию lipsum (она возвращает текст "Lorem ipsum dolor..."), но вместо того чтобы вызывать её, мы через __globals__ достаем её глобальные переменные — а в них нас ждет модуль __builtins__ с функцией eval.

Вообще, при эксплуатации SSTI-подобных уязвимостей в питоне полезно помнить о существовании свойства __globals__ у всех питоновских функций (кроме встроенных). Если в вашем окружении нет функций, а только объекты — не беда, найдите у него любой метод и возьмите свойство __func__. Вы получите unbound функцию, у которой уже будет __globals__.
Знали ли вы, что второй аргумент fopen (тот самый, который w или, например, r+) умеет исполнять код? Ну почти.

Оказывается, glibc поддерживает синтаксис для указания кодировок, это можно сделать вот так: fopen("file", "w,ccs=<encoding>"). Сами кодировки подгружаются динамически, функции для работы с каждой кодировкой лежат в отдельном .so-файле. Конфиг, содержащий пути к этим библиотекам называется gconv-modules и обычно лежит где-нибудь в /usr/lib/x86_64-linux-gnu/gconv/, но если переопределить переменную окружения GCONV_PATH, то он будет браться из указанной директории. И path traversal, конечно, в нем полностью поддерживается.

В итоге, если вы можете для чужого приложения

1) переопределить переменную окружения GCONV_PATH
2) куда-нибудь записать свою so-шку и файл gconv-modules
3) дописать ,css=payload во второй аргумент fopen

то вы получите выполнение кода.

Конечно, в реальных приложениях такое вряд ли встретится, но это доказывает что даже в самых базовых библиотеках полно интересного.

Кстати, эта же система кодировок-модулей используется и в iconv (и утилите, и библиотеке), поэтому трюк можно использовать для обхода disabled_functions в php. Правда, для того, чтобы задать GCONV_PATH должен быть разрешен putenv, а это уже само по себе небезопасно.

Подробности можно прочитать в посте японца, который это заметил.
#Nmap

Для красивого отображения результата сканирования с помощью nmap (с сохранением XML, атрибут -oX), достаточно добавить кастомный стиль, который сделает доступным сортировку, поиск и прочие плюшки bootstrap.
Для этого достаточно добавить строку
<?xml-stylesheet href="https://raw.githubusercontent.com/honze-net/nmap-bootstrap-xsl/master/nmap-bootstrap.xsl" type="text/xsl"?>
после <!DOCTYPE nmaprun>.
Или проще - положить содержимое nmap-bootstrap.xsl в /usr/share/nmap/nmap.xsl, после чего локальные результаты сканирования будут иметь красивый и удобный для работы вид, без парсинга содержимого XML и верстки в сторонних утилитах.
Только при работе с локальными файлами корректно будет работать только Firefox, хром не хочет доверять стилям. Но и так сойдет.
#Burp

Чтобы сохранить нужные данные, например, после фильтрации в инструменте Intruder, не обязательно делать экспорт. Достаточно зажать CTRL (или ⌘) и кликнуть по заголовку колонки.
Содержимое колонки будет скопировано в буфер обмена.
#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'ом на одном домене, а выполняем его на другом.