SECCON 2015 × CEDEC CHALLENGE
-
Upload
kusanok -
Category
Technology
-
view
1.045 -
download
4
Transcript of SECCON 2015 × CEDEC CHALLENGE
SandbagとSUNIDRAのチート手法およびセキュリティ上の問題点
Superflip(@kusano_k)
Sandbagの問題
•不正なスコアの送信
•通信が平文
• APIサーバーのXSS
Sandbag –不正なスコアの送信 –手法
• http://api.sandbag2015.net/score/rankingに下記のJSON形式のデータをPOSTで送る
• {"uuid":"01234567-89ab-cdef-0123-456789abcdef","name":"kusano","point":2147483647}
>curl -X POST -d "{¥"uuid¥":¥"01234567-89ab-cdef-0123-456789abcdef¥",¥"name¥":¥"kusano¥",¥"point¥":2147483647}" http://api.sandbag2015.net/score/ranking{"rank":"0"}
Sandbag –不正なスコアの送信 –影響度
•ユーザー体験を損なう
Sandbag –不正なスコアの送信 –対策案
•通信のキャプチャにより容易に手法を発見できた
•通信の暗号化
•アプリの難読化
•完璧な対策は不可能•ランキング対象を全てのユーザーではなく、ユーザーのフレンドのみにするなど、チートされてもユーザーが嫌な思いをしないようなゲーム設計にする
Sandbag –通信が平文 –概要
•通信のキャプチャにより名前やポイントの送信が確認できた=通信が平文で行われている
Sandbag –通信が平文 –影響度
•ユーザーの個人情報(名前、ポイント)が漏洩する危険性がある
•他のユーザーになりすまされる危険性がある
•スマートフォンユーザーは公衆Wi-Fiなど傍受可能な手段でインターネットに接続することが多い
•チートよりもこちらのほうが問題
Sandbag –通信が平文 –対策案
•通信の暗号化
•下記のような暗号化では不充分
•アプリ内に埋め込んだ鍵で暗号化
•アプリを解析されて鍵を抜き出される
• DH鍵交換など
• MITM攻撃に対して脆弱
• HTTPSを使うのが簡単
•エラーが発生したらちゃんとエラーにする
public void onReceivedSslError(WebView paramWebView,SslErrorHandler paramSslErrorHandler,SslError paramSslError)
{paramSslErrorHandler.proceed();
}
Sandbag – APIサーバーのXSS –手法
•名前を「<s>hogehoge」などとしてスコアを送信
• http://api.sandbag2015.net/score/rankingをブラウザで開く
※私が送信したデータではありません
Sandbag – APIサーバーのXSS –影響度
•例えば、http://bbs.sandbag2015.net/というURLでユーザー交流用の掲示板を運営し、 .sandbag2015.net でCookieを発行していると、なりすましなどが可能になる
Sandbag – APIサーバーのXSS –対策案
• Content-Typeをapplication/jsonにする
SUNIDRA
•裏技
•不正なスコアの送信
• 301pt以上のスコアの表示
SUNIDRA –裏技 –手法
•通常は
• HP: 100•攻撃力: 10
•名前を「Warrior」にすると
•攻撃力: 24
•名前を「Phoenix」にすると
• HP: 999
•名前を「Lunatic」にすると
• HP: 15•攻撃力: 5
SUNIDRA –裏技 –影響度
•チートではなく正しい裏技(?)なので特に影響は無いのでは
SUNIDRA –裏技 –対策案
•難読化はなされているが、文字列の暗号化が弱い
•文字列ごとに決まった値と xorをすると復号できる
• 256通りなので全探索可能
•より強力な難読化ツールの導入
•裏技の名前を直接コード中に書くのではなく、ハッシュ値を使う
resourceを0x07でxor
SUNIDRA –不正なスコアの送信 –手法
• 手法というか、スコア送信の仕様
• https://cedec2015.seccon.jp/cedec2015/GameCtrl/ にゲーム開始時とゲームクリア時にs, p, gをform-urlencodeしてPOSTで送信
• s
• ゲーム開始時: Start
• ゲームクリア時: GameClear
• p
• 名前やスコアをgで暗号化
• 詳細は次ページ
• g
• pの暗号化に使用する鍵
• ゲーム開始時: Base64で復号すると32バイト以下になる文字列なら何でも良い
• 本アプリでは32バイトのBase64っぽい文字列(復号すると24バイト)
• ミス?
• 解析の攪乱のため?
• ゲームクリア時: ゲーム開始時にサーバーから送られてくる文字列
• ゲームクリア時のpはこの文字列で暗号化する
このせいで悩んだ(´・ω・`)
SUNIDRA –不正なスコアの送信 –手法(pの構成)
• 【ランダム英数字(/+)256文字】:【アプリのSHA1ハッシュ】,【プレイヤーHP】,【ボスHP】,【残り時間】,【プレイヤー名】
• アプリのSHA1ハッシュ
• アプリのHSA1ハッシュをBase64エンコード
• g6J6KPwHXeLG+7aqoaUS+fvJDTo=
• アプリの改竄対策
• 修正版がランキングに対応していないのはこのため
• プレイヤHP
• ゲームクリア時に0以下だと弾かれる
• ボスHP
• ゲームクリア時に1以上だと弾かれる
• 残り時間
• ランキングに使われる
• ゲームクリア時に301以上だったり、-1以下だったりすると弾かれる
• プレイヤー名
• Base64エンコードして送信
• 何でも良い(後述)
SUNIDRA –不正なスコアの送信 –手法(pの暗号化)
• pはRijndael(AES)で暗号化して送信する
• 鍵長
• 256ビット
• ブロック長
• 256ビット
• なので、AESではない
• PyCryptoが対応していなくて面倒だった
• パディング
• ゼロ埋め
• 暗号利用モード
• ECB
• 一般的には良くないとされるが、このアプリでは特に悪用方法が思いつかなかった
• ECBなのでIVを指定する必要は無い
• 暗号化は2段階
k = crypt(key=g, plain="6789ABCDEFGHIJKLMNOPQRSTUVWXYZ")p = crypt(key=k, plain=p)
なぜか32バイトではなく30バイトミス? 解析の攪乱?
SUNIDRA –不正なスコアの送信 –影響度
•ユーザー体験を損なう
SUNIDRA –不正なスコアの送信 –対策案
•チート手法の発見方法
•ルート証明書を端末に追加して、HTTPS通信の解析
•アプリが難読化されていると、解析の確認用に実際の通信内容が欲しい
•アプリのコードの解析
•より強力な難読化ツールの導入
•(OSだけではなく)アプリ側でも証明書を検証する
SUNIDRA –不正なスコアの送信 –面倒だったこと
•ゲームオーバー時にはスコアの送信をしていない
•一度ゲームをクリアする必要があった
•どの関数を呼び出しているかわからない
× obj = this.f(Encoding.ASCII.GetBytes(arg_37B_0),~
○ obj = this.f(Convert.FromBase64String(arg_37B_0),~
SUNIDRA - 301pt以上のスコアの表示 –手法
•普通は301pt以上のスコアを送信するとエラーになる
•名前を「kusano¥n 09: 999pt, kusano」にしてスコアを送信
SUNIDRA - 301pt以上のスコアの表示 –対策案
•適切なエスケープ
•テキスト形式なので、¥nをエスケープ