Я заглянув у додаток Prisma, і ви не повірите, що я там знайшов

2016 рік ще не скінчився, але продовжує радувати нас крутими продуктами по обробці зображень. Спочатку всі вболівали FaceSwap, потім з'явився MSQRD, тепер у нас є Prisma. Ще більше радості/гордості, звичайно, від того, що останні 2 продукту — наші, рідні. MSQRD роблять хлопці з Білорусі, Prisma ж взагалі родом з Москви. Логічно, що у будь-якого популярного продукту відразу починають плодитьяся конкуренти. Призмі в цьому плані пощастило більше всіх — завдяки збігу певних обставин, основним конкурентом призмі стали Mail.ru Group, які майже відразу випустив аж 2 схожих продукту зі схожими функціями: Vinci (від команди vk.com) і Artisto (від команди my.com).



А особисто мені стало цікаво подивитися на ці «клони» зсередини. Навіщо мені все це і до яких висновків я прийшов — про це я розповів на roem.ru, повторюватися не бачу сенсу. На Хабре ж я б хотів поділитися технікою детального аналізу додатків для iOS на прикладі Prisma.

Що нас чекає? По-перше, ми дізнаємося, що є додаток для iOS і з чого воно складається, яку інформацію можна звідти витягти. По-друге, я розповім як снифать трафік client-server додатків, навіть якщо їхні автори цього дуже не хочуть. За фактом я не розповім вам нічого нового я не придумав ніякого ноу-хау, це просто вектор відомих технік і умінь на додатки. Але буде цікаво. Погнали.

iOS-додаток, IPA-файл
iOS-додаток являє собою .ipa-файл. По факту це zip-архів і може відкриватися будь-яким архіватором (так так, mobilz обіцяв навчити ламати програми, а насправді покаже, як користуватися архіватором). Сам .ipa-файл простіше всього отримати з допомогою iTunes — в розділі «Програми» є вкладка AppStore, яка є аналогом AppStore на iPhone. Відповідно, вам потрібно обліковий запис (AppleID); завантаживши додаток з допомогою iTunes ми можемо перейти в директорію до нього.




Далі .ipa-файл, як я вже говорив, відкривається будь-яким архіватором. Всередині ми знайдемо крім іншого директорію Payload і файл iTunesMetadata.plist. У Payload знаходиться наш додаток, а точніше директорія з розширенням .app, яку MacOS буде намагатися запустити, але нам досить просто відкрити вміст. iTunesMetadata містить метаінформацію з AppStore. Який акаунт скачав додаток, в якому розділі додаток знаходиться і т. д. і т. п. Нічого цікавого в ньому для нашого аналізу немає, йдемо безпосередньо до .app. Розберемо відразу на конкретному додатку, Prisma 2.3 — Payload/Prisma.app.

У різних проектах ми можемо побачити різну структуру, але завжди точно буде Info.plist (Payload/Prisma.app/Info.plist). Це основні налаштування програми, такі як мінімальна версія для запуску, підтримувані орієнтації, підтримка iPad та інше. Тут вже цікавіше:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>DTCompiler</key>
<string>com.apple.компілятори.llvm.clang.1_0</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>DTPlatformVersion</key>
<string>9.3</string>
<key>DTSDKName</key>
<string>iphoneos9.3</string>
<key>CFBundleName</key>
<string>prisma</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIcon29x29</string>
<string>AppIcon40x40</string>
<string>AppIcon60x60</string>
</array>
</dict>
</dict>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>CFBundleDisplayName</key>
<string>Prisma</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>instagram</string>
<string>fb</string>
<string>fbauth2</string>
<string>fbshareextension</string>
<string>fbapi</string>
<string>fb-profile-expression-platform</string>
<string>vk</string>
<string>vk-share</string>
<string>vkauthorize</string>
</array>
<key>DTSDKBuild</key>
<string>13E230</string>
<key>CFBundleShortVersionString</key>
<string>2.3</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>Pushwoosh_APPID</key>
<string>46F12-BE2E4</string>
<key>BuildMachineOSBuild</key>
<string>15G31</string>
<key>DTPlatformBuild</key>
<string>13E230</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>DTXcodeBuild</key>
<string>7D1014</string>
<key>CFBundleVersion</key>
<string>40</string>
<key>UIStatusBarHidden</key>
<true/>
<key>FacebookAppID</key>
<string>582433738573752</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
</array>
<key>Fabric</key>
<dict>
<key>Kits</key>
<array>
<dict>
<key>KitName</key>
<string>Crashlytics</string>
<key>KitInfo</key>
<dict/>
</dict>
</array>
<key>APIKey</key>
<string>8e17945e7d29d1c775f321348caef29075f5ab9a</string>
</dict>
<key>FacebookDisplayName</key>
<string>Prisma.AI</string>
<key>CFBundleIdentifier</key>
<string>com.prisma-ai.app</string>
<key>DTXcode</key>
<string>0731</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>vk.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>cdninstagram.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
<key>CFBundleExecutable</key>
<string>prisma</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb582433738573752</string>
</array>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>vk5530956</string>
</array>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>prisma</string>
</array>
</dict>
</array>
</dict>
</plist>

