SourMint:悪意あるSDKに関する調査レポート
Kirill Efimov
2020年8月24日
0 分で読めます概要
Mintegral SDKは、iOSとAndroidの両方に対応した、広く利用されているモバイルアプリ広告SDKです。数千のモバイルアプリで使用され、月間ダウンロード数は10億回を超えています。アプリ開発者は、このSDKを使ってサードパーティ広告を掲載し、アプリを収益化しています。
Snykのセキュリティリサーチチームは、Mintegral SDKに関する重大な開示を2件行いました。最初の開示は2020年8月に公開され、SDKのiOS版で行われていた過剰なデータ収集とクリックハイジャックを明らかにしました。2件目の開示では、リモートコード実行を可能にするバックドアがSDKのiOS版で見つかったほか、Android版に関する新たな調査結果も明らかになりました。
この記事では、ブログ記事で取り上げた内容を超えて、調査の技術的な詳細と調査結果を共有します。
この調査レポートは、次の3つのセクションで構成されています。
「過剰なデータ収集」では、iOS SDKにおけるすべてのHTTPリクエストの傍受と記録について説明します。2020年8月24日に公開した内容で、Mintegral SDKのiOS版におけるURLとリクエストの追跡機能を解説します。
「SDKのiOS版におけるバックドアがリモートコード実行を可能に」では、2020年10月15日に公開した、MintegralAdSDKのリモートコード実行機能について説明します。
「AndroidでのダウンロードURL追跡」では、Mintegral SDKのAndroid版で見つかったさまざまな問題について説明します。
iOSでの過剰なデータ収集[2020年8月]
概要
この調査は、2020年8月時点ではオープンソース版を入手できなかったため、Mintegral iOS SDKのバイナリ版を対象に実施しました。調査には、GitHubからダウンロードできるSDKバージョン6.3.5.0(x86アーキテクチャ)を使用しました。
Mintegral iOS SDKのバージョン5.5.1以降には、情報漏えいにつながる悪意ある機能が含まれていることを確認しました。簡単に言うと、このSDKはユーザーのリンククリックと、影響を受けたアプリ内のネットワークアクティビティを監視します。この監視は、開発者や広告メディエーションプラットフォームがSDKを有効にしていなくても行われます。また、プロキシ、シミュレーター、脱獄済みデバイスを識別して、悪意ある動作を隠そうとします。
メソッドスウィズリング
Mintegral SDKは、メソッドスウィズリングと呼ばれる手法を使って、実行時にUIApplication openURLメソッドとSKStoreProductViewController loadProductWithParametersメソッドの実装を置き換えます。また、カスタムのNSURLProtocolクラスを登録します。
これらのフックは、アプリ内でユーザーがクリックしたHTTPリクエスト、開いたURL、App Storeリンクに関するあらゆる情報を送信し、アプリのユーザーを監視するために使われます。
HTTPリクエストのヘッダーとURL自体にも機密情報が含まれる可能性がありますが、IDFA(広告識別子)と組み合わせることで、Mintegralは広告アトリビューション詐欺を実行できます。
広告アトリビューション詐欺
アプリを収益化するため、開発者は広告プラットフォームを導入することがよくあります。広告プラットフォームは、ユーザーが広告をクリックした後にアプリがインストールされるたびに、広告主から収益を得ます。開発者が複数の広告プラットフォームをアプリで利用することも珍しくありません。そのため、インストールのアトリビューションをどの広告プラットフォームに付与するかを判断するため、各クリックはアトリビューションプロバイダー(モバイル計測プラットフォーム、MMP)に記録されます。
次の図は、Mintegralの悪意ある機能の動作を示しています。この例では、ユーザーは「別のプラットフォーム」の広告をクリックしました。しかし、Mintegralはアプリで開かれたすべてのURLを傍受できるため、そのクリックが自社広告から発生したように見せかけ、アトリビューションプロバイダーに追加のリクエストを送信できます。処理の全体像は次のとおりです。
ユーザーが、Mintegral以外の広告ネットワークが配信したアプリ内広告のリンクをクリックし、App Storeから新しいアプリをインストールします。
広告ネットワークのSDKが、クリック情報をバックエンドプラットフォームに送信します。
メソッドスウィズリングでiOSのイベントハンドラーに挿入されたコードを通じてクリックイベントを傍受したMintegralは、クリックデータを自社サーバーに記録します。
広告ネットワークが、アトリビューションプロバイダーにクリック通知を登録します。
Mintegralも、アトリビューションプロバイダーにクリック通知を登録します。
アトリビューションプロバイダーがインストールイベントと登録済みのクリック通知を照合すると、一致する通知が2件見つかります。ラストタッチアトリビューションモデルでは、Mintegralのクリック通知にアトリビューションが付与され、もう一方の広告ネットワークのクリック通知は却下されます。

