Android Applications Basics
Reading time: 35 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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
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
バイナリとインターフェースし、ルートアクセスのリクエストを処理します。これにはSuperuserやSuperSU(Google Playストアで入手可能)が含まれます。
caution
ルート化プロセスは非常に危険であり、デバイスに深刻な損傷を与える可能性があることに注意してください。
ROMs
カスタムファームウェアをインストールすることでOSを置き換えることが可能です。これにより、古いデバイスの有用性を拡張したり、ソフトウェア制限を回避したり、最新のAndroidコードにアクセスしたりすることができます。
OmniROMやLineageOSは使用するのに人気のあるファームウェアの二つです。
カスタムファームウェアをインストールするためにデバイスをルート化する必要はないことに注意してください。一部の製造元は、文書化され、安全な方法でブートローダーのロック解除を許可しています。
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
- Dalvikバイトコードを含み、アプリケーションがデフォルトで実行するコンパイルされたJava(またはKotlin)コードを表します。
- lib/
- CPUアーキテクチャごとにサブディレクトリに分けられたネイティブライブラリを格納します。
armeabi
:ARMベースのプロセッサ用のコードarmeabi-v7a
:ARMv7およびそれ以降のプロセッサ用のコードx86
:X86プロセッサ用のコードmips
:MIPSプロセッサ専用のコード- assets/
- アプリに必要な雑多なファイルを格納し、追加のネイティブライブラリやDEXファイルを含むことがあり、時にはマルウェア作成者が追加のコードを隠すために使用します。
- res/
- resources.arscにコンパイルされていないリソースを含みます。
Dalvik & Smali
Android開発では、JavaまたはKotlinがアプリ作成に使用されます。デスクトップアプリのようにJVMを使用する代わりに、AndroidはこのコードをDalvik実行可能(DEX)バイトコードにコンパイルします。以前は、Dalvik仮想マシンがこのバイトコードを処理していましたが、現在では新しいAndroidバージョンではAndroid Runtime(ART)が引き継いでいます。
リバースエンジニアリングでは、Smaliが重要になります。これはDEXバイトコードの人間が読めるバージョンで、ソースコードをバイトコード命令に変換するアセンブリ言語のように機能します。Smaliとbaksmaliは、この文脈でのアセンブリおよび逆アセンブリツールを指します。
Intents
インテントは、Androidアプリがそのコンポーネント間または他のアプリと通信するための主要な手段です。これらのメッセージオブジェクトは、アプリ間またはコンポーネント間でデータを運ぶこともでき、HTTP通信でのGET/POSTリクエストのように機能します。
したがって、インテントは基本的にコンポーネント間で渡されるメッセージです。インテントは特定のコンポーネントやアプリに向けられることも、特定の受取人なしで送信されることもできます。
簡単に言えば、インテントは次のように使用できます:
- アクティビティを開始するため、通常はアプリのユーザーインターフェースを開く
- システムやアプリに変更を通知するためのブロードキャストとして
- バックグラウンドサービスを開始、停止、通信するため
- ContentProvidersを介してデータにアクセスするため
- イベントを処理するためのコールバックとして
脆弱な場合、インテントはさまざまな攻撃を実行するために使用される可能性があります。
Intent-Filter
インテントフィルターは、アクティビティ、サービス、またはブロードキャストレシーバーが異なるタイプのインテントとどのように相互作用できるかを定義します。基本的に、これらのコンポーネントの能力を説明し、どのようなアクションを実行できるか、またはどのようなブロードキャストを処理できるかを示します。これらのフィルターを宣言する主な場所はAndroidManifest.xmlファイル内ですが、ブロードキャストレシーバーの場合はコーディングすることも選択肢です。
インテントフィルターは、カテゴリ、アクション、およびデータフィルターで構成され、追加のメタデータを含めることができます。この設定により、コンポーネントは宣言された基準に一致する特定のインテントを処理できます。
Androidコンポーネント(アクティビティ/サービス/コンテンツプロバイダー/ブロードキャストレシーバー)の重要な側面は、その可視性または公開状態です。コンポーネントは、**exported
がtrue
の値である場合、またはマニフェストにインテントフィルターが宣言されている場合、公開と見なされ、他のアプリと相互作用できます。ただし、開発者はこれらのコンポーネントを明示的にプライベートに保ち、他のアプリと意図せず相互作用しないようにする方法があります。これは、マニフェスト定義でexported
属性をfalse
**に設定することで実現されます。
さらに、開発者は特定の権限を要求することで、これらのコンポーネントへのアクセスをさらに保護するオプションがあります。**permission
**属性を設定することで、指定された権限を持つアプリのみがコンポーネントにアクセスできるようにし、誰がそれと相互作用できるかに対する追加のセキュリティと制御のレイヤーを追加します。
<activity android:name=".MyActivity" android:exported="false">
<!-- Intent filters go here -->
</activity>
インプリシットインテント
インテントは、インテントコンストラクタを使用してプログラム的に作成されます:
Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));
Actionとして以前に宣言されたインテントはACTION_SENDであり、Extraはmailto Uriです(Extraはインテントが期待している追加情報です)。
このインテントは、以下の例のようにマニフェスト内で宣言する必要があります:
<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
値を使用できます。競合が発生した場合、「チョイザー」ウィンドウが表示され、ユーザーが決定できます。
明示的インテント
明示的インテントは、ターゲットとするクラス名を指定します:
Intent downloadIntent = new (this, DownloadService.class):
他のアプリケーションでは、以前に宣言されたインテントにアクセスするために、次のように使用できます:
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)
を使用してブロードキャストを送信することが可能です。
また、**LocalBroadCastManager
のsendBroadcast
**関数を使用すると、メッセージがアプリを離れないことが保証されます。これを使用すると、受信者コンポーネントをエクスポートする必要すらありません。
Sticky Broadcasts
この種のブロードキャストは送信された後も長期間アクセス可能です。
これらはAPIレベル21で非推奨となり、使用しないことが推奨されています。
これにより、任意のアプリケーションがデータを盗聴することができるだけでなく、データを変更することも可能です。
「sticky」という単語を含む関数(例:sendStickyBroadcast
やsendStickyBroadcastAsUser
)を見つけた場合は、影響を確認し、削除を試みてください。
Deep links / URL schemes
Androidアプリケーションでは、ディープリンクを使用してURLを介して直接アクション(インテント)を開始します。これは、アクティビティ内で特定のURLスキームを宣言することによって行われます。Androidデバイスがこのスキームを持つURLにアクセスしようとすると、アプリケーション内の指定されたアクティビティが起動します。
スキームは**AndroidManifest.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
にも注意してください)
次に、データフィールドで host と path を指定できます:
<data android:scheme="examplescheme"
android:host="example"
/>
ウェブからアクセスするには、次のようにリンクを設定することができます:
<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インテントを持つアプリのマニフェストファイルで定義されています。
<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
すべてのアプリがランチャーアクティビティを必要とするわけではなく、特にユーザーインターフェースのないバックグラウンドサービスのようなアプリは必要ありません。
アクティビティは、マニフェストで「exported」としてマークすることで、他のアプリやプロセスに利用可能にすることができます。この設定により、他のアプリがこのアクティビティを開始できるようになります:
<service android:name=".ExampleExportedService" android:exported="true"/>
しかし、別のアプリからアクティビティにアクセスすることが常にセキュリティリスクであるわけではありません。懸念は、機密データが不適切に共有される場合に生じ、情報漏洩につながる可能性があります。
アクティビティのライフサイクルはonCreateメソッドから始まり、UIを設定し、ユーザーとのインタラクションのためにアクティビティを準備します。
アプリケーションクラス
Android開発では、アプリはApplicationクラスのサブクラスを作成するオプションがありますが、必須ではありません。このようなサブクラスが定義されると、それはアプリ内で最初にインスタンス化されるクラスになります。**attachBaseContext
メソッドがこのサブクラスで実装されている場合、onCreate
**メソッドの前に実行されます。このセットアップにより、アプリケーションの残りの部分が開始される前に早期初期化が可能になります。
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ファイルで明示的な設定が必要です:
<service android:name=".ExampleExportedService" android:exported="true"/>
Broadcast Receivers
Broadcast receivers は、メッセージングシステムにおけるリスナーとして機能し、複数のアプリケーションがシステムからの同じメッセージに応答できるようにします。アプリは Manifest を通じて、または registerReceiver
API を介してアプリのコード内で 2つの主要な方法 で レシーバーを登録 できます。Manifest では、ブロードキャストは権限でフィルタリングされ、動的に登録されたレシーバーは登録時に権限を指定することもできます。
Intent フィルター は、両方の登録方法で重要であり、どのブロードキャストがレシーバーをトリガーするかを決定します。一致するブロードキャストが送信されると、レシーバーの onReceive
メソッドが呼び出され、アプリが低バッテリーアラートに応じて動作を調整するなど、適切に反応できるようになります。
ブロードキャストは 非同期 であり、順序なしにすべてのレシーバーに到達することも、同期 であり、レシーバーが設定された優先順位に基づいてブロードキャストを受け取ることもできます。ただし、任意のアプリが自分自身を優先させてブロードキャストを傍受できる可能性があるため、潜在的なセキュリティリスクに注意することが重要です。
レシーバーの機能を理解するには、そのクラス内の onReceive
メソッドを探してください。このメソッドのコードは受信した Intent を操作でき、特に Ordered Broadcasts では、データの検証が必要であることを強調しています。Ordered Broadcasts は Intent を変更または削除することができます。
Content Provider
Content Providers は、アプリ間で 構造化データを共有する ために不可欠であり、データセキュリティを確保するために 権限 を実装する重要性を強調しています。これにより、アプリはデータベース、ファイルシステム、またはウェブなど、さまざまなソースからデータにアクセスできます。readPermission
や writePermission
などの特定の権限は、アクセスを制御するために重要です。さらに、一時的なアクセスは、アプリのマニフェスト内の grantUriPermission
設定を通じて付与でき、path
、pathPrefix
、および pathPattern
などの属性を利用して詳細なアクセス制御を行います。
入力検証は、SQL インジェクションなどの脆弱性を防ぐために重要です。Content Providers は、データ操作とアプリケーション間の共有を促進する基本的な操作をサポートします: insert()
、update()
、delete()
、および query()
。
FileProvider は、ファイルを安全に共有することに特化した Content Provider です。これは、フォルダーへのアクセスを制御するための特定の属性を持ってアプリのマニフェストで定義され、android:exported
および android:resource
がフォルダー構成を指します。機密データが誤って公開されないように、ディレクトリを共有する際には注意が必要です。
FileProvider の例のマニフェスト宣言:
<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
で共有フォルダーを指定する例:
<paths>
<files-path path="images/" name="myimages" />
</paths>
さらなる情報は以下を確認してください:
WebViews
WebViewsはAndroidアプリ内のミニウェブブラウザのようなもので、ウェブまたはローカルファイルからコンテンツを取得します。通常のブラウザと同様のリスクに直面しますが、特定の設定を通じてリスクを軽減する方法があります。
Androidは主に2種類のWebViewを提供しています:
- WebViewClientは基本的なHTMLには適していますが、JavaScriptのアラート機能をサポートしていないため、XSS攻撃のテストに影響を与えます。
- WebChromeClientはフルChromeブラウザの体験に近い動作をします。
重要な点は、WebViewブラウザはデバイスのメインブラウザとクッキーを共有しないことです。
コンテンツを読み込むために、loadUrl
、loadData
、loadDataWithBaseURL
などのメソッドが利用可能です。これらのURLやファイルが安全に使用できることを確認することが重要です。セキュリティ設定はWebSettings
クラスを通じて管理できます。例えば、setJavaScriptEnabled(false)
でJavaScriptを無効にすることで、XSS攻撃を防ぐことができます。
JavaScriptの「ブリッジ」はJavaオブジェクトがJavaScriptと相互作用することを可能にし、Android 4.2以降はセキュリティのためにメソッドに@JavascriptInterface
を付ける必要があります。
コンテンツアクセスを許可すること(setAllowContentAccess(true)
)はWebViewがContent Providersにアクセスできるようにしますが、コンテンツURLが安全であることを確認しない限りリスクとなる可能性があります。
ファイルアクセスを制御するために:
- ファイルアクセスを無効にすること(
setAllowFileAccess(false)
)はファイルシステムへのアクセスを制限し、特定のアセットに対して例外を設け、機密でないコンテンツのみに使用されることを保証します。
その他のアプリコンポーネントとモバイルデバイス管理
アプリケーションのデジタル署名
- デジタル署名はAndroidアプリに必須で、インストール前に真正に作成されたことを保証します。このプロセスはアプリの識別のために証明書を使用し、インストール時にデバイスのパッケージマネージャーによって検証される必要があります。アプリは自己署名または外部CAによって認証され、無許可のアクセスから保護され、デバイスへの配信中にアプリが改ざんされないことを保証します。
セキュリティ強化のためのアプリ検証
- Android 4.2以降、Verify Appsという機能により、ユーザーはインストール前にアプリの安全性を確認できます。この検証プロセスは、潜在的に有害なアプリに対してユーザーに警告を発したり、特に悪意のあるアプリのインストールを防いだり
// 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);
}
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。