Про ключі ви можете почитати детальніше офіційній документації, нас же цікавлять лише деякі з них.

По-перше, ми можемо добути API-ключі для сторонніх продуктів (зразок crashlytics), ідентифікатори груп/сторінок в vk/facebook. По-друге, ми можемо точно знати детальні налаштування урлов, куди ходить додаток:

LSApplicationQueriesSchemes

<key>LSApplicationQueriesSchemes</key>
<array>
<string>instagram</string>
<string>fb</string>
<string>fbauth2</string>
<string>fbshareextension</string>
<string>fbapi</string>
<string>fb-profile-expression-platform</string>
<string>vk</string>
<string>vk-share</string>
<string>vkauthorize</string>
</array>

Бачимо, що додаток захоче працювати з инстаграмом, facebook і вконтактом. Ця інформація жодним чином, звичайно, не допоможе «зламати» додаток, але дасть нам додаткову інформацію.

NSAppTransportSecurity

<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>vk.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>cdninstagram.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>

Якщо не помиляюся, прапор з'явився з 9-ої версії iOS. Розповідає нам, куди додаток буде ломитися по http-протоколу (https доступний будь-домен). Тобто при всьому бажанні додаток не зможе звернутися на http, якщо не налаштований NSAppTransportSecurity.

Ключ в цілому теж нам особливо нічого не дає, крім інформації. Але курочка по зернятку. Бачимо, що додаток хоче ломитися по http на vk.com і cdninstagram.com. Ок.

CFBundleURLTypes

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb582433738573752</string>
</array>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>vk5530956</string>
</array>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>prisma</string>
</array>
</dict>
</array>

Мабуть, самий цікавий з непотрібних ключів. Знову ж таки, він нам нічого особливо корисного не дає, але розповідає про зареєстрованих урлах на цьому конкретному додатку. Наприклад, якщо в мобільному сафарі ви наберете fb582433738573752:// вас перекине в додаток (якщо воно встановлено, звичайно). Дану інформацію, повторюся, теж можна віднести до умовно-марною. Але пару разів я натикався на додатки, де крім стандартних урлов соцмереж я знаходив урли типу «app-admin» або «app-dev». При переході на які можна було отримати приховані налаштування програми. В одному додатку я отримав редакторський доступ до одному виданню, в якому можна було публікувати статті, пхати їх на головну, видаляти, змінювати місцями ітп.

Далі нас цікавить директорія Frameworks: Payload/Prisma.app/Frameworks

В ній ми знайдемо ще трохи непотрібної інформації про використовуваних зовнішніх фреймворках і SDK.


Детальніше я напишу трохи нижче про кожен фреймворк, але заздалегідь можу сказати, що, наприклад, звідси теж можна вицепіть цікаву інформацію. Серед інших фреймворків бачимо FLAnimatedImage, який працює з анімованими GIF — мимоволі напрошується висновок, що Prisma все ж буде і з відео.

Також в метафайлах часто можна знайти якесь сміття, забутий розробниками. Часто я знаходжу README.md, .gitignore, ліцензії та інше. Знову ж таки, Prisma хороший приклад, т. к. з версії 2.3 в ній з'явилася просто забута розробниками фотка одного з друзів. Ті, хто докопаються, прошу не викладати ім'я людини в коментах, він дуже просив.

Також знаходимо USERTrustRSAAddTrustCA.cer — вже цікавіше. Наскільки я зрозумів це запаролених сертифікат, аналоговий брутфорс профіту не дав.