Snykは大手アトリビューションプロバイダーと協力し、Mintegralがクリックデータを使って偽のクリック通知を生成していることを確認しました。調査を通じて同プロバイダーは、偽のクリック通知が生成され、その結果、広告クリックのアトリビューションが誤ってMintegralに付与されていることを示しました。
デモアプリ
攻撃を実証するため、デモアプリをセットアップしました。このアプリでは、悪意あるopenURLフックの動作を確認できます。デバッグ用プロキシを使って、すべてのネットワークトラフィックを傍受します。
アプリを初期化するには、Mintegralのドキュメントにある次のコードスニペットを使います。
SDKを初期化したら、ボタンをクリックしてアプリからexample.comを開きます。
アプリを起動すると、プロキシ上でMintegral SDKからのリクエストがすぐにいくつか確認できます。
GET https://setting.rayjump.com/sdk/customidGET https://setting.rayjump.com/settingPOST https://analytics.rayjump.com

設定
https://setting.rayjump.com/settingからの応答は、さまざまなオプションを含むJSONオブジェクトです。次の表に、今回の調査で特に注目したフィールドを示します。
JSONフィールド | 説明 |
|---|---|
csw | アンチデバッグ機能を有効または無効にします。 |
cou |
|
cdai | 漏えいした情報の送信先URL(*)。 |
cspn | StoreKitメソッドのフックを有効または無効にします。 |
cud | NSURLProtocolのフックを有効または無効にします。 |
cudl | NSURLProtocolで追跡するURLの配列(**)。 |
* 今回の場合はLdxThdi1WBK/WgfPhbxQYkeXHBPwHZKsYFh= で、デコードするとhttps://n.systemlog.me/logです。
** 今回の場合はkBzuJd5/H+i/D+SMY7V/DFKwR0M0D+SMhBPthdSsHZPUYFT0+N==で、デコードすると["itunes.apple.com","apps.apple.com"]です。
ペイロードのデコード
ボタンをクリックしてexample.comを開くと、さらに2件のリクエストが確認できます。1件目は想定どおりhttp://example.comへのGETリクエストです。2件目はhttps://n.systemlog.me/logへのPOSTリクエストです。

リクエストの本文はBase64でエンコードされているように見えます。しかし、実際にはBase64エンコードされた文字列ではありません。Mintergral SDKは独自のエンコード/デコードロジックを実装しており、+[MTGBase base64DecodeString:]および +[MTGBase base64CleverDecodeString:]にその実装があります。MTGBaseはSDKの公開ヘッダーで公開されておらず、開発者がアクセスすることを想定していない点に注意してください。
ペイロードのデコードには、次のコードスニペットを使います。

