Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@
- [AWS - Step Functions Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-stepfunctions-post-exploitation/README.md)
- [AWS - STS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sts-post-exploitation/README.md)
- [AWS - VPN Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-vpn-post-exploitation/README.md)
- [Readme](pentesting-cloud/aws-security/aws-post-exploitation/aws-workmail-post-exploitation/README.md)
- [AWS - Privilege Escalation](pentesting-cloud/aws-security/aws-privilege-escalation/README.md)
- [AWS - Apigateway Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apigateway-privesc/README.md)
- [AWS - AppRunner Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apprunner-privesc/README.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ aws sesv2 send-custom-verification-email --email-address <value> --template-name

Still to test.

## WorkMail pivot to bypass SES sandbox

When `ses:GetAccount` shows the account is still in the SES sandbox and `ses:ListIdentities` returns no verified senders, attackers can **pivot to WorkMail** to send immediately (no sandbox and higher default quotas) by creating orgs, verifying domains, and registering mailboxes.

{{#ref}}
../aws-workmail-post-exploitation/README.md
{{#endref}}

## References

- [Threat Actors Using AWS WorkMail in Phishing Campaigns](https://www.rapid7.com/blog/post/dr-threat-actors-aws-workmail-phishing-campaigns)

{{#include ../../../../banners/hacktricks-training.md}}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# AWS - WorkMail Post Exploitation

{{#include ../../../../banners/hacktricks-training.md}}

## Abusing WorkMail to bypass SES sandbox

Even if SES is stuck in the **sandbox** (verified-recipient only, ~200 msgs/24h, 1 msg/s), WorkMail has no equivalent restriction. An attacker with long-term keys can spin up disposable mail infra and start sending immediately:

1. **Create a WorkMail org (region-scoped)**
```bash
aws workmail create-organization --region us-east-1 --alias temp-mail --directory-id <dir-id-if-reusing>
```
2. **Verify attacker-controlled domains** (WorkMail invokes SES APIs as `workmail.amazonaws.com`):
```bash
aws ses verify-domain-identity --domain attacker-domain.com
aws ses verify-domain-dkim --domain attacker-domain.com
```
3. **Provision mailbox users** and register them:
```bash
aws workmail create-user --organization-id <org-id> --name marketing --display-name "Marketing"
aws workmail register-to-work-mail --organization-id <org-id> --entity-id <user-id> --email [email protected]
```

Notes:
- Default **recipient cap** documented by AWS: **100,000 external recipients/day per org** (aggregated across users).
- Domain verification activity will appear in CloudTrail under SES but with **`invokedBy`: `workmail.<region>.amazonaws.com`**, so SES verification events can belong to WorkMail setup rather than SES campaigns.
- WorkMail mailbox users become **application-layer persistence** independent from IAM users.

## Sending paths & telemetry gaps

### Web client (WorkMail UI)
- Sends surface as **`ses:SendRawEmail`** events in CloudTrail.
- `userIdentity.type` = `AWSService`, `invokedBy/sourceIPAddress/userAgent` = `workmail.<region>.amazonaws.com`, so the **true client IP is hidden**.
- `requestParameters` still leak sender (`source`, `fromArn`, `sourceArn`, configuration set) to correlate with newly verified domains/mailboxes.

### SMTP (stealthiest)
- Endpoint: `smtp.mail.<region>.awsapps.com:465` (SMTP over SSL) with the mailbox password.
- **No CloudTrail data events** are generated for SMTP delivery, even when SES data events are enabled.
- Ideal detection points are **org/domain/user provisioning** and SES identity ARNs referenced in subsequent web-sent `SendRawEmail` events.

<details>
<summary>Example SMTP send via WorkMail</summary>

```python
import smtplib
from email.message import EmailMessage

SMTP_SERVER = "smtp.mail.us-east-1.awsapps.com"
SMTP_PORT = 465
EMAIL_ADDRESS = "[email protected]"
EMAIL_PASSWORD = "SuperSecretPassword!"

target = "[email protected]" # can be unverified/external
msg = EmailMessage()
msg["Subject"] = "WorkMail SMTP"
msg["From"] = EMAIL_ADDRESS
msg["To"] = target
msg.set_content("Delivered via WorkMail SMTP")

with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as smtp:
smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
smtp.send_message(msg)
```

</details>

## Detection considerations

- If WorkMail is unnecessary, block it via **SCPs** (`workmail:*` deny) at the org level.
- Alert on provisioning: `workmail:CreateOrganization`, `workmail:CreateUser`, `workmail:RegisterToWorkMail`, and SES verifications with `invokedBy=workmail.amazonaws.com` (`ses:VerifyDomainIdentity`, `ses:VerifyDomainDkim`).
- Watch for anomalous **`ses:SendRawEmail`** events where the identity ARNs reference new domains and the source IP/UA equals `workmail.<region>.amazonaws.com`.

## References

- [Threat Actors Using AWS WorkMail in Phishing Campaigns](https://www.rapid7.com/blog/post/dr-threat-actors-aws-workmail-phishing-campaigns)
- [AWS WorkMail limits](https://docs.aws.amazon.com/workmail/latest/adminguide/limits.html)

{{#include ../../../../banners/hacktricks-training.md}}
14 changes: 14 additions & 0 deletions src/pentesting-cloud/aws-security/aws-services/aws-iam-enum.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ aws iam list-mfa-devices
aws iam list-virtual-mfa-devices
```

### Stealth permission confirmation via intentional failures

When `List*` or simulator APIs are blocked, you can **confirm mutating permissions without creating durable resources** by forcing predictable validation errors. AWS still evaluates IAM before returning these errors, so seeing the error proves the caller has the action:

```bash
# Confirm iam:CreateUser without creating a new principal (fails only after authz)
aws iam create-user --user-name <existing_user> # -> EntityAlreadyExistsException

# Confirm iam:CreateLoginProfile while learning password policy requirements
aws iam create-login-profile --user-name <target_user> --password lower --password-reset-required # -> PasswordPolicyViolationException
```

These attempts still generate CloudTrail events (with `errorCode` set) but avoid leaving new IAM artifacts, making them useful for **low-noise permission validation** during interactive recon.

### Permissions Brute Force

If you are interested in your own permissions but you don't have access to query IAM you could always brute-force them.
Expand Down