Android Applications Basics

Reading time: 40 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

Android Security Model

二つの層があります:

  • OSは、インストールされたアプリケーションを互いに隔離します。
  • アプリケーション自体は、開発者が特定の機能を公開し、アプリケーションの機能を構成することを可能にします。

UID Separation

各アプリケーションには特定のユーザーIDが割り当てられます。これはアプリのインストール時に行われ、アプリはそのユーザーIDが所有するファイルまたは共有ファイルとしか相互作用できません。したがって、アプリ自体、OSの特定のコンポーネント、およびルートユーザーのみがアプリのデータにアクセスできます。

UID Sharing

二つのアプリケーションは同じUIDを使用するように構成できます。これは情報を共有するのに便利ですが、一方が侵害されると両方のアプリケーションのデータが侵害されることになります。これがこの動作が推奨されない理由です
同じUIDを共有するには、アプリケーションはマニフェスト内で同じandroid:sharedUserId値を定義する必要があります。

Sandboxing

Androidアプリケーションサンドボックスは、各アプリケーションを別のユーザーIDの下で別のプロセスとして実行することを可能にします。各プロセスは独自の仮想マシンを持っているため、アプリのコードは他のアプリから隔離されて実行されます。
Android 5.0(L)以降はSELinuxが強制されます。基本的に、SELinuxはすべてのプロセス間の相互作用を拒否し、その後、期待される相互作用のみを許可するポリシーを作成しました

Permissions

アプリをインストールするときに権限を要求される場合、アプリはAndroidManifest.xmlファイル内の**uses-permission要素で構成された権限を要求しています。uses-permission要素は、name属性内で要求された権限の名前を示します。また、maxSdkVersion属性もあり、指定されたバージョンよりも高いバージョンでは権限の要求を停止します。
Androidアプリケーションは最初にすべての権限を要求する必要はなく、動的に権限を要求することもできますが、すべての権限は
マニフェストに宣言されている必要があります**。

アプリが機能を公開する際には、特定の権限を持つアプリのみがアクセスできるように制限することができます
権限要素には三つの属性があります:

  • 権限のname
  • 関連する権限をグループ化するためのpermission-group属性
  • 権限がどのように付与されるかを示すprotection-level。四つのタイプがあります:
  • Normal:アプリに既知の脅威がない場合に使用されます。ユーザーは承認する必要はありません
  • Dangerous:要求されたアプリケーションに昇格したアクセスを付与することを示します。ユーザーに承認を求められます
  • Signatureコンポーネントをエクスポートするのと同じ証明書で署名されたアプリのみが権限を付与されます。これは最も強力な保護タイプです。
  • SignatureOrSystemコンポーネントをエクスポートするのと同じ証明書で署名されたアプリまたはシステムレベルのアクセスで実行されているアプリのみが権限を付与されます。

Pre-Installed Applications

これらのアプリは一般的に**/system/appまたは/system/priv-appディレクトリにあり、その中には最適化されたものもあります(classes.dexファイルが見つからないこともあります)。これらのアプリケーションは、時には過剰な権限で実行されている**ため、確認する価値があります(ルートとして)。

  • AOSP(Android OpenSource Project)ROMに付属しているもの
  • デバイスの製造元によって追加されたもの
  • 携帯電話のプロバイダーによって追加されたもの(彼らから購入した場合)

Rooting

物理的なAndroidデバイスにルートアクセスを取得するには、一般的に1つまたは2つの脆弱性を悪用する必要があります。これらは通常、デバイスおよびバージョンに特有です。
エクスプロイトが成功すると、通常、LinuxのsuバイナリがユーザーのPATH環境変数で指定された場所(例:/system/xbin)にコピーされます。

suバイナリが設定されると、別のAndroidアプリがsuバイナリとインターフェースし、ルートアクセスのリクエストを処理します。これにはSuperuserSuperSU(Google Playストアで入手可能)が含まれます。

caution

ルート化プロセスは非常に危険であり、デバイスに深刻な損傷を与える可能性があることに注意してください。

ROMs

