AWS Hacking & Security Study에 참여하며 각종 실습 내용을 남길 예정입니다.
1주차 주제는 S3 취약점 및 보안입니다.
S3 접근 제어
S3의 접근 제어 관련해서는 아래와 같은 정책을 활용할 수 있습니다.
- IAM
- IAM user 또는 role에 S3 관련 권한 부여
- Bucket Policy
- 각 S3에 대한 권한 부여
- IAM/IP/VPC 등에 대한 접근 제어 가능
- HTTP 차단, SSE 방식에 따른 차단 가능
- ACL(Access Control List)
- 현재 미권장 옵션이며, 신규 버킷 생성 시 disabled (= 객체 소유권이 버킷 소유자)
- 대부분 IAM + Bucket Policy로 원하는 요건을 만족시킬 수 있기 때문에 예외적으로 사용(CloudFront 로그 저장 권한 부여 등)
- 버킷 소유자와 객체 소유자 분리 가능
- 특정 객체에 대해만 Public 허용 등에 활용할 수 있음
- Allow만 가능
- Bucket / Object 별 설정 가능
- 권한 부여 대상(Grantee)
- Bucket owner (your AWS account)
- Everyone (public access)
- Authenticated users group (anyone with an AWS account)
- 주의) 동일 계정이 아니어도 타 AWS 계정 내 유효한 credential이 있다면 접근 가능
- S3 log delivery group
- Block public access
- 현재 S3 버킷 생성 시 기본적으로 private 버킷으로 생성
- Account level
- 'Block Public Access settings for this account' 메뉴를 활용하여 계정 내 모든 버킷에 대해 public access를 차단
- 현재 버킷 및 신규 버킷에 적용
- Bucket level
- 각 개별 Bucket에 설정하여 public access를 차단
- 상세 옵션
- Block public access to buckets and objects granted through new access control lists (ACLs)
- 새로운 ACL이 public을 허용하는 것을 모두 차단, 활성화 시 객체를 public read로 올리면 차단함
- Block public access to buckets and objects granted through any access control lists (ACLs)
- 기존 자원에 public 허용된 ACL을 무시함/차단
- Block public access to buckets and objects granted through new public bucket or access point policies
- 새 Bucket Policy 적용 시 public 허용 문구가 있는 것을 막음
- Block public and cross-account access to buckets and objects through any public bucket or access point policies
- 기존 버킷 정책에 Public 허용 문구가 있다면 무시함 → 기존 Public 문구가 있는 정책 수정 필요
- Block public access to buckets and objects granted through new access control lists (ACLs)
- Organization SCP
- 조직 레벨의 권한 제어
- VPC Endpoint Policy
- S3 vpc endpoint에 특정 버킷만 접근 가능하게 설정
위 정책들을 종합적으로 고려하여 최종 Allow/Deny를 결정합니다.
이때 Allow/Deny의 우선 순위는 아래와 같습니다.
- 명시적 Deny 확인
- 명시적 Allow 확인
- 최종 Deny (묵시적 Deny)
명시적 Deny가 가장 우선이며 명시적 Allow 정책이 없다면 S3에 대해 접근 권한을 얻을 수 없습니다.
S3 보안 기능
s3에는 추가적으로 보안을 강화할 수 있는 기능이 있습니다.
- pre-signed url
- 일정 시간 특정 객체에 접근할 수 있는 url 제공
- SSE (ServerSideEncryption)
- SSE-S3
- 객체 업로드 시 자동 적용
- AES256
- SSE-KMS
- SSE-S3
실습
이제 여러가지 보안 실습을 진행해보겠습니다.
pre-signed url
먼저 bucket을 하나 생성합니다. 기본적으로 Public 접근이 비활성화 된 것을 확인할 수 있습니다.
$ NICKNAME=xxxxxx
$ aws s3 mb s3://ahss-$NICKNAME-presign --region ap-northeast-2 --profile study
make_bucket: ahss-xxxxxx-presign
$ aws s3api get-public-access-block --bucket ahss-$NICKNAME-presign --profile study | jq
{
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": true,
"IgnorePublicAcls": true,
"BlockPublicPolicy": true,
"RestrictPublicBuckets": true
}
}
그 다음 이미지 파일을 하나 다운로드 받고 S3로 업로드 합니다.
$ curl https://www.nasa.gov/sites/default/files/thumbnails/image/main_image_star-forming_region_carina_nircam_final-5mb.jpg -o jameswebb.jpg
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 5185k 100 5185k 0 0 1062k 0 0:00:04 0:00:04 --:--:-- 1086k
$ aws s3 cp jameswebb.jpg s3://ahss-$NICKNAME-presign --profile study
upload: ./jameswebb.jpg to s3://ahss-xxxxxx-presign/jameswebb.jpg
$ aws s3 ls s3://ahss-$NICKNAME-presign --human-readable --profile study
2023-08-28 21:28:24 5.1 MiB jameswebb.jpg
$ lynx --dump https://ahss-$NICKNAME-presign.s3.ap-northeast-2.amazonaws.com/jameswebb.jpg
AccessDeniedAccess
DeniedK3F6E5WEW67ZQJ02a3Dk2nzRVv55j+UQ0XP34xYqbqE2EWcbKjOkIyThXzonOj8ed
8C4W6h6b112RJiGPpnIaDv5a/8=
AWS 자격증명이 없다면 파일을 다운로드 받을 수 없습니다.
이제 pre-signed URL을 생성해보겠습니다.
$ aws s3 presign s3://ahss-$NICKNAME-presign/jameswebb.jpg --expires-in 600 --region ap-northeast-2 --profile study
https://ahss-xxxxxx-presign.s3.ap-northeast-2.amazonaws.com/jameswebb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAVTPII2CIKEYZX5AV%2F20230828%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Date=20230828T123436Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Security-Token=FwoGZXIvYXdzENb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDF2Jwk6UwfT%2Fh%2B7JfiLsAeW9lnL6i7%2FjP97mf0AIISgbNlPIm5AErRssQHdy51kNeIqwu5qhEeX1%2FT01y%2F2d7uwbngDV6w1oXeJHgmceWyNJ4rbz%2BYmBw5uJGxYP%2BFDXjUwNVYsfr5zsv2K03gdyyAkp8mKP68r4HeRbTQKwlvl6I5zIlAbNjhCXB2v7dEFgDVRRqNgnXZZc%2FwkfwYcAQzOqdgpWRLzWzKByxb773AzdamepcMldahhejcpLGBphHUmZ%2Fw8HcLRQ49Nhs%2B50ZPiVDl4BGOIFQQouWX6tTT1t0ELCLDPJLLqW7ZIiIkj3Xo3ZvoTIhuUzrMyoKJGksqcGMjKUSJ2n9gjKSKbVBdaxQOZrUkvJqu5pyRwnj8lCWIWd%2FQ1R5UBo18bWbr4HvpZt%2FQDgBA%3D%3D&X-Amz-Signature=4984e569128e14e166d64db8551942e028ef3c821e99c5d80bf65b2a00911607
생성된 주소로 접속하면 누구든지 해당 이미지를 확인할 수 있습니다.
public 버킷 IP 기반 접근 제어
public 버킷은 비권장 되지만 상황에 따라 사용할 수 있습니다.
이때 지정된 IP만 버킷에 접근하도록 설정해보겠습니다.
먼저 앞서 생성한 버킷을 public 버킷으로 변경합니다.
그 다음 버킷 정책을 수정합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::ahss-$NICKNAME-presign/*"
}
]
}
이제 누구든지 버킷에 접근하여 파일을 다운로드 받을 수 있는 취약한 상태가 됩니다.
이번에는 ip 제한을 추가해보겠습니다.
{
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::ahss-닉네임-presign",
"arn:aws:s3:::ahss-닉네임-presign/*"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "X.X.X.X/32"
}
}
}
]
}
SourceIp는 아래 명령어로 확인할 수 있습니다.
$ curl ipinfo.io/ip ;echo
위 정책을 반영하면 특정 Ip에서만 객체를 다운로드 받을 수 있습니다.
SSE-KMS 관련 버킷 policy (링크)
S3 버킷은 기본적으로 SSE-S3 암호화를 사용합니다.
$ aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg --profile study | jq
{
"AcceptRanges": "bytes",
"LastModified": "2023-08-28T12:28:24+00:00",
"ContentLength": 5310371,
"ETag": "\"3bae2c6845352e627516a529fd507ffb\"",
"ContentType": "image/jpeg",
"ServerSideEncryption": "AES256",
"Metadata": {}
}
S3 버킷 암호화 방식을 변경하겠습니다.
kms 키는 별도로 생성하지 않고 aws/s3 키를 선택하겠습니다.
이제 textfile을 생성하고 업로드 해보겠습니다.
$ echo "123456789abcdefg" > textfile
$ aws s3api put-object --key text02 --body textfile --profile study --bucket ahss-$NICKNAME-presign
{
"ETag": "\"f9f2c7e384d9103b605421f54f978a46\"",
"ServerSideEncryption": "aws:kms",
"SSEKMSKeyId": "arn:aws:kms:ap-northeast-2:xxxxxxxxxxxx:key/79def8ba-aa00-4a03-9a00-a02853484a61",
"BucketKeyEnabled": true
}
kms 암호화로 변경하기 전에 업로드한 객체를 확인해봅니다.
기존 암호화 설정과 동일하게 AES256인 것을 알 수 있습니다.
$ aws s3api head-object --key text01 --profile study --bucket ahss-$NICKNAME-presign
{
"AcceptRanges": "bytes",
"LastModified": "2023-08-28T12:53:14+00:00",
"ContentLength": 17,
"ETag": "\"3ca451faac980583cffaadf8b63e6820\"",
"ContentType": "binary/octet-stream",
"ServerSideEncryption": "AES256",
"Metadata": {}
}
이제 버킷 정책에서 aws:kms만 허용하는 정책을 적용해보겠습니다.
{
"Version": "2012-10-17",
"Id": "S3-Security-Deny-unless-SSE-KMS",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::ahss-$NICKNAME-presign/ssekms-only/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
}
]
}
이제 테스트용 객체를 업로드 해보겠습니다.
$ aws s3api put-object --key text03 --body textfile --profile study --bucket ahss-$NICKNAME-presign
{
"ETag": "\"75de64acba420347f9858a7dc6895284\"",
"ServerSideEncryption": "aws:kms",
"SSEKMSKeyId": "arn:aws:kms:ap-northeast-2:385423560848:key/79def8ba-aa00-4a03-9a00-a02853484a61",
"BucketKeyEnabled": true
}
$ aws s3api put-object --key text04 --body textfile --server-side-encryption AES256 --profile study --bucket ahss-$NICKNAME-presign
{
"ETag": "\"3ca451faac980583cffaadf8b63e6820\"",
"ServerSideEncryption": "AES256"
}
$ aws s3api put-object --key text05 --body textfile --server-side-encryption aws:kms --profile study --bucket ahss-$NICKNAME-presign
{
"ETag": "\"cee2abb7c5c1ca665f797964baf35e52\"",
"ServerSideEncryption": "aws:kms",
"SSEKMSKeyId": "arn:aws:kms:ap-northeast-2:xxxxxxxxxxxx:key/79def8ba-aa00-4a03-9a00-a02853484a61",
"BucketKeyEnabled": true
}
# ssekms-only/* prefix 반영
$ aws s3api put-object --key ssekms-only/text06 --body textfile --profile study --bucket ahss-$NICKNAME-presign
An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
$ aws s3api put-object --key ssekms-only/text07 --body textfile --server-side-encryption AES256 --profile study --bucket ahss-$NICKNAME-presign
An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
$ aws s3api put-object --key ssekms-only/text08 --body textfile --server-side-encryption aws:kms --profile study --bucket ahss-$NICKNAME-presign
{
"ETag": "\"e03c06e3d9e54fa9579ab348d76c90ca\"",
"ServerSideEncryption": "aws:kms",
"SSEKMSKeyId": "arn:aws:kms:ap-northeast-2:xxxxxxxxxxxx:key/79def8ba-aa00-4a03-9a00-a02853484a61",
"BucketKeyEnabled": true
}
ssekms-only/*
prefix를 포함한 객체를 업로드할 때에는 --server-side-encryption aws:kms
가 명시되어야 업로드가 되는 것을 확인할 수 있습니다.
HTTPS 연결만 허용하기 (링크)
S3 버킷 정책을 통해 HTTPS 연결만 허용하는 실습을 해보겠습니다.
먼저 버킷 정책을 아래와 같이 수정합니다.
{
"Version": "2012-10-17",
"Id": "S3-Security-Deny-unless-HTTPS",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::ahss-$NICKNAME-presign/*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
객체에 접근해보겠습니다.
$ aws s3api head-object --key jameswebb.jpg --endpoint-url http://s3.amazonaws.com --profile study --bucket ahss-$NICKNAME-presign
An error occurred (403) when calling the HeadObject operation: Forbidden
$ aws s3api head-object --key jameswebb.jpg --endpoint-url https://s3.amazonaws.com --profile study --bucket ahss-$NICKNAME-presign
{
"AcceptRanges": "bytes",
"LastModified": "2023-08-28T12:28:24+00:00",
"ContentLength": 5310371,
"ETag": "\"3bae2c6845352e627516a529fd507ffb\"",
"ContentType": "image/jpeg",
"ServerSideEncryption": "AES256",
"Metadata": {}
}
http로는 error가 발생하지만 https로 접근 가능한 것을 볼 수 있습니다.
S3 Game
총 11개의 문제가 있는 S3 보안 설정 관련 워크샵을 진행해보겠습니다. (링크)
# Level 1 - list + get이 public
$ aws s3 ls s3://s3game-level1 --no-sign-request
2020-06-01 17:58:46 24361 S3game.png
2020-04-20 15:39:19 1568 level1-hint2.html
2020-04-20 15:39:19 1484 level1-hint3.html
2020-04-20 15:39:19 1566 level1-hint4.html
2020-04-20 21:28:16 2240 level1.html
2020-06-01 18:09:01 1936 s3game.html
2020-05-02 17:08:53 115 treasure1
$ aws s3 cp s3://s3game-level1/treasure1 . --no-sign-request
download: s3://s3game-level1/treasure1 to ./treasure1
$ cat treature1
The secret code is 748l6b6xwzl6
Go to https://s3game-level2.s3.us-east-2.amazonaws.com/level2-748l6b6xwzl6.html
# Level 2 - get이 public
list 권한은 없지만 get 권한은 있어서 파일 이름을 유추하여 다운로드 받습니다.
$ aws s3 ls s3://s3game-level2 --no-sign-request
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
$ aws s3 cp s3://s3game-level2/treasure2 . --no-sign-request
download: s3://s3game-level2/treasure2 to ./treasure2
# Level 3 - metadata
Level 2에서 얻은 treasure2를 확인하면 Access key와 Secret Access Key가 있습니다.
$ aws configure
AWS Access Key ID [********************]: 'Level2 treasure2 Access Key'
AWS Secret Access Key [*******************]: 'Level2 treasure2 Secret Access Key'
Default region name [us-east-2]:
Default output format [json]:
$ aws s3 ls s3://s3game-level3
2020-04-20 15:44:08 1721 level3-76qp7mlpzyg1-hint2.html
2020-04-20 15:44:08 1787 level3-76qp7mlpzyg1-hint3.html
2020-04-20 20:22:48 1873 level3-76qp7mlpzyg1-hint4.html
2020-04-20 21:27:42 1990 level3-76qp7mlpzyg1.html
2020-05-02 17:12:11 234 treasure3_has_no_secret_code
$ aws s3 cp s3://s3game-level3/treasure3_has_no_secret_code .
download: s3://s3game-level3/treasure3_has_no_secret_code to ./treasure3_has_no_secret_code
$ cat treasure3_has_no_secret_code
Hm... the chest is empty :(
Let's look around, may be secret code is somewhere else...
Think about where else the code can be hidden?
Find the code and go to https://s3game-level4-<THE CODE>.s3.us-east-2.amazonaws.com/level4.html
treasure3_has_no_secret_code 파일을 보면 secret code가 없어서 별도로 찾아야 합니다.
힌트를 보니 metadata를 활용해야 해서 head-object를 확인합니다.
aws s3api head-object --bucket s3game-level3 --key treasure3_has_no_secret_code | jq
{
"AcceptRanges": "bytes",
"LastModified": "2020-05-02T08:12:11+00:00",
"ContentLength": 234,
"ETag": "\"6244574e387025dec9b9b589773d4d29\"",
"ContentType": "binary/octet-stream",
"Metadata": {
"x-amz-meta-secret-code": "k73045aztqln"
}
}
x-amz-meta-secret-code 로 Level 4로 넘어갑니다.
# Level 4 - object-tag
이번에는 s3 버킷 명이 앞 버킷들과 조금 다릅니다.
$ aws s3 ls s3://s3game-level4-k73045aztqln
2020-04-20 15:45:01 2040 level4-hint2.html
2020-05-25 04:45:57 1462 level4.html
2020-05-24 02:24:41 270 treasure4_also_has_no_secret_code
$ aws s3 cp s3://s3game-level4-k73045aztqln/treasure4_also_has_no_secret_code .
download: s3://s3game-level4-k73045aztqln/treasure4_also_has_no_secret_code to ./treasure4_also_has_no_secret_code
$ cat ./treasure4_also_has_no_secret_code
Oh... this chest is empty as well :(
Let's look around, may be secret code is somewhere else...
You already know about metadata. Think where else the code can be hidden?
Find the code and go to https://s3game-level5-<THE CODE>.s3.us-east-2.amazonaws.com/level5.html
head-object에도 secret key는 없습니다.
$ aws s3api head-object --bucket s3game-level4-k73045aztqln --key treasure4_also_has_no_secret_code | jq
{
"AcceptRanges": "bytes",
"LastModified": "2020-05-23T17:24:41+00:00",
"ContentLength": 270,
"ETag": "\"70aeb0a9dbe1662df2b924288c46cdce\"",
"ContentType": "binary/octet-stream",
"Metadata": {}
}
object-tag를 확인
$ aws s3api get-object-tagging --bucket s3game-level4-k73045aztqln --key treasure4_also_has_no_secret_code
{
"TagSet": [
{
"Key": "secret_code",
"Value": "8v95e5rv7z4i"
}
]
}
# Level 5 - versioning
이번 버킷에는 treasure 파일이 없습니다.
$ aws s3 ls s3://s3game-level5-8v95e5rv7z4i
2020-05-02 17:35:32 2005 level5-hint2.html
2020-05-02 17:35:32 2802 level5-hint3.html
2020-04-20 20:08:44 1698 level5-hint4.html
2020-04-20 20:04:58 1648 level5.html
힌트를 보고 versioning을 확인합니다.
$ aws s3api get-bucket-versioning --bucket s3game-level5-8v95e5rv7z4i
{
"Status": "Enabled"
}
삭제된 파일이 있는지 확인합니다.
$ aws s3api list-object-versions --bucket s3game-level5-8v95e5rv7z4i
{
"Versions": [
{
"ETag": "\"e3545f5babf2f5ca5a9d20f7475f80ab\"",
"Size": 2005,
"StorageClass": "STANDARD",
"Key": "level5-hint2.html",
"VersionId": "4mtBa02BZXl0VmlqgATEHowXt8tZXG0U",
"IsLatest": true,
"LastModified": "2020-05-02T08:35:32+00:00"
},
...
{
"ETag": "\"9693f24274d7ec88a8563d662c34be99\"",
"Size": 126,
"StorageClass": "STANDARD",
"Key": "treasure5_is_deleted",
"VersionId": "344PQOyFqocF0TI66MbLynNNdQqHfBz3",
"IsLatest": false,
"LastModified": "2020-05-02T08:20:06+00:00"
}
],
"DeleteMarkers": [
{
"Key": "treasure5_is_deleted",
"VersionId": "EtCsdZVg383Pj4qEB9XzjPKwMWMMd_d8",
"IsLatest": true,
"LastModified": "2020-05-02T08:20:38+00:00"
}
...
삭제된 파일명과 버전 id를 사용해서 파일을 다운로드합니다.
$ aws s3api get-object --bucket s3game-level5-8v95e5rv7z4i --key treasure5_is_deleted --version-id 344PQOyFqocF0TI66MbLynNNdQqHfBz3 treasure5_is_deleted
$ cat treasure5_is_deleted
The code is vjv45x1gux81
Find the code and go to https://s3game-level6-vjv45x1gux81.s3.us-east-2.amazonaws.com/level6.html
# Level 6 - select-object-content
$ aws s3 ls s3://s3game-level6-vjv45x1gux81
2020-04-20 23:39:42 1785 level6-hint2.html
2020-07-01 23:58:43 2404 level6.html
2020-05-02 17:52:25 12884420 s3select.csv.gz
$ aws s3 cp s3://s3game-level6-vjv45x1gux81/s3select.csv.gz .
download: s3://s3game-level6-vjv45x1gux81/s3select.csv.gz to ./s3select.csv.gz
s3select.csv 파일을 열어보면 Number;Secret;Date;Round;Category;Value;Question;Answer
와 같은 정보가 ;로 구분되어있습니다.
해당 파일 안에 treasure 정보가 있는 것으로 보입니다.
select-object-content를 활용해서 검색을 해봅니다.
$ aws s3api select-object-content --bucket s3game-level6-vjv45x1gux81 \
--key s3select.csv.gz \
--expression "select * from s3object where Category = 'TREASURE'" \
--expression-type SQL \
--input-serialization '{"CSV": {"FileHeaderInfo": "USE", "FieldDelimiter": ";"}, "CompressionType": "GZIP"}' \
--output-serialization '{"CSV": {}}' "treasure6"
$ cat treasure6
2117,"8,96E+11",16/11/1993,Double Jeopardy!,TREASURE,1000,What is the fastest way to find something in a big dataset on S3?,Go to https://s3game-level7-zhovpo4j8588.s3.us-east-2.amazonaws.com/level7.html
# Level 7 - presigned URL
이번 버킷에는 ls 권한이 없습니다. 따라서 파일 명을 유추해서 접근해야합니다.
$ aws s3 ls s3://s3game-level7-zhovpo4j8588
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
문제를 봤을 때 presigned URL을 활용해야하기 때문에 이를 생성해봅니다.
먼저 treasure7로 생성해보았는데, 링크로 접속 시 Access Deny가 뜹니다.
$ aws s3 presign s3://s3game-level7-zhovpo4j8588/treasure7 --expires-in 600
https://s3game-level7-zhovpo4j8588.s3.us-east-2.amazonaws.com/treasure7?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAZBIEGK7GRDTWDGNC%2F20230828%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20230828T021154Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=cacac890bf1f7f831b8d822dcbd38bdb58c1d6262200a1d9cbd5093349e0368f
힌트를 보고 파일명을 somethingstrange로 변경해서 다시 시도합니다.
$ aws s3 presign s3://s3game-level7-zhovpo4j8588/somethingstrange --expires-in 600
https://s3game-level7-zhovpo4j8588.s3.us-east-2.amazonaws.com/somethingstrange?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAZBIEGK7GRDTWDGNC%2F20230828%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20230828T021744Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=6cb6cb6a69f0d853367ffcd3f6c563eb8b7a644129e04ae4677039637b74c5a0
생성된 링크로 접속하면 파일이 다운로드 됩니다.
해당 파일을 보면 treasure7_is_presigned 파일을 접근하는 presigned URL이 있습니다.
$ cat somethingstrange
https://s3game-level7-zhovpo4j8588.s3.amazonaws.com/treasure7_is_presigned?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAZBIEGK7GR3AZJ5BO%2F20230827%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20230827T204502Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Security-Token=IQoJb3JpZ2luX2VjELX%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMiJHMEUCIHbs5NGPAogLNIRLsRdeyaX3G7sUlXeblO2o7kOEcUr%2BAiEA8chKY9qSyt2l%2FhyhsI5i9A%2BuUQ81ZYNJjmjs81eg0GAqzQMIfhADGgw2MjExNjg0NDk0ODUiDLcFD6mylFuqqvWkEyqqA5ZlQDI1WXsq4HWEDDNu6sArBrJC3KtkAgRNCv01xTH%2FL3AZTl09pWukdm7xEwSTY9ATERftPbuDnoogaZc3Qq8L%2B44cIBZeKQC0%2F1wHK66mDFeEZprYTRryGV5PcbzhOkrMwMph69tV9T4tFEkpAHg%2BK0ES3phFj0D6h9bK2n%2BLvSUeOr7GUPOY%2FmY2CH6TUS5CHuy1P3z7DU4%2BTozUgoan7gdRs9s9nApYlxCrLibBRKp02DvA9dywB9RS780tjoJaxv6Px7Dg1xYuHC946Dvlcm1V1905Gfa6CJTKvHEVQTenHHkX2jYz9BHQGusWq%2FtR9o0zSn8HTqsGkzSjqHdOXTmiSzOE82FDxWZ%2FD0KjAiSnxiE5WtA9cFEDImXBoUhCNdUM9%2BA0YNRRIBhB1gaiiJ%2Fdqsr2EZmHr8eXkfQcP3WjKXXDdrUnv9gJ2BeijdtSU40uyl221nEmOHI0LrCevJZ3V4o%2FykaGvAwttM5ELJvStEJtPJnAfdxXleJ5%2BABDDGaVWSVrOoeY7%2Ba5vItoQxlpF45x0CydPedOPdoZou60FQJ7odjcsjDN666nBjqeAdGPt24VNL1%2BbfBUZq4rrtC%2FVKcM5EGrjJEvCuaIp3kp8pa5A8o5mZ%2F3x84%2Bl%2B5YkvXWle%2BwyIAAEzxHbhvNMNSiTHmozgji7Dr6yvox6AlxzKd%2BHz47LFBLSuANi%2BIaRBr9bJHGRLxeKfqLClQwD01zNk3RV%2Fy3J2sguskdfG7oLOnmUqkCcTCsriG1RPHfWQ%2B54mS87drcZ%2F%2F7zCOg&X-Amz-Signature=ef6bd60080faacc6523e987a17e46c364afd717b5b1219025ddb929844962ba0
다시 presigned URL에 접속하면 treasure7_is_presigned 파일이 다운로드 되고, level 8의 링크가 있습니다.
$ cat treasure7_is_presigned
The code is v6g8tp7ra2ld
Find the code and go to https://s3game-level8-v6g8tp7ra2ld.s3.us-east-2.amazonaws.com/level8.html
# Level 8 - 취약한 CloudFront 설정
$ aws s3 ls s3://s3game-level8-v6g8tp7ra2ld
2020-04-24 18:17:55 2265 level8.html
2020-05-02 18:37:19 126 treasure8_CDN
힌트에 나와있는 CloudFront URL을 파일을 다운로드 받습니다.
$ wget d2suiw06vujwz3.cloudfront.net/treasure8_CDN
--2023-08-28 20:39:04-- http://d2suiw06vujwz3.cloudfront.net/treasure8_CDN
d2suiw06vujwz3.cloudfront.net (d2suiw06vujwz3.cloudfront.net) 해석 중... 99.86.146.49, 99.86.146.150, 99.86.146.15, ...
다음으로 연결 중: d2suiw06vujwz3.cloudfront.net (d2suiw06vujwz3.cloudfront.net)|99.86.146.49|:80... 연결했습니다.
HTTP 요청을 보냈습니다. 응답 기다리는 중... 200 OK
길이: 126 [binary/octet-stream]
저장 위치: `treasure8_CDN'
treasure8_CDN 100%[==============================================================================================================================>] 126 --.-KB/s / 0s
2023-08-28 20:39:05 (2.27 MB/s) - `treasure8_CDN' 저장함 [126/126]
$ cat treasure8_CDN
The code is 781xtls2quvy
Find the code and go to https://s3game-level9-781xtls2quvy.s3.us-east-2.amazonaws.com/level9.html
# Level 9 - referer
버킷 파일 목록은 보이지만 다운로드는 할 수 없습니다.
$ aws s3 ls s3://s3game-level9-781xtls2quvy
2020-04-21 17:00:25 1540 level9-hint2.html
2020-05-02 18:47:05 2246 level9.html
2020-05-02 18:50:22 128 treasure9_referer
$ curl -O https://s3game-level9-781xtls2quvy.s3.us-east-2.amazonaws.com/treasure9_referer
$ cat treasure9_referer
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>9ZQ5C66SK110702V</RequestId><HostId>jbOWtQ2GAUvOOb1vk5I/UssSRlUtz6/rmNTJQI+DtpOjxV1XJtlYsutwsTdQ/CP/3M02+jTFPDI=</HostId></Error>%
문제에 있는 bucket policy의 "aws:Referer" 설정을 참고하여 다시 다운로드 받습니다.
$ curl -O --referer http://s3game.treasure https://s3game-level9-781xtls2quvy.s3.us-east-2.amazonaws.com/treasure9_referer
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 128 100 128 0 0 135 0 --:--:-- --:--:-- --:--:-- 136
$ cat treasure9_referer
The code is gac6tf83erp6
Find the code and go to https://s3game-level10-gac6tf83erp6.s3.us-east-2.amazonaws.com/level10.html
# Level 10 - S3 Storage Class
이번 S3는 목록이 보이지만 파일이 너무 많아 정답 파일을 바로 찾을 수가 없습니다.
$ aws s3 ls s3://s3game-level10-gac6tf83erp6
2020-05-02 19:00:31 128 03kufblhnwiw
2020-05-02 18:57:44 128 0f6e843c99to
2020-05-02 18:59:59 128 0jx774dmh047
2020-05-02 18:59:48 128 0rtmc3bs4kb6
2020-05-24 02:00:26 128 0sg0snw2oktd
2020-05-02 19:01:58 128 13iqnird613i
2020-05-02 18:57:56 128 13itwr8uz0iw
2020-05-02 18:59:47 128 183e62jsoa09
...
문제에서는 Storage Class 별로 파일을 확인하는 것을 유도합니다.
$ aws s3api list-objects --bucket s3game-level10-gac6tf83erp6 --query "Contents[?StorageClass=='STANDARD']"
[
{
"Key": "03kufblhnwiw",
"LastModified": "2020-05-02T10:00:31+00:00",
"ETag": "\"4730dca4ccc205769b149c0c84abf15c\"",
"Size": 128,
"StorageClass": "STANDARD"
},
{
"Key": "0f6e843c99to",
"LastModified": "2020-05-02T09:57:44+00:00",
"ETag": "\"13a308d161965ab89137b2cba7072938\"",
"Size": 128,
"StorageClass": "STANDARD"
},
{
"Key": "0jx774dmh047",
"LastModified": "2020-05-02T09:59:59+00:00",
"ETag": "\"3f92bbdaa4ca8f47acd409f801be03b2\"",
"Size": 128,
"StorageClass": "STANDARD"
},
{
"Key": "0rtmc3bs4kb6",
"LastModified": "2020-05-02T09:59:48+00:00",
"ETag": "\"daf98ddd78cd7635396a2f3232ae5ec0\"",
"Size": 128,
"StorageClass": "STANDARD"
},
...
$ aws s3api list-objects --bucket s3game-level10-gac6tf83erp6 --query "Contents[?StorageClass=='STANDARD_IA']"
[
{
"Key": "djq30a807iyq",
"LastModified": "2020-05-23T16:56:46+00:00",
"ETag": "\"b29bd78cd969aec7862407ff045d8aeb\"",
"Size": 128,
"StorageClass": "STANDARD_IA"
}
]
$ aws s3api list-objects --bucket s3game-level10-gac6tf83erp6 --query "Contents[?StorageClass=='GLACIER']"
[]
Standard-IA 클래스 객체가 하나 있기 때문에 해당 객체를 다운로드 받습니다.
$ aws s3 cp s3://s3game-level10-gac6tf83erp6/djq30a807iyq .
$ cat djq30a807iyq
The code is djq30a807iyq
Find the code and go to https://s3game-level11-djq30a807iyq.s3.us-east-2.amazonaws.com/level11.html
# Level 11 - 암호화
$ aws s3 ls s3://s3game-level11-djq30a807iyq
2020-05-02 19:11:55 2485 level11.html
2020-05-02 19:06:33 128 treasure11_encryption
$ aws s3 cp s3://s3game-level11-djq30a807iyq/treasure11_encryption .
fatal error: An error occurred (400) when calling the HeadObject operation: Bad Request
힌트에 있는 key를 활용하여 s3 객체를 다시 다운로드 받아 봅니다.
$ aws s3 cp s3://s3game-level11-djq30a807iyq/treasure11_encryption . --sse-c AES256 --sse-c-key 'UkXp2s5v8y/B?E(H+MbPeShVmYq3t6w9'
download: s3://s3game-level11-djq30a807iyq/treasure11_encryption to ./treasure11_encryption
$ cat ./treasure11_encryption
The code is bk0m5ax5n92o
Find the code and go to https://s3game-level12-bk0m5ax5n92o.s3.us-east-2.amazonaws.com/level12.html
마지막 링크로 들어가면 아래와 같은 페이지를 확인할 수 있습니다.
이상으로 1주차 스터디 내용을 마칩니다.
기존에는 IAM과 연관된 S3 버킷 정책만 주로 다뤘는데, 새로운 기능을 많이 사용해볼 수 있었습니다.
'Cloud & DevOps > AWS' 카테고리의 다른 글
Athena로 S3에 저장된 VPC flow logs 조회하기 (0) | 2024.02.03 |
---|---|
[2주차] IAM 취약점 및 보안 (1) | 2023.09.05 |
Route53 도메인 구입하기 (0) | 2023.04.21 |
[AWS] EKS Service Account -> IAM role assume을 위한 configuration 파일 설정 (0) | 2023.01.03 |
[AWS] S3에 대한 권한은 어떻게 얻을까? (0) | 2022.10.26 |