ペイロードには、IDFA、IDFV、OSバージョン、ユーザーエージェントなど、大量のデータが含まれています。また、「clever」というフィールドも含まれており、これもエンコードされています。base64DecodeStringを使ってデコードできます。
ご覧のとおり、URL、スタックトレース、コントローラーやメソッド名などの追加情報が含まれています。
さらに詳しく
前述のとおり、Mintegral SDKはクローズドソースです。ここでは、x86アーキテクチャ向けのバージョン6.3.5.0を調べます。
このバイナリは、複数の別のバイナリを含むMach-O実行ファイルです。調査対象のコードは_CXX_CXX_OperationPKTask.oにあります。
クラスを調べると、+[_CXX_CXX_OperationPKTask load]が確認できます。このメソッドは、クラスが実行時に追加されると自動的に実行されます。つまり、SDKをCocoaPods経由でインストールすると、開発者が実際にSDKを使っているかどうかにかかわらず、悪意あるロジックが初期化されます。
loadメソッドはいくつかの呼び出しを実行し、最終的に___cxxwebk_init_vwに到達します。このメソッドはアンチデバッグ保護フラグが有効かどうかを確認し、フラグがfalseの場合、またはデバッグが無効の場合にフックを初期化します。

フックの初期化は、前述の設定リクエストに依存します。次の表は、応答JSONのフィールドとMTGSettingクラスの対応関係を示しています。
JSONフィールド | MTGSettingプロパティ | 説明 |
|---|---|---|
csw | cSrtW | アンチデバッグ機能を有効または無効にします。 |
cou | cOpenURL |
|
cspn | cPackageName | StoreKitメソッドのフックを有効または無効にします。 |
アンチデバッグロジック

__cxx_cxx_op_isInSuperViewFrame関数は、次の場合にtrueを返します。
デバイスのプラットフォームが「シミュレーター」である。
デバッガーがアタッチされている(
____mvpmvvm_isDebuggerAttached_block_invokeで実装)。デバイス上に次のファイルのいずれかが存在する(脱獄の兆候)。
/Applications/Cydia.app
/Library/MobileSubstrate/MobileSubstrate.dylib
/bin/bash
/usr/sbin/sshd
/etc/apt
/usr/bin/ssh
プロキシが有効になっている(
CFNetworkCopySystemProxySettingsを使用)。
openURLのメソッドスウィズリング
次のスクリーンショットのロジックは___cxxwebkmcouitninapoメソッドに実装されています。このメソッドは、該当するフラグが有効な場合に___cxxwebk_init_vwから呼び出されます。

上のスクリーンショットは、メソッドスウィズリングの実装を示しています。次の呼び出しを実行します。
「openURL:」メソッドのセレクターを取得する
NSSelectorFromString。UIApplicationのクラス記述子を取得するNSClassFromString。メソッド記述子を取得する
class_getInstanceMethod。メソッドの実際の実装を取得する
method_getImplementation。次に、
_____cxxwebkmcouitninapo_block_invoke_2を呼び出した後、元のopenURLを呼び出すコードブロックを定義します。method_setImplementationを使って、元のopenURLを前の手順で作成したコードブロックに置き換えます。
openURL:options:completionHandler:メソッドでもほぼ同じ処理が行われますが、その前にシステムのバージョンを確認します(ハンドラーが初めて導入されたのはiOS 10です)。
ここまでで、フックの適用方法がわかりました。次に、フック自体の実装(_____cxxwebkmcouitninapo_block_invoke_2)を見ていきます。
openURLフックの実装
実際の実装は___cxxwebkmcoulszメソッドにあります。ここでは、アンチデバッグチェックがもう1つ実行され、その後__mc_notifyInHouseフラグが確認されます。このフラグが1の場合、何も行いません。
これは、Mintegralが配信した広告でユーザーがクリックしたマーケティングURLをすべて無視するためです。次のスクリーンショットでは、+[MTGBase mtgOpenURL:options:completionHandler:]に該当するロジックが確認できます。

次のコードでは、バックトレースデータもシリアライズして、https://n.systemlog.me/logに送信するペイロードに含めて漏えいさせていることがわかります。
+[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:]の呼び出しにブレークポイントを設定できます。次のスクリーンショットで、呼び出し時の引数を確認できます。