カスタムファームウェアをインストールしてOSを置き換えることが可能です。これにより、古いデバイスの有用性を拡張したり、ソフトウェア制限を回避したり、最新のAndroidコードにアクセスしたりできます。
OmniROMLineageOSは使用するのに人気のあるファームウェアの二つです。

カスタムファームウェアをインストールするためにデバイスをルート化する必要はないこともあります一部の製造元は、文書化され、安全な方法でブートローダーのロック解除を許可しています。

Implications

デバイスがルート化されると、任意のアプリがルートとしてアクセスを要求できるようになります。悪意のあるアプリケーションがそれを取得すると、ほぼすべてにアクセスでき、電話を損傷させることができます。

Android Application Fundamentals

  • Androidアプリケーションの形式は_ APKファイル形式_と呼ばれます。基本的にはZIPファイルです(ファイル拡張子を.zipに変更することで、内容を抽出して表示できます)。
  • APKの内容(網羅的ではありません)
  • AndroidManifest.xml
  • resources.arsc/strings.xml
  • resources.arsc:バイナリXMLのようなプリコンパイルされたリソースを含みます。
  • res/xml/files_paths.xml
  • META-INF/
  • ここに証明書があります!
  • classes.dex
  • アプリケーションがデフォルトで実行するコンパイルされたJava(またはKotlin)コードを表すDalvikバイトコードを含みます。
  • lib/
  • CPUアーキテクチャごとにサブディレクトリに分けられたネイティブライブラリを格納します。
  • armeabi:ARMベースのプロセッサ用のコード
  • armeabi-v7a:ARMv7およびそれ以降のプロセッサ用のコード
  • x86:X86プロセッサ用のコード
  • mips:MIPSプロセッサ専用のコード
  • assets/
  • アプリに必要な雑多なファイルを格納し、追加のネイティブライブラリやDEXファイルを含むことがあり、時にはマルウェア作成者が追加のコードを隠すために使用します。
  • res/
  • resources.arscにコンパイルされていないリソースを含みます。

Dalvik & Smali

Android開発では、JavaまたはKotlinがアプリ作成に使用されます。デスクトップアプリのようにJVMを使用する代わりに、AndroidはこのコードをDalvik Executable (DEX)バイトコードにコンパイルします。以前は、Dalvik仮想マシンがこのバイトコードを処理していましたが、現在では新しいAndroidバージョンではAndroid Runtime (ART)が引き継いでいます。

リバースエンジニアリングでは、Smaliが重要になります。これはDEXバイトコードの人間が読めるバージョンで、ソースコードをバイトコード命令に変換するアセンブリ言語のように機能します。Smaliとbaksmaliは、この文脈でのアセンブリおよび逆アセンブリツールを指します。

Intents

インテントは、Androidアプリがそのコンポーネント間または他のアプリと通信するための主要な手段です。これらのメッセージオブジェクトは、アプリ間またはコンポーネント間でデータを運ぶこともでき、HTTP通信でのGET/POSTリクエストのように機能します。

したがって、インテントは基本的にコンポーネント間で渡されるメッセージです。インテントは特定のコンポーネントやアプリに向けられることも、特定の受取人なしで送信されることもできます。
簡単に言えば、インテントは次のように使用できます:

  • アクティビティを開始するため、通常はアプリのユーザーインターフェースを開く
  • システムやアプリに変更を通知するためのブロードキャストとして
  • バックグラウンドサービスを開始、停止、通信するため
  • ContentProvidersを介してデータにアクセスするため
  • イベントを処理するためのコールバックとして

脆弱な場合、インテントはさまざまな攻撃を実行するために使用される可能性があります

Intent-Filter

インテントフィルターは、アクティビティ、サービス、またはブロードキャストレシーバーが異なるタイプのインテントとどのように相互作用できるかを定義します。基本的に、これらのコンポーネントの能力を説明し、どのようなアクションを実行できるか、またはどのようなブロードキャストを処理できるかを示します。これらのフィルターを宣言する主な場所はAndroidManifest.xmlファイル内ですが、ブロードキャストレシーバーの場合はコーディングすることも選択肢です。

