数千万人もの人々が、Pokémon Goの新たな世界を探索しています。しかし実際には、そのユーザーの多くは人間ではなく、自動化されたエージェント、つまりボットです。ゲームをプレイするボット自体は目新しいものではありませんが、Pokémon Goではボットの新たなユースケースが生まれています。こうしたボットは、自動トラフィックでPokémon Goのサーバーを圧迫し、誰もがゲームを楽しむ妨げになり始めています。Pokémon Goは、モバイルAPIに対する自動攻撃とその防御の仕組みを理解するうえで、格好のケーススタディです。Shapeではこの種の攻撃に日々対処しているため、Pokémon Go APIへの攻撃で何が起きたのかを詳しく見ていきます。
Pokémon Go API攻撃
Nianticは最近、ブログ記事を公開し、ボットが自動トラフィックを生成することで引き起こしていた問題について詳しく説明しました。この問題は、実際に中南米でのサービス開始を妨げていました。記事内のグラフによると、Nianticが8月3日13:00(太平洋時間)に自動化への対策を導入して以降、空間クエリのトラフィックが大幅に減少しています。自動トラフィックは、実際のプレイヤーによるトラフィックの約2倍に達していたとみられます。ここ数週間、Pokémon Goのサーバーが著しく過負荷になっていたのも無理はありません。

図1. Nianticがスクレイパーのブロックを開始して以降、空間クエリのトラフィックは50%以上減少しました。 出典: Nianticのブログ記事
Pokémonボットを知る
Pokémonボットには2つの種類があります。1つ目は通常のゲームプレイを自動化するタイプで、歩き回ったりPokémonを捕まえたりする操作を自動化するなど、ほかのゲームアプリでもよく問題となっています。この種のボットには、MyGoBotや PokemonGo-Bot などがあります。一方、Pokémon Goの登場をきっかけに、Pokémonの位置情報を提供する「Tracker」または「Mapper」と呼ばれる新しいタイプのボットが開発されました。これらのボットは、 Pokevision や Go Radar などのPokémon Goマッピングサービスを支えています。
Pokémon Goボットの仕組み
モバイルAPIボットとは、モバイルアプリとそのバックエンドサーバー(この場合はNianticのサーバー)間の通信を模倣するプログラムです。ボットは、実行された操作をサーバーに通知し、サーバーからの応答を受け取ります。
図2は、指定した場所から3歩以内にいる近くのPokémonを示すPokémon Goマップのスクリーンショットです。これを実現するため、ボットの作成者は通常、次の手順に従います。
- モバイルアプリとバックエンドサーバー間の通信プロトコルをリバースエンジニアリングします。ボット作成者はゲームをプレイしながら、アプリとサーバー間の通信をキャプチャし、プロトコル形式を解析します。
- 一連の「正規の」リクエストをバックエンドサーバーに送信して、アクションを実行するプログラムを作成します。この場合、近くにいるPokémonの位置情報は、実際にその場所まで歩かなくても、対象のGPS座標を指定した1回のリクエストで取得できます。ボットにとっての課題は、サーバーによる検知を回避し、実在する人間のように見せることです。
- Google Mapsとの連携や、ボット独自の地図機能など、ユーザー向けの関連機能を提供します。

図2. Pokémon Goのマップのスクリーンショット
モバイルアプリのクラックと防御策
Pokémon Goアプリを例に、リバースエンジニアリングによってモバイルアプリが解析され、その秘密が暴かれる仕組みを見ていきましょう。攻撃者は主にPokémon GoのAndroidアプリを悪用したため、ここではAndroidアプリの解析と防御に焦点を当てます。
プロトコルのリバースエンジニアリング
Pokémon Goアプリとバックエンドサーバーは、SSL経由のProtoBufを使用して通信します。ProtoBufは、ネットワーク上で転送されるデータ形式を定義します。たとえば、プレイヤー統計情報のProtoBuf定義の一部を以下に示します。