開かれたURL(http://example.com?foo=bar&x=y)。
クリックが発生したクラス(
ViewController)。クリックが発生したメソッド(
openURLWithOptions:)。バックトレース情報。
もう1つ興味深い関数は_nsh_id_by_ccです。競合SDKの識別を担っているようです。次のスクリーンショットに、該当するロジックを示します。

+[_CXX_CXX_OperationPKTask _cxx_cm_log_warnings:to:ins:]に戻ると、ペイロードを+[MTGBase base64EncodeString:]でエンコードした後、新しいコードブロックを作成し、_dispatch_asyncを使って実行します。
そこから、追加のペイロード変換を伴う一連の呼び出しが行われ、最終的に-[_MC_ApiManager AFRequestWithUrl:paras:success:failure:]に到達します。このメソッドは、MTGSettingのcollectDomainUrl(デフォルトではhttps://n.systemlog.me/log)にPOSTリクエストを送信します。
非公開URLが漏えいする様子を示す動画

SKStoreProductViewControllerのフック
SKStoreProductViewControllerは、ユーザーがApp Storeからメディアを購入できるページを提供するビューコントローラーです。
loadProductWithParameters:completionBlock:メソッドは、表示する新しい商品画面を読み込みます。
フックの実装に関する技術的な詳細には立ち入らず、デモアプリケーションに次のコードスニペットを追加しました。
その結果、「clever」フィールドに次のペイロードを含むPOSTリクエストがhttps://n.systemlog.me/logに送信されることを確認できました。
ご覧のとおり、リクエストには商品IDが含まれています。これで証明されました。
NSURLProtocolのフック
NSURLProtocolクラスを使うと、開発者はAppleのURLローディングシステムの動作を再定義できます。Mintegral SDKはNSURLProtocolの悪意ある実装を登録しており、リモートから設定することで、アプリケーションが送信するあらゆるリクエストを傍受し、URLやHTTPヘッダー(Authorizationヘッダーを含む)を追跡できます。
アプリケーション開発者にとって、これはAPIトークン、Cookie、Basic認証ヘッダーがMintegralによって収集される可能性があることを意味します。
SDKが悪意あるコードのこの部分をどのように有効化するかを理解するため、___cxxwebk_init_vwに戻って確認します。

上のスクリーンショットが示すように、フックを有効化するにはcudフラグを有効にし、cudl配列を空にしない必要があります。
次のスクリーンショットは、上記のメソッドから呼び出される___cxxwebkterisiuuxx関数の一部を示しています。

___cxxwebkterisiuuxx関数内のコードは、次の処理を実行します。
NSURLProtocolを継承するクラスを作成します(objc_registerClassPair、objc_allocateClassPair)。実質的にインターセプターとなる
canInitWithRequest:の実装を追加します(class_addMethod)。+[NSURLProtocol registerClass:]を呼び出し、そのクラスをURLローディングシステムに登録します。
悪意あるコードが収集するデータを検証するため、調査では次のコードスニペットを追加しました。
その結果、「clever」フィールドに次のペイロードを含むPOSTリクエストがhttps://n.systemlog.me/logに送信されることを確認できました。
リクエストにはURLとAuthorizationヘッダーが含まれています。リクエスト本文は含まれていませんが、ヘッダーにも機密データが含まれていることは珍しくありません。個人を特定できる情報が含まれる可能性さえあります。たとえば、APIでJWTトークンを使用している場合、メールアドレスやユーザー名がトークン内に格納されていることがあります。
結論
調査では、Mintegralの開発者がSDKの悪意ある動作を隠すために用いている興味深い手法を数多く確認しました。特定の地域における特定のアプリケーションでのみフックを有効化していたため、悪意あるコードは1年以上にわたり、注目されることなく残っていました。
時系列を見ると、悪意あるSDKの最初のバージョン(5.5.1)は2019年7月17日に公開されました。その後のすべてのバージョンにも、同じ悪意ある機能が含まれていたことがわかりました。
このSDKの悪意ある活動は、多くの人気アプリケーションに影響を及ぼしました。この調査が実態を明らかにすることで、今後、広告ネットワークに対する監視とプライバシー管理が強化されることを期待しています。
iOSでのリモートコード実行(RCE)[2020年10月]
要約
SDK全体でJavaScriptとの通信に使われるMTGBaseBridgeWebViewクラスを発見しました。このクラスはバックドアとして機能し、ネイティブアプリケーションコードから任意の関数を呼び出せるようにします。

上の画像は、リモートコード実行の仕組みを簡略化して示した図です。
差分分析
最初の公開情報開示の後、MintegralはSDKのオープンソース版のリリースを発表しました。
そこで、新しいオープンソース版と、CocoaPodsで配布されていた以前のバイナリ版を比較しました。旧バージョンのソースコードはありませんでしたが、クラス名の比較は可能でした。そのため、バイナリから.oファイルを抽出し、オープンソース版の.hファイルとシンボルを比較しました。
予想どおり、以前発見した悪意ある_CXX_CXX_OperationPKTaskコンポーネントは削除されていましたが、差分から別の問題が見つかりました。次のクラスが目に留まりました。
MTGCommandDispatcher
MTGComponentCommands
MTGRemoteCommand
MTGRemoteCommandParameterModel
MTGRemoteCommandParser
MTGInvocationBoxing
これらのファイルの用途を理解するため、バイナリを詳しく調べることにしました。
影響を受けるバージョン
MintegralAdSDKの6.5.0.0以前のすべてのバージョン(6.5.0.0を含む)。2020年9月10日に公開されたバージョン6.6.0.0には、本稿で説明するバックドア機能はありません。
ブリッジの実装
まずMTGRemoteCommandParserクラスの使用箇所を調べたところ、MTGBaseBridgeWebViewクラス内の-(void)handleNativeObject:parameters:の1か所だけでした。
実装を見ると、-(void)handleNativeObject:parameters:はparameters引数を解析するためにMTGRemoteCommandParserを使い、MTGCommandDispatcherクラスの-(void)dispatchCommand:feedback:メソッドを呼び出すことがわかります。
一見すると-(void)handleNativeObject:parameters:は使われていないように見えますが、実際はそうではありません。JavaScriptコードからどのように呼び出せるか見てみましょう。
MTGBaseBridgeWebViewはWKNavigationDelegateプロトコルの-(void)webView:decidePolicyForNavigationAction:decisionHandler:メソッドを実装しています。このメソッドは、Webビューでナビゲーションが発生するたびに呼び出されます。つまり、JavaScript内でlocation.href=somethingを呼び出すだけで、このメソッドを起動できます。SDKのオープンソース版では、ナビゲーションリクエストURLを解析する正規表現が見つかりました。mv://(.+?):(.+?)/(.+?)\\?([\\s\\S]*)。

上のスクリーンショットにある-(void)callFunctionWithName:fucId:param:は、selfのfucNameセレクターを呼び出しているだけです。
したがって、MTGBaseBridgeWebViewの-(void)handleNativeObject:parameters:を呼び出すには、次のJavaScriptコードを記述します。location.href = 'mv://1:fucId/handleNativeObject?<parameters>'。
なお、執筆時点では、ここまで説明した内容はSDKの最新バージョンとオープンソース版の両方で有効です。唯一の例外は、最新リリースでは-(void)handleNativeObject:parameters:が削除されていることです。
リモートメソッド呼び出し
MTGInvocationBoxingやその他のクラスの実装全体については説明しません。代わりに、リモートメソッドを起動する悪意あるJavaScriptコードをどのように作成できるかを示します。
以下の概念実証では、+(void)save:と+(NSString*)loadという2つのメソッドを持つNoteRepositoryクラスを備えた「シンプルなメモ」アプリを攻撃します。
Mintegralのサーバーを独自のサーバー実装に置き換えて、悪意あるJavaScriptコードを注入します。このアプリケーションとサーバーのソースコード全体はこちらにあります。
このアプリケーション向けの悪意あるJavaScriptコードは次のとおりです。
値 | デコード後 |
|---|---|
hbxtJ7QU+TPXJ75ZH+SXhFQTYbzP | static_NoteRepository |
Y7KtHv== | load |
このコードはNoteRepositoryクラスの+(NSString*)loadメソッドを呼び出し、その結果をdemo-evil-server.com/logエンドポイントに送信します。
このコードは前のセクションで説明したものと同じ難読化手法を使っています。ただし、この概念実証には、エンコードとデコードを実行するJavaScriptコードがすでに含まれています(banner.htmlを参照)。
完全なリモートコード実行(RCE)の実現
上の例では、SDKを使って任意のクラスの静的メソッドを呼び出せることを示しました。このセクションでは、それを利用して任意のネイティブコードを実行する方法を説明します。
デモとして、メッセージが「PWNED!」のUIAlertControllerを作成する方法を示します。
参考として、次のObjective-Cコードを見てみましょう。
呼び出しの間、UIAlertControllerのインスタンスを作成して保持する方法、共有アプリケーションインスタンスを取得する方法、さらにそのインスタンスを使ってpresentViewController:animated:completion:を呼び出す方法を明らかにする必要があります。
ステップ1:UIAlertControllerクラスへの参照を保存する
MTGRemoteCommandParserがサポートするオブジェクト参照は次の2種類です。
static:名前でクラスオブジェクトへの参照を取得します。singleton:次の複数のステップを実行します。名前でクラスを取得します(この例では
MTGSetting)。クラスに対して
sharedInstanceメソッドを実行します。[MTGSetting sharedInstance]はObjective-Cでの記述です。
valueForKey:を使って、ドット区切りのプロパティを取得します。この例では[[MTGSetting sharedInstance] valueForKey:@"jsonTitles"]になります。
jsonTitlesはNSMutableDictionaryのインスタンスにすぎません。このエクスプロイトでは、参照を一時的に保存するために使います。MTGRemoteCommandParserがサポートするパラメーターの型は次のとおりです。
0:数値。1:参照。2:文字列。4:nil。
参照(1)型を使うと、メソッドの引数としてオブジェクトへの参照を渡せます。重要なのは、uniqueIdentifierがトップレベルのuniqueIdentifierとまったく同じ方法で解析されるため、singleton型もサポートされることです。
ステップ2:UIAlertControllerクラスの新しいインスタンスを割り当てる
この例では、singleton_MTGSetting.jsonTitles.a.alloc.initが重要な役割を果たします。すでに見たとおり、singleton_MTGSetting.jsonTitles.aを使うとUIAlertControllerクラスへの参照を取得できます。しかし、なぜ[[UIAlertController valueForKey:@"alloc"] valueForKey:@"init"]が機能するのかを確認する必要があります。valueForKey:のドキュメントには、次のように記載されています。
valueForKey:が返す値を見つけるために使用する検索パターンについては、Key-Value Coding Programming GuideのAccessor Search Patternsで説明されています。
valueForKey:は、引数を取らないメソッドであれば、名前を指定して任意のメソッドを呼び出せることがわかりました。
これでUIAlertControllerクラスの新しいインスタンスを作成し、jsonTitles辞書のbプロパティから参照できるようになります。
ステップ3:「PWNED!」メッセージを設定する
このステップは簡単です。UIAlertControllerのインスタンスでsetMessage:を呼び出し、メッセージにPWNED!を設定します。
ステップ4:UIApplicationクラスへの参照を保存する
このステップはステップ1と同様です。UIApplicationクラスへの参照をjsonTitles.xに保存します。
ステップ5:アラートを表示する
複雑に見えますが、これまでのステップで紹介したさまざまな手法を組み合わせているだけです。Objective-Cコードでは次のようになります。
これで、リモートコード実行によってアラートを表示できることを示しました。ペイロード全体はこちらにあります。各ステップを順番に呼び出すため、アクションの配列を作成し、それぞれのアクションの完了後にwindow.WindVane.onSuccessコールバック内で次のアクションを実行しました。
悪意ある広告を使ってエクスプロイトを配信し、クリップボードの内容を漏えいさせる様子を示す動画

JavaScriptエクスプロイトのソース
Mintegral SDKがJavaScriptコードを介してネイティブのリモートコード実行を可能にすることは、すでに確認されています。ただし、そのJavaScriptコードはすべてMintegralが所有し、制御しています。しかし興味深いことに、広告主自身が作成したインタラクティブ広告を通じても、同じことを実現できます。広告はJavaScriptベースのウェブページです。
理論上、広告主はJavaScriptエクスプロイトを含む悪意のある広告を配信することで、特定のユーザーグループや特定のデバイス群を正確に狙うことができます。
結論
MintegralがSDKにリモートでネイティブメソッドを呼び出す機能を含めた理由は推測するしかありませんが、MTGCommandDispatcherやMTGRemoteCommandといったクラス名から、これは意図的なものだったと考えられます。また、公開後すぐにMintegralはこのコードを削除しました。当時、私たちはその存在を把握していませんでした。
Androidでのダウンロード追跡[2020年10月]
概要
この調査記事の前の2つのセクションでは、SnykのセキュリティリサーチチームがMintegral SDK内の悪意ある挙動を発見した経緯を紹介しました。この挙動はiOSデバイスで悪用され、広告詐欺、データ漏えい、リモートコード実行(RCE)につながる可能性があります。今回は、SDKのAndroid版についてさらに調査しました。その内容をこのセクションで説明します。
主な調査結果は次のとおりです。
ブラウザーとアプリの両方で、通常のファイル、メールの添付ファイル、Googleドキュメントのリンクなど、GoogleからのダウンロードURIを追跡。
正規のものかどうかを問わず、すべてのAPKダウンロードを追跡。
このデータはMintegralのサーバーに送信されます。
確認された挙動
Googleドキュメントのリンクをダウンロードしたところ、アプリからhttps://n.systemlog.meへの次のリクエストが送信されていることを確認しました。

これは、iOS SDKでMintegralのサーバーにデータを送信するために使われていたものと同じエンドポイントです。ペイロードはエンコードされていますが、SDKバイナリ内のデコード処理を使うと、次の内容が得られます。
エンコードされたパラメーターが2つあります。cleverとdviです。これらもデコードすると、興味深いことが分かりました。
Google DriveアプリからダウンロードしたGoogleスプレッドシートのURLは、ulフィールドでバックエンドに送信され、ダウンロードしたファイル名はkwフィールドに含まれています。また、dviにはデバイスに関するデータが格納されています。
想定される用途
iOSの場合、クライアントのデバイスからMintegralのサーバー、さらにアトリビューションプロバイダー(MMP)へ、不正な重複クリックが送信されていました。今回の場合、ダウンロードまたはインストールされたAPKがサーバーに報告され、サーバー側のクリック生成に利用される可能性があります。次の図はデータの流れを示しています。

Alphabモジュール
前述の挙動は、Mintegralが「最適化パッケージ」と説明していたalphabモジュールに含まれています。

記事の公開後、このモジュールはMintegralのサイトから削除され、配布されているSDKにも含まれなくなったようです。SDKを逆コンパイルし、この挙動の原因となるコードを特定しました。
AlphaCommonConstクラス
このクラスには、多数のハードコードされた定数定義があります。一部の文字列は、iOS版で確認されたものと同様に、AlphabBase64Utilクラスにある独自のBase64ベースのエンコード方式で難読化されています。
デコードすると、次の文字列が得られます。
これらは、次に説明する初期化処理で使われています。
Alphabレシーバー
AlphabReceiverクラスのinit()メソッドでは、BroadcastReceiverが、先ほどの難読化された文字列の一部を使って初期化されています。
これらをデコード済みの文字列に置き換えると、次のコードになります。
Java Reflection APIを使って新しいブロードキャストレシーバーが作成され、次の2種類のインテントを監視していることが分かります。
android.intent.action.PACKAGE_ADDED- デバイスへのパッケージのインストール時に発生する、システム全体に向けたインテント。alphab_net_debug_action- ネットワークデバッグを検知すると思われるカスタムインテント。
インテントを受信すると、AlphabReceiverクラスがParseAndLoad()メソッドを構築します。
このフィールドは後で条件判定に使われます。
if節にある他の2つのメソッドを逆コンパイルすると、現在のネットワーク接続がWi-FiプロキシまたはVPNクライアントを経由しているかどうかを確認していることが分かります。これは、アプリのデバッグや通信の傍受を防ぐためのものです。このインテントにより、SDKの開発者はこのデバッグ対策機能を回避できます。
Alphabオブザーバー
同様に、このContentObserverの初期化ブロックも、リフレクションと難読化された文字列の中に隠されています。
整理すると、次のようになります。
つまり、このContentObserverはcontent://downloads URIを監視するよう登録されており、デバイスにファイルがダウンロードされるたびに動作します。
Androidのダウンロードマネージャーに問い合わせ、公開ダウンロードを取得します。
文字列をデコードすると、次の内容が得られます。
ダウンロードURLが次のいずれかの条件を満たすと、https://n.systemlog.met/stlogへのレポートが生成されます。
apkで終わる - 手動ダウンロードの場合。com.android.vendingに属するパッケージを参照する、またはURLにgoogle.comを含む - 条件に一致するGoogleアプリやブラウザーのURLをすべて検出します。
以下は、https://n.systemlog.met/stlogサーバーにリクエストを送信するコードスニペットです。
これは次の内容に相当します。
ここでは、例で取得したリクエストに含まれていたパラメーターを確認できます。
p- ダウンロード対象のパッケージ名、つまりアプリv- アプリのバージョンul- ダウンロードしたファイルのURLkw- ダウンロードしたファイル名fl- ファイルサイズ
デモアプリ

この挙動を実証するため、次の操作ができるデモアプリを作成しました。
1. リフレクションを使ってネットワークデバッグフラグを有効にし、デバッグ対策を回避する
2. google.comを含むURLからファイルをダウンロードする
3. apkで終わるURLからファイルをダウンロードする
HTTPプロキシで送信リクエストを取得しました。ダウンロードボタンのいずれかをクリックすると、サーバーのエンドポイントへのリクエストが確認できます。

追跡の挙動を示す動画をご覧ください。

タイムライン
日付 | |
|---|---|
8月5日 | Snykのリサーチチームが、Mintegral iOS SDKによる過剰なデータ収集とクリックの乗っ取りを発見 |
8月17日 | Snykが調査結果をAppleに責任ある形で開示 |
8月24日 | SnykがSour MintのiOSに関する調査結果を公開 |
8月25日 | MintegralがSDKに関する疑惑を否定する声明を発表 |
9月3日 | IronSourceがメディエーションプラットフォームからMintegralを削除すると発表 |
9月3日 | MintegralがiOS SDKのバージョン6.5.0.0をリリースし、悪意のある隠された_CXX_CXX_OperationPKTaskコンポーネントを削除 |
9月4日 | MoPub(Twitter)メディエーションプラットフォームが、プラットフォーム上でMintegralの認定を取り消すと発表 |
9月4日 | MintegralがSDKをオープンソース化する計画を発表 |
9月4日 | Snykのリサーチチームが、SDKのAndroid版に隠されたダウンロード追跡機能を発見 |
9月9日 | SnykがAndroid SDKの調査結果をGoogleに責任ある形で開示 |
9月10日 | MintegralがiOS SDKのバージョン6.6.0.0をリリースし、バックドアコンポーネントMTGRemoteCommandParserを削除 |
9月22日 | SnykがiOS SDKのソースコード版バージョン6.6.0.0を入手し、差分分析を実施 |
9月23日 | Snykが、MintegralがAndroid SDKからGoogleのダウンロード追跡モジュールを削除したことを確認 |
9月30日 | 差分分析により、SnykがSDKのiOS版にRCEを可能にするバックドアを発見 |
10月2日 | Snykが新たなiOSの調査結果をAppleに責任ある形で開示 |
10月3日 | Appleが影響を受けたパブリッシャーに通知し、RCEを可能にするコードの削除を要請 |
10月15日 | SnykがiOSおよびAndroidの最新の調査結果を公開 |