インテントフィルターは、カテゴリ、アクション、およびデータフィルターで構成され、追加のメタデータを含めることができます。この設定により、コンポーネントは宣言された基準に一致する特定のインテントを処理できます。

Androidコンポーネント(アクティビティ/サービス/コンテンツプロバイダー/ブロードキャストレシーバー)の重要な側面は、その可視性または公開状態です。コンポーネントは、**exportedtrueの値で設定されている場合、またはマニフェスト内にインテントフィルターが宣言されている場合、公開と見なされ、他のアプリと相互作用できます。ただし、開発者はこれらのコンポーネントを明示的にプライベートに保ち、他のアプリと意図せず相互作用しないようにする方法があります。これは、マニフェスト定義内でexported属性をfalse**に設定することで実現されます。

さらに、開発者は特定の権限を要求することで、これらのコンポーネントへのアクセスをさらに保護するオプションがあります。**permission**属性を設定することで、指定された権限を持つアプリのみがコンポーネントにアクセスできるようにし、誰がそれと相互作用できるかに対する追加のセキュリティと制御の層を追加します。

java
<activity android:name=".MyActivity" android:exported="false">
<!-- Intent filters go here -->
</activity>

インプリシットインテント

インテントは、インテントコンストラクタを使用してプログラム的に作成されます:

java
Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));

このActionは、以前に宣言されたインテントのACTION_SENDであり、Extraはmailto Uriです(Extraはインテントが期待している追加情報です)。

このインテントは、以下の例のようにマニフェスト内で宣言する必要があります:

xml
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

インテントフィルターは、メッセージを受信するためにアクションデータ、およびカテゴリが一致する必要があります。

"インテント解決"プロセスは、どのアプリが各メッセージを受信すべきかを決定します。このプロセスは、優先度属性を考慮し、これはインテントフィルター宣言で設定できます。優先度が高い方が選択されます。この優先度は-1000から1000の間で設定でき、アプリケーションはSYSTEM_HIGH_PRIORITY値を使用できます。競合が発生した場合、ユーザーが決定できるように"チョイザー"ウィンドウが表示されます。

明示的インテント

明示的インテントは、ターゲットとするクラス名を指定します:

java
Intent downloadIntent = new (this, DownloadService.class):

他のアプリケーションでは、以前に宣言されたインテントにアクセスするために次のように使用できます:

java
Intent intent = new Intent();
intent.setClassName("com.other.app", "com.other.app.ServiceName");
context.startService(intent);

Pending Intents

これにより、他のアプリケーションがあなたのアプリケーションの代理でアクションを実行することができます。Pending Intentを構築する際には、インテントと実行するアクションを指定する必要があります。もし宣言されたインテントが明示的でない場合(どのインテントが呼び出せるかを宣言していない場合)、悪意のあるアプリケーションが被害者アプリの代理で宣言されたアクションを実行する可能性があります。さらに、アクションが指定されていない場合、悪意のあるアプリは被害者の代理で任意のアクションを実行できるようになります。

Broadcast Intents

前のインテントとは異なり、1つのアプリだけでなく、ブロードキャストインテントは複数のアプリで受信されることができます。ただし、APIバージョン14以降は、Intent.setPackageを使用してメッセージを受信するアプリを指定することが可能です

また、ブロードキャストを送信する際に権限を指定することも可能です。受信アプリはその権限を持っている必要があります。

ブロードキャストには2種類があります:通常(非同期)と順序付き(同期)。順序受信者要素内の設定された優先度に基づいています。各アプリはブロードキャストを処理、転送、または破棄することができます

Contextクラスの関数sendBroadcast(intent, receiverPermission)を使用してブロードキャストを送信することが可能です。
また、**LocalBroadCastManagersendBroadcast**関数を使用すると、メッセージがアプリを出ることはありません。これを使用すると、受信者コンポーネントをエクスポートする必要すらありません。

Sticky Broadcasts

この種のブロードキャストは送信された後も長期間アクセス可能です
これらはAPIレベル21で非推奨となり、使用しないことが推奨されています
これにより、任意のアプリケーションがデータを盗聴することができるだけでなく、データを変更することも可能です