Pokémon Goは、わずか2週間でPOGOProtosによってリバースエンジニアリングされ、オンラインで公開されました。なぜこれほど短期間で実現できたのでしょうか。当初、Nianticは証明書ピンニングを使用していませんでした。
証明書ピンニングは、中間者攻撃への対策として一般的に使用される手法です。簡単に言えば、モバイルアプリは、アプリ自体に埋め込まれたサーバー証明書のみを信頼します。証明書ピンニングによる保護がなければ、攻撃者は容易にMitmproxyやFiddlerなどのプロキシをセットアップし、攻撃者が作成した証明書を自身のスマートフォンにインストールできます。次に、プロキシ経由でトラフィックをルーティングするようスマートフォンを設定し、Pokémon GoアプリとNianticのサーバー間のトラフィックを傍受できます。実際に、これを容易にするPokémon Go専用のプロキシツールとしてpokemon-go-mitmがあります。
7月31日、NianticはサーバーとPokémon Goアプリの両方に大幅な変更を加えました。証明書ピンニングによる保護を備えたPokémon Go 0.31.0がリリースされました。しかし残念ながら、時すでに遅く、通信プロトコルはすでにGitHubで公開されていました。また、証明書ピンニングを正しく実装することは必ずしも容易ではありません。以降のセクションでは、攻撃者が証明書ピンニングを回避するためによく使用する手法をいくつか取り上げます。
APKの静的解析
The Androidアプリケーションパッケージ(APK)は、パッケージファイル形式で、Androidでモバイルアプリをインストールするために使用されます。Androidアプリは主にJavaで記述され、Javaコードはdex形式にコンパイルされてapkファイルに組み込まれます。また、Androidアプリは、ネイティブコードで記述された共有ライブラリ(Android NDK)を呼び出す場合もあります。
Dexファイルは、Baksmaliなどのツールを使用してSMALI言語に容易に逆アセンブルできることが知られています。さらに、dex2jarやjd-guiなどのツールを使用すると、Dexファイルを読みやすいJavaコードに逆コンパイルできます。攻撃者はこれらの手法を使用して、Pokémon GoのAndroidアプリ(バージョン0.29.0および0.31.0)をJavaコードに逆コンパイルしました。以下に示すサンプルコードでは、com.nianticlabs.nia.network.NianticTrustManagerクラスの証明書ピンニングを実装しています。