Безпосередньо в бінарники часто знаходяться приховані plist, які можуть бути цікавими. Також, якщо додаток зібрано на webview-технологіях (типу Cordova), ми знайдемо config.xml кордови і, власне, оригінал додатка. Наприклад, додаток Sworkit, яке, крім іншого, пропонує користувачам оплатити додаткові відеоуроки, вже має їх в исходниках в зручному .mp4-форматі. Хочеш зручно — плати. Хочеш незручно, але безкоштовно — читай на Хабре цю статтю.

Мабуть, це основне, що можна добути з пакету з додатком. Точніше основне, що вдалося добути мені. Упевнений, ви хлопці розумні і знайдете ще більше корисного — пишіть в коментарі і ми додамо це в статтю. Але, знову ж таки, все індивідуально. У деяких програмах можна знайти дуже багато, в тому числі і цілком исходники.

Ну і трохи докладніше про самому додатку. Призма (2.3) 17.6 Мб. Нативний swift, підтримка російської та англійської мови. Фреймворки:
Alamofire.framework — http-клієнт
AlamofireImage.framework
AlamofireNetworkActivityIndicator.framework
Bolts.framework — допоміжний набір інструментів для розробника
FBSDKCoreKit.framework — facebook
FBSDKShareKit.framework — facebook
FLAnimatedImage.framework — бібліотека для роботи з відео
KeychainAccess.framework — врапперов авторизації. Найчастіше використовується для роботи з touchid
Obfuscator.framework — обфускатор, тут, думаю, пояснювати не потрібно
PINCache.framework — key/value сховище для великих об'єктів з підтримкою роботи в різних потоках.
PINRemoteImage.framework — модуль picache
pop.framework — бібліотека для роботи з анімацією. Найчастіше використовується для UI-анімації.
RHBOrientationObjC.framework — робота з акселерометром, точніше, з орієнтацією пристрою.
SDWebImage.framework — ще один http_клиент/кешер для зображень
SwiftyJSON.framework — зручна робота з json
Swinject.framework — DI патерн розробки
VK_ios_sdk.framework — vk.com
Що в підсумку ми маємо? Ми зібрали купу інформації про роботу програми та розуміємо, чого від нього очікувати. Ми знайшли якийсь сертифікат і зберегли його собі. Ми дізналися, що нас незабаром чекає відео і знайшли класну фотку одного засновника Prisma. Рухаємося далі.

Сниффаем HTTP
Prisma і тут виявилася гарним прикладом для статті. Якщо ті ж Artisto і Vinci ходять по голому http і немає праці їх сниффать, Prisma ходить по https з перевіркою автентичності сертифіката. І тут починаються танці з бубнами. Але давайте по порядку.

1. Для початку нам потрібен http(s)-проксі. Я користуюся Charles, він досить простий і функціональний.
2. Нам потрібно iOS-пристрій. Емулятори не підійдуть.
3. Нам потрібна одна мережа між пристроями. Найпростіше — Wi-Fi.

На своєму терміналі запускаємо проксі, заодно включаємо і https-проксі. На пристрої, відповідно, в налаштуваннях Wi-Fi-мережі прописуємо руками проксі (IP нашого терміналу і порт):


Далі найчастіше досить підсунути в iOS свій сертифікат. Як це зробити добре написано на тому ж сайті Charles. Але у випадку з Prisma цього зробити не вийшло — розробники не ликом шиті і перевіряють справжність сертифіката. Але робиться це засобами пристрою, а ми теж хитруни ті ще. Однак для того, щоб змусити iOS не перевіряти сертифікат на справжність, нам потрібно буде jailbreak.

Дійте можна було зробити до версії iOS 9.3.3, і то на свій страх і ризик — як варіант, використовуйте тематичні ресурси і уважно читайте коментарі. Зокрема, деякий софт «типу для джаилбрейка» може попросити AppleID разом з паролем, що загрожує зникненням даних і грошей грошей з прив'язаною карти. Всі ці тонкощі докладно описані.

Я не буду описувати як робив це я, т. к. разлочка сильно відрізняється залежно від версій пристрою і iOS. Єдине, навіщо нам це треба в даному випадку — https://github.com/nabla-c0d3/ssl-kill-switch2/releases — крайня версія ssl kill switch. З допомогою Cydia (знову ж, всю інформацію можна знайти в мережі) ставимо будь-переглядач файлів, наприклад iFile. І за допомогою нього заливаємо .deb-файл останнього релізу ssl kill switch. Працювати ssl kill switch після перезавантаження телефону. Важливо не забути його вимкнути після всіх маніпуляцій, тому що в противному випадку ми ризикуємо, адже наш пристрій більше не перевіряє справжність ssl.