「sticky」という単語を含む関数(例:sendStickyBroadcastsendStickyBroadcastAsUser)を見つけた場合は、影響を確認し、削除を試みてください

Androidアプリケーションでは、ディープリンクを使用してURLを介して直接アクション(インテント)を開始します。これは、アクティビティ内で特定のURLスキームを宣言することによって行われます。Androidデバイスがこのスキームを持つURLにアクセスしようとすると、アプリケーション内の指定されたアクティビティが起動します。

スキームは**AndroidManifest.xml**ファイルに宣言する必要があります:

xml
[...]
<activity android:name=".MyActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="examplescheme" />
</intent-filter>
[...]

前の例のスキームは examplescheme:// です(category BROWSABLE にも注意してください)

次に、データフィールドで hostpath を指定できます:

xml
<data android:scheme="examplescheme"
android:host="example"
/>

ウェブからアクセスするには、次のようにリンクを設定することができます:

xml
<a href="examplescheme://example/something">click here</a>
<a href="examplescheme://example/javascript://%250dalert(1)">click here</a>

アプリで実行されるコードを見つけるために、ディープリンクによって呼び出されるアクティビティに移動し、**onNewIntent**関数を検索します。

HTMLページを使用せずにディープリンクを呼び出す方法を学びましょう。

AIDL - Androidインターフェース定義言語

Androidインターフェース定義言語(AIDL)は、Androidアプリケーションにおけるクライアントとサービス間のプロセス間通信(IPC)を容易にするために設計されています。他のプロセスのメモリに直接アクセスすることはAndroidでは許可されていないため、AIDLはオブジェクトをオペレーティングシステムが理解できる形式にマーシャリングすることで、異なるプロセス間の通信を容易にします。

主要概念

  • バウンドサービス: これらのサービスはIPCのためにAIDLを利用し、アクティビティやコンポーネントがサービスにバインドし、リクエストを行い、レスポンスを受け取ることを可能にします。サービスのクラス内のonBindメソッドは、相互作用を開始するために重要であり、脆弱性を探すためのセキュリティレビューにおいて重要な領域です。

  • メッセンジャー: バウンドサービスとして機能するメッセンジャーは、onBindメソッドを通じてデータを処理することに重点を置いてIPCを促進します。このメソッドを注意深く検査し、安全でないデータ処理や機密関数の実行がないか確認することが重要です。

  • バインダー: AIDLの抽象化によりバインダーの直接使用はあまり一般的ではありませんが、バインダーは異なるプロセスのメモリ空間間でデータ転送を促進するカーネルレベルのドライバーとして機能することを理解することは有益です。さらなる理解のために、リソースはhttps://www.youtube.com/watch?v=O-UHvFjxwZ8で利用可能です。

コンポーネント

これには、アクティビティ、サービス、ブロードキャストレシーバー、プロバイダーが含まれます。

ランチャーアクティビティとその他のアクティビティ

Androidアプリでは、アクティビティは画面のようなもので、アプリのユーザーインターフェースの異なる部分を表示します。アプリは多くのアクティビティを持つことができ、それぞれがユーザーにユニークな画面を提供します。

ランチャーアクティビティはアプリへの主要な入り口であり、アプリのアイコンをタップすると起動します。これは、特定のMAINおよびLAUNCHERインテントを持つアプリのマニフェストファイルで定義されています。

html
<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

すべてのアプリがランチャーアクティビティを必要とするわけではなく、特にユーザーインターフェースのないバックグラウンドサービスのようなものです。

アクティビティは、マニフェストで「exported」としてマークすることによって、他のアプリやプロセスに利用可能にすることができます。この設定により、他のアプリがこのアクティビティを開始できるようになります:

markdown
<service android:name=".ExampleExportedService" android:exported="true"/>

しかし、別のアプリからアクティビティにアクセスすることが常にセキュリティリスクであるわけではありません。懸念は、機密データが不適切に共有される場合に生じ、情報漏洩につながる可能性があります。

アクティビティのライフサイクルはonCreateメソッドで始まり、UIを設定し、ユーザーとのインタラクションのためにアクティビティを準備します。

