Если вы когда-нибудь сталкивались с SSTI в Jinja2, то вы наверняка гуглили RCE payload и находили что-то монструозное вроде этого:
Этот пейлоад достает класс
К счастью, всё можно сделать гораздо проще:
Здесь мы используем встроенную в Jinja функцию
Вообще, при эксплуатации SSTI-подобных уязвимостей в питоне полезно помнить о существовании свойства
{{''.__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__
.Знали ли вы, что второй аргумент
Оказывается, glibc поддерживает синтаксис для указания кодировок, это можно сделать вот так:
В итоге, если вы можете для чужого приложения
1) переопределить переменную окружения
2) куда-нибудь записать свою so-шку и файл
3) дописать
то вы получите выполнение кода.
Конечно, в реальных приложениях такое вряд ли встретится, но это доказывает что даже в самых базовых библиотеках полно интересного.
Кстати, эта же система кодировок-модулей используется и в
Подробности можно прочитать в посте японца, который это заметил.
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.
Для этого достаточно добавить строку
после
Или проще - положить содержимое nmap-bootstrap.xsl в /usr/share/nmap/nmap.xsl, после чего локальные результаты сканирования будут иметь красивый и удобный для работы вид, без парсинга содержимого XML и верстки в сторонних утилитах.
Для красивого отображения результата сканирования с помощью 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 и верстки в сторонних утилитах.
#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 официально релизнул 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.
Впрочем, работа с ним может показаться неудобной из-за необходимости писать скрипт во встроенном примитивном редакторе. Но есть изящный выход из ситуации, детали на скриншоте.
Недавно команда 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 февраля. В связи с этим тема флага
Детальней про Referrer фичу: https://www.chromestatus.com/feature/6251880185331712
Следить за жизнью релизов Chrome: https://www.chromestatus.com/features/schedule
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.
1) Отрицание
Это не бага, а фича!
2) Злость
Импакта нет и не будет!
3) Торг
Ну может быть, в редких случаях.
4) Депрессия
Всякие чуваки показывают трюки SSRF => RCE
5) Принятие
Ты сам проверяешь и пытаешься эксплуатировать эту багу.
Написал заметку о том, что можно выжать из Blind SSRF.
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 начала бы отдавать в ответе случайную память на сервере.
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.
Обойти XSS WAF можно через нульбайт, в блоге deteact есть описание, почему это происходит.
А еще там есть смешная обходка для Open Redirect - некорректный парсинг урла, который проверяет вхождение домена в начале строки, который можно откинуть в basic auth.
В Gitlab недавно нашли способ чтения произвольных файлов, как следствие, это может привести к выполнению произвольного кода. Забавно, что репорт открыли достаточно быстро, еще не все успели обновиться.
Из привелегий - нужно иметь учетку (ну или открытую регистрацию), так что если у вас есть корпоративный gitlab, вы знаете, что делать.
Из привелегий - нужно иметь учетку (ну или открытую регистрацию), так что если у вас есть корпоративный gitlab, вы знаете, что делать.
SVG - забавная штука. Это формат графики, который представлен в виде XML файла. Поэтому в нем уже делали всякие атаки, типа XXE. С помощью него выполняются XSS атаки при открытии изображения в браузере. Но еще, он странно ведет себя как тег в html страницах.
Совсем недавно, Safari выполнял событие onload в любом элементе, которое находится в теге svg.
А Firefox умеет выполнять тег <script>, даже если он не закрытый.
На самом деле, при построении DOM-дерева он автоматически закрывает SVG, а для того, чтобы это был корректный XML - все теги внутри него (а еще, ты можешь заметить href, вместо src). Но это можно использовать для обхода некоторых видов защит.
Совсем недавно, Safari выполнял событие onload в любом элементе, которое находится в теге svg.
<svg><hello onload=alert(1337)>
А Firefox умеет выполнять тег <script>, даже если он не закрытый.
<svg><script href=data:,alert(1) />
На самом деле, при построении DOM-дерева он автоматически закрывает SVG, а для того, чтобы это был корректный XML - все теги внутри него (а еще, ты можешь заметить href, вместо src). Но это можно использовать для обхода некоторых видов защит.
Если у тебя доступен файл .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 токена). Иногда это уже реализовано в библиотеках, но далеко не во всех. Еще забавно, что куки могут быть удалены, сессионный идентификатор может уже давно умереть, а подключение к вебсокету все еще работать.🔥3
Иногда, для 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'ом на одном домене, а выполняем его на другом.