アプリケーションのソースコードが公開されていると、リバースエンジニアリングは極めて容易になります。 Pokemon Go Xposed は、100行未満のJavaコードを使用して、MITMProxyの証明書がNianticの正規の証明書であるとPokémon Goアプリに誤認させました。
Pokemon Go Xposedはどのようにしてこれを実現したのでしょうか。方法は非常に簡単です。このツールは、上記のコードスニペットにある関数checkServerTrustedの呼び出しをフックするだけです。このフックにより、関数の第1パラメーターであるchainがNianticの証明書の値に変更されます。そのため、プロキシがどのような未承認の証明書を使用しても、Pokémon Goアプリはその証明書を信頼するよう仕向けられます。
攻撃者による逆アセンブルや静的解析を困難にするのに役立つツールは数多くあります。 ProGuard と DexGuard は、Javaコードとdexファイルを難読化するツールです。難読化により、逆コンパイルされた状態でもコードが読みにくくなります。別の方法として、 Android packers を使用してAndroidアプリの元のclasses.dexファイルを暗号化することもできます。暗号化されたdexファイルは実行時にメモリ内で復号されるため、ほとんどの攻撃者にとって静的解析は、不可能ではないにしても極めて困難になります。ネイティブライブラリの使用も、アプリのリバースエンジニアリングを大幅に困難にする方法の1つです。
ネイティブライブラリのリバースエンジニアリング
最も興味深かったのは、pokemongodevのハッカーとNianticの間で繰り広げられた、「Unknown6」というフィールドをめぐる攻防です。このフィールドは、特定の場所の近くにいるPokémonを取得するためのマップリクエストで送信される署名に含まれていました。「Unknown6」は、リバースエンジニアリングされたprotobufに含まれる、用途が特定されていないフィールドの1つです。当初、Unknown6にどのような値を指定しても、Nianticのサーバーはそのまま受け入れていました。しかし、08/03の太平洋時間13:00以降、すべてのPokémon Goボットが突然Pokémonを一切見つけられなくなり、最終的に図1に示すクエリ数の大幅な減少につながりました。
その後、ハッカーたちはプロトコル内の「Unknown6」フィールドの重要性に気付き、当初はUnknown6がリクエストの完全性を検証するための何らかのダイジェストまたはHMACではないかと推測しました。これにより、pokemongodevコミュニティの関心が一気に高まり、謎のフィールドの解読を試みるため、「Unknown6」チームがすぐに結成されました。Discordチャンネルは、プログラマーと非プログラマーの双方から大きな関心が寄せられたため非公開になりましたが、ライブアップデートチャンネルでは、解読作業の進捗が随時共有されました。3日と5時間後の8月6日午後、Unknown6チームは解読に成功したと発表し、近くにいるPokémonを再び取得できるようになった更新版のPokémon Go APIを公開しました。
ハッキングの詳細に関する技術解説はまだ公開されていませんが、関連する多くのツールや技術がフォーラムやライブ更新で言及されました。IDA-ProはHex-Raysが提供する、ネイティブライブラリのARMコードを逆アセンブルできるプロフェッショナル向けツールです。また、新しいHex-Rays decompilerでは、バイナリコードファイルをC言語風の形式に逆コンパイルできます。攻撃者はこれらのツールを使用して、実行時にモバイルアプリとそのライブラリをデバッグし、動的解析を行えます。もちろん、このような強力なツールを使用しても、バイナリプログラムのリバースエンジニアリングは依然として極めて困難です。意図的な難読化が施されていなくても、逆アセンブルまたは逆コンパイルされたコードは理解しにくく、コード量も膨大になることが少なくありません。必要な作業が複雑で予測困難であることを示す例として、ライブ更新チャンネルとその後のインタビューでは、「Unknown6」の暗号化関数は数時間以内に特定されたものの、チームは「Unknown22」という別のフィールドの解析にさらに長い時間を費やし、最終的にそれがUnknown6とは無関係だったことが説明されています。
そのため、難読化は、ネイティブライブラリの保護において、今なお多くの実用的なメリットがあります。バイナリに高度な難読化を施すことで、リバースエンジニアリングの難易度が桁違いに高まる可能性があります。しかし、WindowsやWindowsアプリケーションのシリアルコードが数多くクラックされてきたことからも分かるように、強い動機を持つモバイルクラッカーは、しばしばクラックに成功します。
サーバー側の保護
サーバー側の防御は、クライアント側の防御とはまったく異なる仕組みで機能します。ここでは、Pokémon GoのモバイルAPIを保護するために使用される手法をいくつか紹介します。
レート制限
レート制限は、自動化されたトラフィックを停止、または少なくとも減速させるために一般的に用いられる手法です。初期の頃、Pokémonスキャナーは1秒あたり数十件のリクエストを送信し、数十個のセルをスキャンして、すべてのPokémonを見つけることができました。
7月31日、Nianticはレート制限による保護を追加しました。1つのアカウントから約5秒以内に複数のマップリクエストが送信された場合、Nianticのサーバーは最初のリクエストのみを受け付け、残りを破棄しました。攻撃者は、これらのレート制限に対して次の方法で対応しました。a)スキャンプログラムから送信するマップリクエストの間隔を5秒空ける b)複数のアカウントと複数のスレッドを使用してレート制限を回避する
Pokémon Goの場合、レート制限の導入は、自動化された攻撃の新たな戦場となるアカウントの自動作成を招いただけでした。攻撃者は、レート制限が過度に攻撃的なスクレイパーや初心者の攻撃者による自動化を抑制する基本的な手法としては有効である一方、高度な攻撃者による自動リクエストの送信を防ぐことはできないと、すぐに気付きました。
IPブロッキング
IPブロッキングは、標準的なネットワークファイアウォールやWeb Application Firewall(WAF)が、不審なIPアドレスからのリクエストを破棄するために使用する従来の手法です。IPレピュテーションを追跡するデータベースは数多くあり、ファイアウォールやWAFはこうした脅威インテリジェンスを定期的に取得できます。
一般に、IPベースのブロックはリスクが高く、効果的ではありません。トラフィック量が多いIPを無差別にブロックすると、大学や企業のNATまでブロックしてしまう可能性があります。一方、多くのPokémonボットやスキャナーは、家庭向けの動的IPアドレスを使用している場合があります。これらのIPはISPの顧客間で共有されているため、IPを長期間ブロックすると、正規のプレイヤーまでアクセスできなくなる可能性があります。
Amazon Web Services(AWS)やDigital Oceanなどのホスティングサービスも、攻撃者が仮想マシンや新しいIPアドレスを入手する手段となります。攻撃者は、盗んだクレジットカードを使えば、こうしたリソースを無料で入手することさえ可能です。一方、正規ユーザーがWebの閲覧やゲームのプレイにホスティングサービスを利用することはないため、ホスティングサービスのIPアドレスをブロックすることは安全な防御策であり、サーバー側で広く用いられています。Nianticは、このフォーラム投稿によると、AWSのIPアドレスを禁止する可能性があります。
行動分析
行動分析は通常、ほかの防御を回避できる高度な攻撃者に対する最後の防衛線です。ボットの行動は人間とは大きく異なります。たとえば、実際の人間が24時間365日ゲームをプレイしたり、1秒間に5匹のポケモンを捕まえたりすることはできません。行動分析は有望なアプローチに思えますが、Pokémon Goのような膨大なデータ量を処理できる高精度な検知システムの構築は容易ではありません。
Nianticはこのほど、GPSスプーフィングを利用して「テレポート」(つまり、あり得ないほどの速さで突然移動)する不正ユーザーに対し、ソフトBANを導入しました。「ソフトBAN」にとどめたのは、誤検知の可能性があるためと考えられます。家族でアカウントを共有する場合があるほか、GPSの測位情報が不正確なこともあり、正当な利用でもボットのように見える可能性があります。
2016年8月12日頃、Nianticはウェブサイトに告知を掲載し、利用規約に違反するとPokémon Goアカウントが永久に停止される可能性があると説明しました。ボットを対象とする複数のアカウント停止ルールも非公式に明らかにされました。たとえば、Pokemonの過剰捕獲に関するルールでは、1日に1,000匹を超えるPokemonを捕まえたアカウントが停止されます。また、Nianticは正規のプレイヤーに対し、不正行為をするプレイヤーや不適切なプレイヤーを報告するよう呼びかけています。
当社の経験では、行動モデリングに基づく検知は非常に効果的な場合がありますが、技術面またはコスト面の理由から、社内での構築が現実的でないことも少なくありません。Nianticはブログ記事で、「この問題への対処には機会費用も伴います。開発者は、新機能の開発ではなく、この問題の抑制に時間を費やさなければなりません」と述べています。さらに大きな問題は、ボットネットや、一般的な防御策を回避するために設計された各種ツールを駆使する、執拗で技術に精通した攻撃者から防御するテクノロジーを構築するには、高度に専門的なスキルを幅広く備えた人材と、膨大な開発作業が必要になることです。
ゲームはまだ終わっていない
Pokémon Goがプレイヤーに愛され続ける限り、ボット作成者とNianticの攻防も続くでしょう。自動化されたトラフィックへの対策は、ゲーム業界だけでなく、あらゆる業界に共通する課題です。同様の攻防は、銀行、航空会社、小売業者のアプリでも繰り広げられており、そこでの損失は数匹のカビゴンを失うこととは桁違いです。望ましくない自動化されたトラフィックによって顧客やユーザーがサービスを利用できなくなる場合、ボットや関連する攻撃ツールは、企業にとって単なる遊びでは済みません。
著者について
関連するブログ記事