アプリケーションクラス

Android開発では、アプリはApplicationクラスのサブクラスを作成するオプションがありますが、必須ではありません。このようなサブクラスが定義されると、それはアプリ内で最初にインスタンス化されるクラスになります。**attachBaseContextメソッドがこのサブクラスで実装されている場合、onCreate**メソッドの前に実行されます。このセットアップにより、アプリケーションの残りの部分が開始される前に早期初期化が可能になります。

java
public class MyApp extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Initialization code here
}

@Override
public void onCreate() {
super.onCreate();
// More initialization code
}
}

サービス

Services は、バックグラウンドオペレーションを実行できる能力を持つもので、ユーザーインターフェースなしでタスクを実行します。これらのタスクは、ユーザーが異なるアプリケーションに切り替えても実行を続けることができるため、サービスは長時間実行される操作にとって重要です。

サービスは多用途であり、さまざまな方法で開始できますが、Intents がアプリケーションのエントリーポイントとしてサービスを起動する主な方法です。startService メソッドを使用してサービスが開始されると、その onStart メソッドが動作を開始し、stopService メソッドが明示的に呼び出されるまで実行を続けます。あるいは、サービスの役割がアクティブなクライアント接続に依存している場合、bindService メソッドを使用してクライアントをサービスにバインドし、データの受け渡しのために onBind メソッドが呼び出されます。

サービスの興味深い応用には、バックグラウンドでの音楽再生やネットワークデータの取得が含まれ、ユーザーがアプリと対話することを妨げません。さらに、サービスはエクスポートを通じて同じデバイス上の他のプロセスにアクセス可能にすることができます。これはデフォルトの動作ではなく、Android Manifestファイルで明示的な設定が必要です:

xml
<service android:name=".ExampleExportedService" android:exported="true"/>

Broadcast Receivers

Broadcast receivers は、メッセージングシステムにおけるリスナーとして機能し、複数のアプリケーションがシステムからの同じメッセージに応答できるようにします。アプリは 二つの主要な方法レシーバーを登録 できます:アプリの Manifest を通じて、またはアプリのコード内で registerReceiver API を使用して 動的に。Manifest では、ブロードキャストは権限でフィルタリングされ、動的に登録されたレシーバーは登録時に権限を指定することもできます。

Intent フィルター は、両方の登録方法において重要で、どのブロードキャストがレシーバーをトリガーするかを決定します。一致するブロードキャストが送信されると、レシーバーの onReceive メソッドが呼び出され、アプリが適切に反応できるようになります。例えば、低バッテリー警告に応じて動作を調整することができます。

ブロードキャストは 非同期 で、すべてのレシーバーに順序なしで到達することもあれば、同期 で、レシーバーが設定された優先順位に基づいてブロードキャストを受け取ることもあります。ただし、どのアプリでも自分を優先させてブロードキャストを傍受できる可能性があるため、潜在的なセキュリティリスクに注意が必要です。

レシーバーの機能を理解するには、そのクラス内の onReceive メソッドを探します。このメソッドのコードは受信した Intent を操作でき、特に Ordered Broadcasts では、Intent を変更または削除する必要があるため、レシーバーによるデータ検証の重要性が強調されます。

Content Provider

Content Providers は、アプリ間で 構造化データを共有する ために不可欠であり、データセキュリティを確保するために 権限 を実装する重要性を強調します。これにより、アプリはデータベース、ファイルシステム、またはウェブなど、さまざまなソースからデータにアクセスできます。特定の権限、例えば readPermissionwritePermission は、アクセスを制御するために重要です。さらに、一時的なアクセスは、アプリのマニフェスト内の grantUriPermission 設定を通じて付与でき、pathpathPrefix、および pathPattern などの属性を利用して詳細なアクセス制御を行います。

入力検証は、SQL インジェクションなどの脆弱性を防ぐために重要です。Content Providers は、データ操作とアプリケーション間の共有を促進する基本的な操作をサポートします:insert()update()delete()、および query()

