iOS-приложения: тестирование безопасности и устойчивости к взлому

IT-копирайтер
Время чтения: 15 минут
Недавно наш отдел мобильной разработки закончил работу над приложением, с помощью которого можно оплачивать связь сотового оператора. Так как приложение работает с данными банковских карт, мы тестировали не только его функции, но и устойчивость к взлому, а также безопасность хранения и передачи данных.
Сегодня я поделюсь методикой тестирования безопасности iOS-приложений и проиллюстрирую теорию практикой. Конечно, договор с заказчиком не позволит мне использовать для этого приложение проекта, поэтому для примера я разберу и проанализирую другое приложение с похожими возможностями — «Плати картой» для оплаты услуг МегаФона.
Необходимый инструментарий
Инструмент для JailBreak
- redsn0w, версия для Mac OS или Windows.
ПО для устройства
- Cydia — программное приложение iOS, которое устанавливается вместе со специальной версией системы в процессе взлома; все перечисленное далее ПО устанавливается через Cydia.
- OpenSSH — утилита для удаленного подключения к iOS-устройствам по SSH.
- Adv-cmds — выполняет ps, kill, finger и другие полезные команды.
- Sqlite3 — клиент баз данных.
- Veency — VNC-сервер для iOS-устройств.
- Tcpdump — утилита, позволяющая захватывать и анализировать интернет-трафик.
- Grep — утилита для поиска.
- GNU Debugger — инструмент отладки, анализа и обратной разработки.
ПО для декстопа
- Burp Suite — инструменты анализа трафика; Java, multiplatform.
- Wireshark — инструмент анализа трафика.
- iExplorer — файловый менеджер.
- Cyberduck — SFTP-клиент; SSH-доступ.
- Screen Sharing — системная утилита для подключения к VNC-серверу; используется в связке с установленным на устройстве Veency, но может использоваться любой VNC-клиент.
- 0xED — hex-редактор.
Подготовка устройства
JailBreak
Для анализа и аудита программного обеспечения необходимо установить специальные утилиты, что невозможно сделать без взлома устройства. Чтобы взломать Apple iPhone, iPad или iPod Touch, приведите его в режим «DFU», а затем просто следуйте указаниям мастера redsn0w.
В итоге, если все прошло успешно, устройство будет взломано, и на нем будет установлена специальная версия iOS с приложением Cydia. Если после запуска Cydia у вас появляется сообщение об ошибке «Ошибка загрузки. Недоверенный сертификат сервера» (Unable to Load. Untrusted Server Certificate), вам потребуется дополнительная настройка.
Установка программного обеспечения
Обязательный минимум для мобильного устройства:
- OpenSSH
- Adv-cmds
- Tcpdump
- Grep
- GNU Debugger
Для десктопа:
- Burp Suite
- Wireshark
- Cyberduck
- 0xED
Пароль root и mobile: «alpine», будет нужен для подключения по SSH.
Пароль для удаленного доступа к устройству по VNC задается в настройках.
Аудит приложения
Анализируя безопасности мобильного приложения, разработчик решает три основные задачи: проверка безопасности клиентской части приложения, его серверной части и способа передачи данных между этими двумя компонентами. Эти три крупные задачи можно разбить на более мелкие, проверяя:
- способы передачи данных через интернет;
- конфиденциальность;
- способы хранения данных;
- устойчивость к взлому.
Рассмотрим эти задачи более подробно.
Анализ интернет-трафика
iOS-приложения могут использовать различные способы передачи и получения данных:
- незащищенные протоколы, такие как http;
- Что проверяем: используются ли они для передачи важных данных?
- защищенные протоколы, такие как https;
- что проверяем: делается ли проверка подлинность SSL-сертификата или приложение принимает любые SSL-сертификаты?
- нестандартные протоколы и низкоуровневые способы передачи данных.
Конфиденциальность данных
Проверяем, не использует ли приложение какие-либо данные пользователя без его ведома.
Хранение данных
Во время стандартной установки приложения на iOS-устройстве, система создает папку с уникальным идентификатором внутри /var/mobile/Applications. Типичная структура папок внутри корневой папки приложения такова:
Смотрим и ищем:
- Plist файлы — что содержат, нет ли скрытых опций?
- Keychain — что и в каком виде хранится?
- Cache — что кэшируется?
- Logs — пишутся ли логи? что именно?
Устойчивость к взлому
Тестирование устойчивости приложения к взлому — это самая сложная и интересная часть, требующая определенных знаний, опыта и терпения. В первую очередь необходимо понять, какие именно данные являются ценными и требуют защиты в рамках конкретного приложения.
Далее, если приложение стороннее, для проведения анализа требуется получить незашифрованную копию исполняемого файла. Незашифрованная копия позволит получить сведения о структуре классов приложения, их интерфейсах и поможет спланировать дальнейшие действия по анализу и взлому.
Давайте рассмотрим, как можно проанализировать эти моменты на примере разбора безопасности приложения для оплаты мобильной связи.
Пример анализа приложения «Плати картой»
Описание приложения на AppStore: Платите за мобильный легко и просто, не отрываясь от дел! Без комиссий. Без очередей. Загрузите приложение «Плати картой» и используйте возможность пополнить свой мобильный счет или счет другого абонента МегаФон путем списания средств с Вашей банковской карты VISA и MasterCard.
Дополнительная информация: в качестве логина/пароля в приложении используются данные аккаунта МегаФон «Сервис-Гид». Адрес сервиса зависит от конкретного региона; пример для Новосибирской области.
Устройство для тестирования и анализа: iPhone 3G.
Предварительный анализ
МегаФон «Сервис-Гид» — это система, позволяющая абонентам сотового оператора МегаФон управлять своим аккаунтом: менять тариф, управлять дополнительным опциями, получать отчеты по оказанным услугам (звонки, SMS), тратить бонусные баллы и т. д.
Соответственно, главный вопрос по безопасности:
- каким образом в приложении обеспечивается сохранность данных аккаунта, предотвращающая несанкционированный доступ к «Сервис-Гид»?
Дополнительные вопросы:
- как и где хранятся данные о банковских картах?
- возможно ли совершить неавторизованный платеж с карты, зарегистрированной в приложении?
Application traffic analysis
HTTP
Все ок. Во время авторизации не используется.
HTTPS
Все ок. Подлинность сертификата проверяется.
Установить PortSwiggerCA.crt на устройство не получилось — устройство перезагружалось. Поэтому пришлось проводить авторизацию не через прокси, а напрямую.
Каналы передачи данных о карте
Проверить по какому каналу передаются данные о карте не получилось, т. к. устройство не поддерживает многозадачность. Было невозможно одновременно залогиниться без прокси и проверить отправку данных с прокси.
Конфиденциальность
В ходе проведения исследования признаков несанкционированного доступа к данным пользователя обнаружено не было.
Хранение данных
Авторизация
- Изучив особенности хранения данных, мы выявили несколько слабых моментов, ставящих безопасность данных пользователя под угрозу.
- Угроза безопасности! При авторизации в папке Documents создается файл authData.xml, где в незашифрованном виде указывается логин и пароль к сервису МегаФон «Сервис-гид».
- Чтобы начать работу, необходимо принять пользовательское соглашение. Соглашение можно не принимать, тогда просто попадаешь в основное окно программы.
- Угроза безопасности! После перезапуска приложение логинится автоматически.
- Угроза безопасности! После закрытия приложения, файл authData.xml с незашифрованным паролем остается в папке Documents, остается он и в случае, когда пользователь выходит из своей учетной записи, т. к. опция «Запомнить» по умолчанию включена. Если нажать «Выход», отключить опцию и закрыть приложение, то после перезапуска приложение все равно залогинится автоматически. Возможно, опция «Запомнить» не сохраняется, если не была нажата кнопка «Войти». При попытке входа с неверными данными выдается сообщение об ошибке, но опция «Запомнить» не учитывается, и при перезапуске приложения пользователь снова авторизуется с сохраненными данными.
- Если во время авторизации отключить опцию «Запомнить», то файл authData.xml не создается.
Данные банковской карты
- Приложение не приняло старую карту, выдало сообщение, что срок действия карты истек.
- При попытке отправить данные с неправильным сроком действия появилось сообщение, что банк не смог провести тестовый платеж.
После ввода действующей карты появился экран подтверждения, где нужно ввести сумму тестового платежа. Сохранило ли приложение данные о карте локально пока не понятно. Предположительно, эти данные хранятся и получаются с сервера.
Попробуем выяснить это с помощью tcpdump.
Важно! Добавьте «-s 0», чтобы не обрезались пакеты и можно было использовать опцию «Follow TCP Stream Wireshark» остановка записи «Ctrl+C».
iPhone-Viktor-Kotov:~ root# tcpdump -w /FILENAME.pcap -s 0 tcpdump: listening on en0, link-type EN10MB (Ethernet), capture size 68 bytes ^C1506 packets captured 1509 packets received by filter 0 packets dropped by kernel iPhone-Viktor-Kotov:~ root#
Анализ трафика в Wireshark ничего криминального не выявил:есть запросы к ispay.megafon.ru/ по https.
Проверка на устойчивость к взлому
Disclaimer: Анализ приложения на уязвимость ко взлому проводится формально, т. к. никаких препятствий к доступу в приложение нет.
Ищем путь для приложения (можно посмотреть и через Cyberduck):
iPhone-Viktor-Kotov:~ root# ls -ld /var/mobile/Applications/*/UPS.app drwxr-xr-x 4 mobile mobile 7310 Apr 19 10:13 /var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app iPhone-Viktor-Kotov:/var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app root# plutil Info.plist | grep Executable CFBundleExecutable = UPS; iPhone-Viktor-Kotov:~ root# cd /var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D iPhone-Viktor-Kotov:/var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D root# cd UPS.app
Находим имя исполняемого файла:
iPhone-Viktor-Kotov:/var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app root# plutil Info.plist | grep Executable CFBundleExecutable = UPS;
Вытаскиваем исполняемый файл с устройства при помощи Cyberduck или с десктопа (из папки iTines):
Далее уже на десктопе в терминале смотрим информацию о файле:
Kotov-Mac-mini-3:PayWithCard qwerty$ file UPS UPS: Mach-O universal binary with 2 architectures UPS (for architecture armv6): Mach-O executable arm UPS (for architecture armv7): Mach-O executable arm
Видим, что внутри две версии: с поддержкой архитектуры armv6 (<=iPhone 3G, <=iPod Touch 2nd gen) и armv7 (более новые iPhone и iPod Touch, все версии iPad).
Дополнительно делаем запрос с otool:
Kotov-Mac-mini-3:PayWithCard qwerty$ otool -f UPS Fat headers fat_magic 0xcafebabe nfat_arch 2 architecture 0 cputype 12 cpusubtype 6 capabilities 0x0 offset 4096 size 241456 align 2^12 (4096) architecture 1 cputype 12 cpusubtype 9 capabilities 0x0 offset 245760 size 244816 align 2^12 (4096)
В результатах запроса здесь и далее жирным выделена важная информация. Делаем запрос на команды загрузки, также при помощи otool:
Kotov-Mac-mini-3:PayWithCard qwerty$ otool -arch armv6 -l UPS | grep crypt cryptoff 4096 cryptsize 163840 cryptid 1
Подключаемся к устройству по SSH:
Kotov-Mac-mini-3:~ qwerty$ ssh -l root 192.168.0.109 root@192.168.0.109's password:
Получаем копию незашифрованного исполняемого файла (на устройстве):
Для этого нам нужно рассчитать стартовый и конечные адреса:
стартовый: cryptoff + 0x1000 в нашем случаем это будет 4096 + 0x1000 = 0x2000
конечный: стартовый + cryptsize в нашем случае это будет 0x2000 + 163840 = 172032 или 0x2A000
iPhone-Viktor-Kotov:/var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app root# gdb -e ./UPS GNU gdb 6.3.50.20050815-cvs (Fri May 20 08:08:42 UTC 2011) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "--host=arm-apple-darwin9 --target=".Reading symbols for shared libraries . done (gdb) set sharedlibrary load-rules ".*" ".*" none (gdb) set inferior-auto-start-dyld off (gdb) set sharedlibrary preload-libraries off (gdb) rb doModInitFunctions Breakpoint 1 at 0x2fe0c1fa
Проверяем, что исполняемый файл получился правильного размера:
iPhone-Viktor-Kotov:/var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app root# ls -l upsarmv6.bin -rw-r--r-- 1 root mobile 163840 Apr 19 14:41 upsarmv6.bin
Теперь нужно скопировать дешифрованную копию исполняемого файла в оригинальный. Для этого необходимо посчитать адрес по формуле:
Architecture offset (architecture 0 offset — так как устройство iPhone 3G) + Encryption offset (cryptoff) 4096 + 4096 = 8192 Kotov-Mac-mini-3:PayWithCard qwerty$ dd seek=8192 bs=1 conv=notrunc if=./upsarmv6.bin of=./UPS 163840+0 records in 163840+0 records out 163840 bytes transferred in 0.434001 secs (377511 bytes/sec)
Далее при помощи hex-редактора 0xED убираем флаг, что исполняемый файл зашифрован:
Открываем перезаписанный исполняемый файл UPS. Дальше в зависимости от нужной нам архитектуры ищем либо первое вхождение (в начале файла) “/usr/lib/dyld”, либо второе — примерно после половины.
Дальше идем последовательно и ищем байт со значением 0x01 (01). Меняем каждый на 0x00 (00) поочередно! Каждый раз сохраняем файл и проверяем в терминале, поменялся ли флаг шифрования для исполняемого файла:
Kotov-Mac-mini-3:PayWithCard qwerty$ otool -arch armv6 -l UPS | grep crypt cryptoff 4096 cryptsize 163840 cryptid 0
Если флаг не поменялся, отменяем изменение и ищем следующий байт, повторяем пока не будет найден нужный, обычно это какой-то из промежутка между /usr/lib/dyld и /System/Library/Frameworks/
Foundation.framework/Foundation
После того как нужный байт найден, делаем дамп классов:
Kotov-Mac-mini-3:PayWithCard qwerty$ class-dump-z -u armv6 UPS
Полученное в логах данные сохраняем в файл UPSClassesDumpLog.txt и изучаем.
Например, поверхностный анализ для UPC показал что у UPSAppDelegate есть свойство/объект @property(retain, nonatomic) DataManager* dataManager;
а у этого класса есть следующий интерфейс:
@interface DataManager : NSObject { ... } @property(assign) BOOL isRemember; @property(assign) BOOL pinLocked; @property(retain, nonatomic) NSString* cardInRegistration; @property(retain, nonatomic) NSMutableArray* payments; @property(retain, nonatomic) NSString* temppass; @property(retain, nonatomic) Card* oldestCard; @property(retain, nonatomic) Card* defaultCard; @property(retain, nonatomic) NSMutableArray* aps; @property(retain, nonatomic) NSMutableArray* whiteList; @property(retain, nonatomic) NSMutableArray* cards; @property(retain, nonatomic) NSString* password; @property(retain, nonatomic) NSString* balance; @property(retain, nonatomic) NSString* login; @property(retain, nonatomic) MSISDN* userMSISDN; -(BOOL)containInWhiteList:(id)whiteList; -(BOOL)isBelongToUser:(id)user; -(id)getCard:(long)card; -(id)getWgiteListRec:(long)rec; -(id)getAps:(long)aps; -(id)getPayment:(long)payment; -(id)getPayments:(id)payments; -(id)getPayments; -(id)getWhiteList; -(BOOL)isWhiteListAddingAlowed; -(id)getAPS; -(id)getCards; -(id)getOldestCard; -(id)getDefaultCard; -(id)getCardInRegistraiton; -(id)getUsersToPayMsisdn; -(id)getUserMSISDN; -(void)saveAuthData; -(void)cleanAuthdata; -(BOOL)loadStoredAuthData; -(BOOL)isAuthdataStored; -(void)dealloc; -(id)init;
Попробуем получить список карт находящихся в процессе регистрации.
Узнаем идентификатор процесса:
iPhone-Viktor-Kotov:/var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app root# ps aux | grep UPS root 1590 0.0 0.3 273044 360 s000 R+ 3:40PM 0:00.02 grep UPS mobile 1579 0.0 8.3 320816 9880 ?? Ss 3:39PM 0:03.22 /var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app/UPS
Подключаемся к процессу при помощи Cycript:
iPhone-Viktor-Kotov:/var/mobile/Applications/006C94AD-C409-44FD-8980-40D004E6188D/UPS.app root# cycript -p 1579 cy#
Получаем указатель на инстанс приложения:
cy# var app = [UIApplication sharedApplication] @"
Узнаем указатель AppDelegate:
cy# app.delegate @"
Присваиваем указатель своей переменной:
cy# var delegate = new Instance(0x1652a0) @"
Получаем указатель на менеджер данных:
cy# delegate.dataManager @"
* В статье мы заменили цифры номера звездочками, но вам номер телефона будет виден полностью.
Пока не понятно для чего используется temppass, возможно, это токен:
cy# dataman.temppass @"AAACOwAaAsrLlGli2mHqImF4l9BbUmWG"
Дальнейший анализ нужно проводить после подтверждения карты — смотреть в каком виде будет доступны данные по карте, можно ли провести оплату на произвольный номер. Хотя, интерфейс и так не лочится.
cy# datMan.cards @["
После обращения к серверу приложение выдало сообщение о невозможности выполнить операцию, т.к. сумма платежа не может быть меньше 100 р.
Резюме
К сожалению, рассматриваемая программа «Плати картой» только частично отвечает требованиям безопасности. Злоумышленник может без особого труда получить доступ к данным аккаунта МегаФон «Сервис-Гид», после чего нанести вред пользователю, изменив параметры его профиля (тариф, услуги) на стороне оператора сотовой связи и получить несанкционированный доступ к конфиденциальной информации (звонки, SMS). Это предварительное заключение, полное резюме будет составлено после окончания исследования.
Комментарии