Проксі включений, перевірка сертифіката вимкнена, погнали дивитися на додаток. Перший запуск — як бачимо, програма спочатку збирає налаштування. Звідки ж вона їх бере? Смикається https://cdn.neuralprisma.com/config.json звичайним GET'ом, там стандартні налаштування, не цікаво. Потім смикається api3.neuralprisma.com/styles POST-му з тілом

{
"codes": ["public"]
}

На виході список фільтрів. Вже цікавіше, погрався з масивом [«public»]. Намагаючись підставити туди щось на кшталт «dev», «new» і іншого, профіту я не отримав, але може у когось з вас вийде. Я рекомендую використовувати для цього Postman.



Гаразд, йдемо далі. Наступний запит при завантаженні фото знову POST на урл api3.neuralprisma.com/upload/image



І все було в моєму житті добре, поки я не побачив заголовок prisma-image-sign з base64 від бінарного md5. Життя біль. Всі мої мрії про те, що я зараз перехвачу трафік призми і навчуся робити те ж саме, що і додаток, але просто по… http звалилися. Що це означає? Таким чином розробники захищаються від таких як я. Посилаючи фотку по http, програма також обчислює якийсь хеш з якою-небудь сіллю і додає цей хеш в заголовок. Як згенерувати хеш знає лише додаток і сервер. Фотка відправляється на сервак, сервак генерує хеш від фотки по тому ж алгоритму, звіряє суми, якщо вони відрізняються — значить запит підроблений. Є спосіб обійти це, якщо ви сильні в асемблері. Дизассм бінарника + аналіз його на тему генерації цього заголовку може дати нам алгоритм. Але враховуючи, що там md5 (мінімум) + base64, на це може піти багато часу. Ну і не забуваємо, що все ускладнюється ще й наявністю фреймворку Obfuscator.framework. Загалом, як я вже писав, життя біль.

Вся подальша робота програми досить проста. Картинка відправляється на сервак, у відповідь отримуємо якесь ім'я зображення. При виборі стилю шлються запити з цим ім'ям додатка + ім'ям стилю, на виході профіт. А адже перемога була так близька.

Ну да ладно, давайте не будемо впадати у відчай і розберемо можливість перехоплення API на прикладі іншого подібного додатки Vinci. Як вже казав, там все ходить по голому http, тому нам навіть не доведеться перекручувати наш пристрій. Просто прописуємо проксі сервер і дивимося що куди ходить при роботі з додатком. Всі запити можна емулювати в Postman, про який я вже писав, або реалізувати на якому-небудь сервері мовою.



Все досить просто. При запуску першим запитом Vinci збирає доступні стилі, далі реєструє девайс, нам це пофіг. Потім я завантажив фото, відправляється POST-запит на /preload з фото, з будь-яким фото, у відповідь ми отримуємо якийсь хеш нашого фото:



Ну і далі, як видно, отримуємо вже готове зображення, звертаючись з урлом http://vinci.camera/process/2_gNmHxDdthLsmPtuXGxRzQnKjbbspfO/21, де
2_gNmHxDdthLsmPtuXGxRzQnKjbbspfO
хеш фото, а 21 — номер фільтра, які можна добути з http://vinci.camera/list



От і все. Отже, чого ми навчилися сьогодні? Ми навчилися збирати інформацію про програму по метафайлам самого додатка і навчилися сниффать трафіки, навіть якщо всі API ходить по https з перевіркою автентичності сертифіката. Ми навчилися збирати інформацію з API: що, куди, навіщо, а також я показав деякі «тупики».

За сим не буду відволікати вас від захоплюючих аналізів додатків, якщо хто що цікаве знайде, скидайте в коменти, разом посміємося.

До речі, цікавий факт. Ті ж SQLinj. У вебі їх зараз вже складно зустріти, будь-розробник розуміє всю небезпеку ін'єкцій. Але от мобільні розробники, які часто приходять в мобільну розробку не з веба (а навіть коли з інтернету — довіряють своїм API, типу «так хто його знає наше API-то, тільки наш додаток!») частенько забувають про веселощі, що може їх чекати при повному доступі до бази віддаленим користувачем.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.