FileProvider は、ファイルを安全に共有することに特化した Content Provider です。これは、フォルダーへのアクセスを制御するための特定の属性を持ってアプリのマニフェストで定義され、android:exportedandroid:resource がフォルダーの設定を指します。機密データを誤って公開しないように、ディレクトリを共有する際には注意が必要です。

FileProvider の例としてのマニフェスト宣言:

xml
<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>

filepaths.xmlで共有フォルダーを指定する例:

xml
<paths>
<files-path path="images/" name="myimages" />
</paths>

さらなる情報は以下を確認してください:

WebViews

WebViewsはAndroidアプリ内のミニウェブブラウザのようなもので、ウェブまたはローカルファイルからコンテンツを取得します。通常のブラウザと同様のリスクに直面しますが、特定の設定を通じてリスクを軽減する方法があります。

Androidは主に2種類のWebViewを提供しています:

  • WebViewClientは基本的なHTMLには適していますが、JavaScriptのアラート機能をサポートしていないため、XSS攻撃のテストに影響を与えます。
  • WebChromeClientはフルChromeブラウザの体験に近い動作をします。

重要な点は、WebViewブラウザはデバイスのメインブラウザとクッキーを共有しないことです。

コンテンツを読み込むために、loadUrlloadDataloadDataWithBaseURLなどのメソッドが利用可能です。これらのURLやファイルが安全に使用できることを確認することが重要です。セキュリティ設定はWebSettingsクラスを通じて管理できます。例えば、setJavaScriptEnabled(false)でJavaScriptを無効にすることで、XSS攻撃を防ぐことができます。

JavaScriptの「ブリッジ」はJavaオブジェクトがJavaScriptと相互作用することを可能にし、Android 4.2以降はセキュリティのためにメソッドに@JavascriptInterfaceを付ける必要があります。

コンテンツアクセスを許可すること(setAllowContentAccess(true))は、WebViewsがContent Providersにアクセスできるようにしますが、コンテンツURLが安全であることを確認しない限りリスクがあります。

ファイルアクセスを制御するために:

  • ファイルアクセスを無効にすること(setAllowFileAccess(false))は、ファイルシステムへのアクセスを制限し、特定のアセットに例外を設け、機密でないコンテンツのみに使用されることを保証します。

その他のアプリコンポーネントとモバイルデバイス管理

アプリケーションのデジタル署名

  • デジタル署名はAndroidアプリに必須で、インストール前に真正に作成されたことを保証します。このプロセスはアプリの識別のために証明書を使用し、インストール時にデバイスのパッケージマネージャーによって検証される必要があります。アプリは自己署名または外部CAによって認証され、不正アクセスから保護され、デバイスへの配信中にアプリが改ざんされないことを保証します。

セキュリティ強化のためのアプリ検証

  • Android 4.2以降、Verify Appsという機能により、ユーザーはインストール前にアプリの安全性を確認できます。この検証プロセスは、潜在的に有害なアプリに対してユーザーに警告を発したり、特に悪意のあるアプリのインストールを防いだりすることができ、ユーザーのセキュリティを強化します。

モバイルデバイス管理 (MDM)

  • MDMソリューションは、デバイス管理APIを通じてモバイルデバイスの監視とセキュリティを提供します。これにより、モバイルデバイスを効果的に管理し、保護するためにAndroidアプリのインストールが必要です。主な機能には、パスワードポリシーの強制ストレージ暗号化の義務付け、およびリモートデータ消去の許可が含まれ、モバイルデバイスに対する包括的な制御とセキュリティを確保します。
java
// Example of enforcing a password policy with MDM
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminComponent = new ComponentName(context, AdminReceiver.class);

if (dpm.isAdminActive(adminComponent)) {
// Set minimum password length
dpm.setPasswordMinimumLength(adminComponent, 8);
}

AIDL / Binderサービスの列挙と悪用

Android Binder IPCは多くのシステムおよびベンダー提供サービスを公開します。これらのサービスは、適切な権限チェックなしにエクスポートされると攻撃面となります(AIDLレイヤー自体はアクセス制御を行いません)。

1. 実行中のサービスを発見する