F5 Application Study Tool:OpenTelemetryによるF5 BIG-IP環境の監視
F5の新しいオープンソースツールは、BIG-IP環境を詳細に可視化し、データを追跡するとともに、強力でカスタマイズ可能なインサイトを得るための基盤を提供します。
F5 BIG-IPでAI防御を実現
F5 BIG-IP Advanced WAF、BIG-IP APM、BIG-IP SSL Orchestratorが、生成AIアプリ向けに包括的なセキュリティソリューションを提供する仕組みをご覧ください。
F5 Advanced WAFによるGraphQL APIの保護
ここ数年、多くの組織がデジタルトランスフォーメーションを進めており、COVID-19のパンデミックによってその動きは加速しています。
アプリケーションサービスの現状 通信業界版:リーダーとしての台頭
通信ネットワークが進化し、さまざまな業界の幅広いユースケースに対応するなか、通信業界の回答者がテクノロジーリーダーとしての存在感を高めていることがわかります。
デジタルトランスフォーメーションは、単なるペーパーレス化ではない
デジタルトランスフォーメーションは、単なるペーパーレス化ではありません。真のモダナイゼーションにアプリケーションアーキテクチャとセキュリティの再構築が必要な理由を、F5ブログでご覧ください。
やめましょう。もう本当にやめましょう。HTTPSはHTTPより高速ではありません。
もうやめましょう。HTTPSはHTTPより高速ではありません。プロトコルのパフォーマンスに関する微妙な違いと、暗号化トラフィックを適切に最適化する方法については、F5ブログをご覧ください。