JSSEC セキュアコーディングデイ #2 |脆弱性事例
JSSECのイベント「セキュアコーディングデイ」において「事例で学ぶセキュアコーディング」と題して講演をしました。今回はその講演内容紹介の2回目です。
事例で学ぶセキュアコーディング
今回は講演内容から事例を紹介します
事例紹介
情報漏えいの事例
WebViewを使用しているゲームアプリに情報漏えいの脆弱性がありました。悪意あるアプリによりアプリが管理しているファイル等が外部に漏えいさせられてしまうという脆弱性です。
このゲームアプリはIntentでURLを受け取ることができるようになっており、その受け取ったURLをWebViewに渡すような実装になっていました。この部分を悪用することで、例えば、端末内に設置させた悪意あるHTMLファイルをこのゲームアプリに開かさることで、ゲームアプリが管理しているファイルを外部に送信させることができてしまいました。
Intentで渡されたURLを処理しているコードは次のとおりです。
まず、最初のActivityではIntentで渡された値からURLを取得し、URLであればそれを次のActivityに渡しています。
protected void goNextActivity() {
int v1 = this.getResources().getIdentifier("splash_anim_in", "anim", this.getPackageName());
int v2 = this.getResources().getIdentifier("splash_anim_out", "anim", this.getPackageName());
Intent v0 = new Intent(this.getApplication(), this.getNextActivity());
v0.setFlags(67108864);
String v3 = GCMIntentService.getUrlExtra(this.getIntent());
if(StringUtil.isNotBlank(v3)) {
GCMIntentService.putUrlExtra(v3, v0);
}
this.startActivity(v0);
URLを渡された次のActivityでは
private boolean openUrlFromNoti(Intent arg5) {
boolean v0 = false;
String v1 = GCMIntentService.getUrlExtra(arg5);
LogUtil.d("AHG@ debug MainActivity openUrlFromNoti() : " + v1);
if(StringUtil.isNotBlank(v1)) {
if(this.webView != null) {
this.webView.loadUrl(v1);
}
このようにURLがあればWebViewにそれを表示するという実装になっていました。
SSL/TLSサーバ証明書検証不備の事例 その1
Unityで作成されているゲームアプリでこの事例がありました。端末とサーバとの間でデータをやりとししながら進行するゲームです。Unityで作られているということで、その通信部分やデータのパースといった部分もC#もしくはVBで実装されており、.NETアセンブリになっています。
通信を行う際に次のようなコードが呼ばれます。
private void update_netStart()
{
ServicePointManager.set_ServerCertificateValidationCallback(new RemoteCertificateValidationCallback(this.OnRemoteCertificateValidationCallback));
this.netTaskList = new NetManager.NetTaskData[100];
for (int i = 0; i < this.netTaskList.Length; i++)
{
this.netTaskList[i].state = NetManager.enumNetTaskState.non;
}
this.listKey_Set = 0;
this.listKey_Go = 0;
this.netPhase = NetManager.enumNetPhase.ready;
}
ここではServicePointManager.ServerCertificateValidationCallbackプロパティで独自のコールバックメソッドを設定しています。その独自のコールバックメソッドは次のようなコードになっていました。
private bool OnRemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
常にtrueを返すという実装になっており、これではサーバ証明書の検証はできません。
SSL/TLSサーバ証明書検証不備の事例 その2
もう一つ同様の事例ですが、こちらはショッピング系のアプリです。先ほどのゲームアプリとは異なりこちらはWebViewをメインにしたアプリで一般的なAndroidアプリです。
このアプリはショッピング系ということもあり、全体を通してSSL/TLS通信を行っており、サーバ証明書の検証についてもきちんと行っています。しかし、一部の通信に関して検証を無視していました。
その問題のコードは次のとおりです。
private static HttpURLConnection getHttpsConnection(String arg7) throws Exception {
URLConnection v0;
KeyManager[] v6 = null;
URL v1 = new URL(arg7);
if("https".equals(v1.getProtocol())) {
TrustManager[] v3 = new TrustManager[]{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] arg1, String arg2) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg1, String arg2) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}};
SSLContext v2 = SSLContext.getInstance("SSL");
v2.init(v6, v3, ((SecureRandom)v6));
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String arg2, SSLSession arg3) {
return 1;
}
});
v0 = v1.openConnection();
((HttpsURLConnection)v0).setSSLSocketFactory(v2.getSocketFactory());
このコードが使用されていたのは、アプリのアップデータ確認機能の部分です。このアプリでは、アップデートがあるかどうか確認しアップデートがある場合ダイアログを表示しGooglePlayに誘導するという機能が実装されており、そこでこのコードが使用されていました。
他の部分では証明書の検証を行っているのになぜこの部分だけ検証を無視していたのでしょうか。それは、この部分についてはサードパーティ製のライブラリを使用していたことが原因です。
サードパーティ製のライブラリを使用することでアプリ開発が楽になります。その反面、この事例のように、サードパーティ製ライブラリが持つ脆弱性も一緒に自身のアプリに作りこまれてしまう恐れがあります。自分が書いたコードだけでなく使用したライブラリについても脆弱性がないかどうか注意する必要があります。
これらSSL/TLSサーバ証明書検証不備の脆弱性ですが、脆弱性診断の現場ではいまだに多くのアプリで見つかります。
次回
今回は講演内容から脆弱性の事例を紹介しました。次回はゲームチートの事例を紹介します。