bash
# from an adb shell (USB or wireless)
service list               # simple one-liner
am list services           # identical output, ActivityManager wrapper
  1. Androidアプリケーションの基本
  2. Androidアプリケーションの構造
  3. Androidアプリケーションのセキュリティ
  4. Androidアプリケーションの脆弱性
  5. Androidアプリケーションのテスト手法
  6. Androidアプリケーションの逆コンパイル
  7. Androidアプリケーションのデバッグ
  8. Androidアプリケーションのペネトレーションテスト
  9. Androidアプリケーションのセキュリティツール
  10. Androidアプリケーションの脆弱性評価
145  mtkconnmetrics: [com.mediatek.net.connectivity.IMtkIpConnectivityMetrics]
146  wifi             : [android.net.wifi.IWifiManager]
  • インデックス(最初の列)はランタイムで割り当てられます – 再起動を跨いでそれに依存しないでください。
  • バインダー名(例: mtkconnmetrics)は service call に渡されるものです。
  • 括弧内の値は、スタブが生成された完全修飾 AIDL インターフェース です。

2. インターフェースディスクリプタを取得する(PING)

すべてのバインダースタブは自動的に トランザクションコード 0x5f4e54461598968902 十進法、ASCII "_NTF")を実装します。

bash
# "ping" the service
service call mtkconnmetrics 1    # 1 == decimal 1598968902 mod 2^32

有効な応答は、Parcel内にUTF-16文字列としてエンコードされたインターフェース名を返します。

3. トランザクションの呼び出し

構文: service call <name> <code> [type value ...]

一般的な引数指定子:

  • i32 <int> – 符号付き32ビット値
  • i64 <long> – 符号付き64ビット値
  • s16 <string> – UTF-16文字列(Android 13+ではutf16を使用)

例 – MediaTekハンドセットでuid 1のネットワーク監視を開始:

bash
service call mtkconnmetrics 8 i32 1

4. 不明なメソッドのブルートフォース

ヘッダーファイルが利用できない場合、コードを反復処理してエラーが次のように変わるまで続けることができます:

Result: Parcel(00000000 00000000)  # "Not a data message"

通常の Parcel 応答または SecurityException

bash
for i in $(seq 1 50); do
printf "[+] %2d -> " $i
service call mtkconnmetrics $i 2>/dev/null | head -1
done

サービスがproguardでコンパイルされている場合、マッピングは推測する必要があります – 次のステップを参照してください。

5. onTransact()を介したコード↔メソッドのマッピング

インターフェースを実装しているjar/odexをデコンパイルします(AOSPスタブの場合は/system/frameworkを確認; OEMはしばしば/system_extまたは/vendorを使用します)。 Stub.onTransact()を検索します – それには巨大なswitch(transactionCode)が含まれています:

java
case TRANSACTION_updateCtaAppStatus:      // 5
data.enforceInterface(DESCRIPTOR);
int appId  = data.readInt();
boolean ok = data.readInt() != 0;
updateCtaAppStatus(appId, ok);
reply.writeNoException();
return true;

今やプロトタイプとパラメータタイプは明確です。

6. 欠落している権限チェックの特定

実装(しばしば内部のImplクラス)は認可を担当しています:

java
private void updateCtaAppStatus(int uid, boolean status) {
if (!isPermissionAllowed()) {
throw new SecurityException("uid " + uid + " rejected");
}
/* privileged code */
}

そのようなロジックや特権UIDのホワイトリスト(例:uid == 1000 /*system*/)がないことは脆弱性の指標です。

ケーススタディ – MediaTek startMonitorProcessWithUid()(トランザクション8)は、許可ゲートなしでNetlinkメッセージを完全に実行し、特権のないアプリがカーネルのNetfilterモジュールと相互作用し、システムログをスパムすることを可能にします。

7. 評価の自動化

Binderの偵察を加速するツール/スクリプト:

  • binderfs – サービスごとのノードを持つ/dev/binderfsを公開
  • binder-scanner.py – バインダーテーブルを歩き、ACLを印刷
  • Fridaショートカット: Java.perform(()=>console.log(android.os.ServiceManager.listServices().toArray()))

参考文献

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする