Cloud & DevOps/AWS

[1주차] S3 취약점 및 보안

백곰곰 2023. 8. 27. 23:13
728x90
반응형

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 문구가 있는 정책 수정 필요
  • Organization SCP
    • 조직 레벨의 권한 제어
  • VPC Endpoint Policy
    • S3 vpc endpoint에 특정 버킷만 접근 가능하게 설정

위 정책들을 종합적으로 고려하여 최종 Allow/Deny를 결정합니다.

이때 Allow/Deny의 우선 순위는 아래와 같습니다.

  1. 명시적 Deny 확인
  2. 명시적 Allow 확인
  3. 최종 Deny (묵시적 Deny)

명시적 Deny가 가장 우선이며 명시적 Allow 정책이 없다면 S3에 대해 접근 권한을 얻을 수 없습니다.


S3 보안 기능

s3에는 추가적으로 보안을 강화할 수 있는 기능이 있습니다.

  • pre-signed url
    • 일정 시간 특정 객체에 접근할 수 있는 url 제공
  • SSE (ServerSideEncryption)
    • SSE-S3
      • 객체 업로드 시 자동 적용 
      • AES256
    • SSE-KMS

실습

이제 여러가지 보안 실습을 진행해보겠습니다.

 

 

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 버킷 정책만 주로 다뤘는데, 새로운 기능을 많이 사용해볼 수 있었습니다.

728x90