2 điểm bởi GN⁺ 2024-02-27 | 1 bình luận | Chia sẻ qua WhatsApp
  • Tracebit tổng hợp kỹ thuật suy đoán AWS Account ID của bucket S3 công khai và riêng tư, và khôi phục 123456789101 từ bucket ví dụ bucket-alpha
  • Manh mối cốt lõi là điều kiện s3:ResourceAccount trong policy của Interface VPC Endpoint cho S3 và việc request có xuất hiện trong log CloudTrail của chính mình hay không
  • Với bucket riêng tư, dù phản hồi cuối cùng vẫn luôn là AccessDenied, vẫn có thể xác định xem mẫu chữ số có khớp hay không vì chỉ những request vượt qua policy của VPC Endpoint mới xuất hiện trong CloudTrail
  • Do độ trễ lan truyền policy và độ trễ của CloudTrail, cách dò đơn giản có thể mất khoảng 40 * 12 phút = 8 giờ, nhưng có thể giảm xuống dưới 10 phút bằng cách kiểm tra song song 120 câu lệnh policy sử dụng aws:useridRoleSessionName
  • Kỹ thuật này khả thi vì StringLike cho phép khớp một phần với s3:ResourceAccount, và một số hoạt động cũng có thể xuất hiện trong CloudTrail của chủ sở hữu bucket

Mở rộng từ kỹ thuật dành cho bucket công khai

  • Năm 2021, Ben Bridts đã công bố cách tìm AWS Account ID của một bucket S3 công khai
  • Cách làm của Tracebit tái sử dụng nhiều thành phần của ý tưởng này, nhưng tập trung vào việc tìm Account ID của bucket S3, bao gồm cả bucket riêng tư
  • Trong ví dụ thực thi, với bucket-alpha, họ thu thập các tên phiên đã vượt qua trong CloudTrail và cuối cùng khôi phục được 123456789101

Vì sao cách cũ cho bucket công khai hoạt động

  • Phương pháp của Ben Bridts hoạt động khi hội đủ ba điều kiện
    • Có thể áp dụng IAM policy cho request
    • Có thể suy ra policy đã cho phép hay chặn request
    • Có thể áp dụng khớp wildcard cho khóa điều kiện s3:ResourceAccount
  • Với bucket công khai, nếu policy chặn request thì sẽ nhận AccessDenied, còn nếu policy cho phép thì request thành công, nên rất dễ phân biệt request có vượt qua policy hay không
  • Khi thu hẹp s3:ResourceAccount từng chữ số một, toàn bộ không gian tìm kiếm giảm từ hàng nghìn tỷ khả năng xuống chỉ còn vài trăm

Với bucket riêng tư, nhìn vào CloudTrail thay vì phản hồi

  • Với bucket riêng tư, dù áp dụng policy nào thì phản hồi cuối cùng vẫn là AccessDenied do bucket policy của đích từ chối
  • Cách làm của Tracebit không dựa vào kết quả phản hồi mà dựa vào việc request có xuất hiện trong log CloudTrail của chính mình hay không
    • Nếu request xuất hiện trong CloudTrail, nghĩa là VPC Endpoint policy đã cho phép, sau đó mới bị bucket policy từ chối
    • Nếu request không có trong CloudTrail, nghĩa là nó đã bị chặn ở VPC Endpoint policy
  • Khi tạo Interface VPC Endpoint cho S3, có thể áp dụng VPC Endpoint policy cho request, và policy này sẽ được đánh giá cùng với các policy khác như bucket policy và IAM policy của chủ thể gửi request
  • Trong VPC Endpoint policy cũng có thể dùng wildcard StringLike và các khóa điều kiện tài nguyên, nên có thể áp dụng cùng kiểu dò tìm như trên

Quy trình cơ bản: từ xác định region đến truy vấn sự kiện

  • Trước tiên phải tìm region của bucket đích
    • Gửi curl tới HTTP endpoint của bucket, ngay cả khi request bị cấm thì header x-amz-bucket-region vẫn được trả về
    • Trong ví dụ, họ xác nhận us-east-1 từ header phản hồi của bucket-alpha.s3.amazonaws.com
  • Triển khai VPC và VPC Endpoint cho S3 trong cùng region với bucket đích
    • VPC Endpoint phải là loại Interface thì mới áp dụng được policy
    • Vì VPC Endpoint này sẽ ảnh hưởng đến các request S3 trong VPC, tốt nhất nên tạo một VPC riêng chỉ phục vụ mục đích này
  • Chạy một EC2 instance trong VPC để gửi request S3, và xác nhận instance đó đang sử dụng VPC Endpoint cho S3
  • Chỉnh sửa VPC Endpoint policy để kiểm tra xem s3:ResourceAccount có bắt đầu bằng một chữ số cụ thể hay không
    • Ví dụ, để kiểm tra Account ID có bắt đầu bằng 0 hay không, đặt điều kiện "0*" cho s3:ResourceAccount
  • Từ EC2 instance, gửi một request quản trị như GetBucketAcl tới bucket đích
    • Dùng request quản trị sẽ bớt cần xử lý riêng trong cấu hình CloudTrail
    • Kết quả request đúng như dự đoán vẫn là AccessDenied

Cách phân biệt mẫu chữ số bằng CloudTrail

  • Sau request, truy vấn CloudTrail xem có xuất hiện sự kiện GetBucketAcl hay không
  • Nếu sự kiện xuất hiện, nghĩa là VPC Endpoint policy đã cho phép request, nên Account ID khớp với mẫu đang kiểm tra
    • Ví dụ: nếu có sự kiện khi dùng điều kiện "0*", thì Account ID bắt đầu bằng 0
  • Nếu sự kiện không xuất hiện, nghĩa là request đã bị chặn ở VPC Endpoint policy, nên không khớp mẫu đó
  • Vì có thể mất vài phút để sự kiện xuất hiện trong CloudTrail, nên họ khuyến nghị chờ 10 phút trước khi kết luận là không có sự kiện
  • Việc thay đổi VPC Endpoint policy cũng cần thời gian để lan truyền và có hiệu lực hoàn toàn; chờ 5 phút sau khi sửa policy cho kết quả tốt

Đã tự động hóa nhưng cách cơ bản vẫn chậm

  • Tracebit đã viết script tự động hóa quy trình này để có thể tìm Account ID của bucket một cách ổn định
  • Thay vì kiểm tra mọi chữ số theo cách tuần tự từng vị trí, họ giảm số lần thử bằng cách dùng cách tiếp cận gần với tìm kiếm nhị phân ở mỗi vị trí
    • Ví dụ, đưa nhiều mẫu vào điều kiện s3:ResourceAccount như ["0*", "1*", "2*", "3*", "4*"] để chia nhỏ phạm vi
  • Dù vậy, thời gian chờ policy được áp dụng và thời gian chờ xác nhận trong CloudTrail vẫn là nút thắt
    • Ngay cả khi dùng tìm kiếm nhị phân, vẫn có thể mất khoảng 40 * 12 phút = 8 giờ
  • Trong ví dụ chạy suốt nhiều giờ, họ đã tìm thành công Account ID của bucket-alpha123456789101

Rút xuống dưới 10 phút bằng 120 câu lệnh policy

  • Cách nhanh hơn là điền trước vào VPC Endpoint policy tất cả các tổ hợp vị trí và chữ số có thể có
  • Policy này chứa tổng cộng 120 câu lệnh
    • Kiểm tra 10 chữ số có thể có cho từng vị trí trong AWS Account ID
    • Mỗi câu lệnh kết hợp mẫu theo vị trí cụ thể của s3:ResourceAccount với điều kiện aws:userid
  • Điều kiện aws:userid được dùng để khớp với giá trị RoleSessionName có thể chỉ định tự do trong lệnh gọi STS AssumeRole
    • Khi assume role với một RoleSessionName cụ thể, có thể chọn để chỉ cho phép câu lệnh policy tương ứng với phép thử cho một vị trí và chữ số nhất định đi qua
  • Policy này vừa khít giới hạn độ dài ký tự tối đa của VPC Endpoint policy
  • Vì kiểm tra song song toàn bộ 120 khả năng, không còn cần sửa policy liên tục hay chờ riêng kết quả CloudTrail cho từng trường hợp
  • Nhờ đó, thời gian dò Account ID giảm xuống dưới 10 phút

Phạm vi lộ diện và khả năng mở rộng

  • Một phần hoạt động có thể xuất hiện trong log CloudTrail của chủ sở hữu bucket đích
  • Tracebit đã trao đổi với đội ngũ AWS Security trước khi công bố
  • Việc AWS Account ID có phải thông tin nhạy cảm hay không vốn đã được bàn luận nhiều, và trong sự kiện CloudTrail ví dụ, Account ID của bên thứ ba được che bằng HIDDEN_DUE_TO_SECURITY_REASONS
  • Cùng kỹ thuật này cũng có thể áp dụng cho các khóa điều kiện tài nguyên khác liên quan đến bucket
    • Ví dụ: aws:ResourceOrgID
    • Ví dụ: aws:ResourceOrgPaths
    • Ví dụ: aws:ResourceTag
  • Kỹ thuật này cũng có thể được áp dụng sang các dịch vụ khác ngoài S3 nếu có điều kiện tương tự
  • Nếu tạo VPC và VPC Endpoint được peering lẫn nhau trên mọi region, có thể xây dựng một cấu hình hoạt động bất kể bucket đích nằm ở region nào
  • Kỹ thuật này khả thi vì có thể dùng khớp một phần bằng StringLike với điều kiện s3:ResourceAccount
  • Sẽ hữu ích nếu cả những sự kiện bị VPC Endpoint policy từ chối cũng được ghi vào CloudTrail

1 bình luận

 
GN⁺ 2024-02-27
Ý kiến trên Hacker News
  • Việc có thể áp dụng khớp ký tự đại diện cho khóa điều kiện s3:ResourceAccount thật sự kỳ lạ
    Có vẻ không có lý do chính đáng nào để cho phép hoặc từ chối quyền dựa trên việc khớp một phần ID tài khoản

    • Có lẽ là vì trong thực thi chính sách AWS có nhiều toán tử và toán hạng, và trong trường hợp này cấu trúc là dùng StringLike cho chuỗi ID tài khoản
      Khá thú vị khi thấy phía DevOps giờ cũng bắt đầu phát hiện các tấn công kênh kề. Các kênh kề từ thực thi suy đoán của CPU như Meltdown, Spectre khi được phát hiện cũng đã gây chấn động lớn; trước đó còn có các lĩnh vực như phân tích điện năng, phát hiện biến dạng từ và mật mã học thời gian hằng
      https://en.m.wikipedia.org/wiki/Side-channel_attack
      https://en.m.wikipedia.org/wiki/Power_analysis
    • Tôi cũng ngạc nhiên ở điểm đó. Trường này có lẽ không nên cho phép gì ngoài khớp chính xác, và tôi không nghĩ ra trường hợp nào cần dùng khớp mẫu cho ID tài khoản
    • Có lẽ xuất phát từ xu hướng tổng quát hóa
      Trong một dự án phụ gần đây, tôi đã làm chức năng viết truy vấn theo dạng lấy cảm hứng từ OWL, có một thư viện toán tử quan hệ để trích host từ URL, truy vấn tiền tố, truy vấn like, truy vấn biểu thức chính quy, v.v.
      Vì đó là dự án phụ của một dự án phụ khác của tôi nên tôi làm theo cách dễ nhất, và để các toán tử luôn có thể dùng được ngay cả khi trường hợp đó không hợp lý. Tôi cũng không biết và không quan tâm nếu truy vấn biểu thức chính quy trên số thì sẽ ra sao. Có thể nội bộ AWS cũng có thứ tương tự, nhưng với một hệ thống có nhiều người dùng và nhạy cảm về bảo mật thì tiêu chuẩn phải khác
    • Nó giống như khớp bitfield của group ID trên hệ thống Unix
      Ai đó có thể nghĩ ra ý tưởng này và thấy mình thông minh, nhưng triển khai nó trong một hệ thống mà bạn không kiểm soát 100% thì có vẻ là điều ngớ ngẩn
  • Thông thường sẽ không công khai rải ID tài khoản, nhưng nên giả định rằng một phần nào đó rồi cũng sẽ bị lộ vào một lúc nào đó
    Ngày càng nhiều nhà cung cấp bên thứ ba và nền tảng SaaS đang chuyển sang các kiểu tích hợp ưu tiên ủy quyền vai trò thay vì IAM user và access key, và đúng là nên như vậy. Khi đó, ít nhất ID tài khoản của tài khoản dùng làm điểm tích hợp sẽ được bên khác biết, mà phía đó cũng có phụ thuộc, lỗ hổng, v.v.

    • Tôi thắc mắc điều này. Kẻ tấn công có thể làm gì với AWS account ID? Nó khác gì so với việc biết địa chỉ email của ai đó?
  • AWS account ID giống như địa chỉ IP. Nó có thể nhạy cảm, nhưng để làm việc thì phải có ai đó biết
    Ví dụ 1–2 năm trước, vì quy trình chống rửa tiền, chúng tôi phải tích hợp với một bên thứ ba. Tôi đề xuất thiết lập PrivateLink với tổ chức đó vì thường an toàn hơn cổng SFTP công khai, nhưng công ty bên kia từ chối vì lý do bảo mật rằng họ phải giấu account ID. Dù account ID là thứ cần thiết trong role ARN của PV endpoint để cấp quyền qua lại
    Cuối cùng chúng tôi đưa dải IP công khai mà họ dùng cho cổng inbound 22 vào danh sách cho phép
    Bài học là bạn có thể nghĩ mình thông minh khi làm rối ID, nhưng nếu bên kia không biết địa chỉ để liên lạc lại thì rất khó vận hành kinh doanh

    • AWS PrivateLink còn có một đặc tính nữa khiến nó nhìn chung không lý tưởng cho kiểu tích hợp này. Giao tiếp là hai chiều, và các subnet IP không được chồng lấn
      Từ phía nhà cung cấp, chúng tôi thường tích hợp bằng VPC Endpoint Service. Cách này giao tiếp một chiều, và dịch vụ của chúng tôi được phơi ra dưới dạng endpoint load balancer trong VPC của khách hàng
  • Với những ai quan tâm, tôi đã đưa mã lên đây: https://github.com/tracebit-com/find-s3-account

  • Đúng là một phát hiện thú vị, nhưng nhìn tiêu đề thì tôi tưởng sẽ có một cách trực tiếp hơn
    Sẽ rất hay nếu trong AWS, với tài khoản quản trị, ta có thể đơn giản hỏi trong tổ chức rằng “tài nguyên X nằm ở đâu” và nhanh chóng biết một S3 bucket cụ thể nằm trong tài khoản nào. Các tài nguyên khác cũng vậy, nhưng S3 bucket là vấn đề đặc biệt lớn
    Nói thật thì đây chủ yếu là vấn đề với các bucket legacy có từ trước khi có thực hành tốt hơn, hoặc những thứ tồn tại từ trước khi toàn bộ bucket được định nghĩa bằng code. Dù vậy, nếu có nhiều AWS account, việc tìm tài nguyên nằm trong tài khoản và region không rõ có thể rất tẻ nhạt

    • Nếu thiết lập AWS Config aggregator cho tổ chức, bạn có thể truy vấn kho tài nguyên của tất cả tài khoản trong tổ chức bằng Athena SQL
      Khi đó, việc tìm tài khoản nào sở hữu tài nguyên đại khái có thể làm bằng select accountId where arn = "x"
  • Các tài nguyên AWS công khai khác có namespace toàn cục cũng làm lộ AWS account ID
    https://blog.plerion.com/conditional-love-for-aws-metadata-e...

  • Liên quan một chút, Cloudflare account_id và zone_id có công khai cũng an toàn
    https://github.com/cloudflare/cloudflare-docs/issues/474
    https://community.cloudflare.com/t/api-zone-id/355566

    The Zone ID and Account ID are not sensitive. Sensitive data like account API Key, Secrets etc. can all be revoked, rotated or changed. See the comment 36 below on the Wrangler repo: as per our security team, it’s completely Fine to have your zone_id and account_id public, the Global API key and associated email address should be kept secret.

    • AWS account ID cũng có công khai cũng an toàn
      Tuy nhiên, một trong những điều có thể làm với nó là xác định mối tương quan. Nếu vận hành nhiều site S3 trên cùng một tài khoản AWS, người ta có thể thấy chúng được host từ cùng một tài khoản. Việc này có quan trọng hay không tùy thuộc vào threat model
    • Với tài khoản CF, dùng tính năng + của Gmail để tạo một địa chỉ email hoàn toàn duy nhất, không dễ đoán
      Không hoàn hảo, nhưng nó thêm một lớp trừu tượng nữa
  • Liên quan, AWS key ID dù không phải phần secret key cũng chứa account ID bên trong ở dạng bị dịch một bit
    https://medium.com/@TalBeerySec/a-short-note-on-aws-key-id-f...
    Key ID này được đưa vào URL được ký sẵn của S3, nên nhiều khả năng bạn vốn đã công khai account ID rồi

    • Có vẻ khá nhiều người trong thread này giả định AWS key ID là một phần của bảo mật nhờ che giấu hoặc defense in depth
      Có lẽ sẽ bị downvote, nhưng nếu vẫn đọc thì đây là một ví dụ cho thấy vì sao bảo mật nhờ che giấu không phải là biện pháp phòng thủ tốt. Bản thân mình sẽ bỏ sót thứ gì đó, còn kẻ tấn công kiên trì thì sẽ không bỏ sót
      Bảo mật không dựa vào che giấu vẫn có hiệu lực bất kể tôi có hiểu điều gì đó hay không, trừ khi kẻ tấn công thuê được một thiên tài có thể phá AES-256 chẳng hạn: https://www.youtube.com/watch?v=KEkrWRHCDQU
  • Vì sao chuyện này có thể quan trọng? Một ví dụ rõ ràng là, nếu có một bucket production, giờ bạn có thể tìm được các bucket development của cùng tổ chức. Cá nhân tôi thì đây không phải hành vi tôi dự đoán trước

    • Điều này chỉ đúng khi dùng cùng một account cho production và development. Đây là thêm một lý do nữa để không dùng chung account
    • Để làm vậy thì chỉ cần biết tên bucket
      Muốn ngăn kiểu thử liệt kê này, nên thêm tiền tố hoặc hậu tố được tạo ngẫu nhiên vào tên bucket. Ngoài ra, không phải để thay thế mà như biện pháp bổ sung, cũng nên công khai object trong bucket dưới một tên không phải hostname mặc định để bản thân tên bucket không bị lộ
    • Sao lại thành ra được như vậy? Trước hết chẳng phải phải biết tên của bucket development sao?
    • Khả năng thấp, trừ khi bằng cách nào đó bucket development nằm trong cùng account
  • While account IDs, like any identifying information, should be used and shared carefully, they are not considered secret, sensitive, or confidential information.
    https://docs.aws.amazon.com/accounts/latest/reference/manage...

    • Ít nhất trong thế giới số, thông tin có vẻ chỉ rơi vào một trong hai loại: công khai hoặc riêng tư. Khái niệm về thông tin cần được cấp quyền hoặc thông tin được bảo vệ không tốt lắm
      Ví dụ địa chỉ nhà về mặt kỹ thuật là thông tin công khai, nhưng tôi tuyệt đối không muốn nó xuất hiện trên một billboard cạnh đường cao tốc kèm ảnh gia đình với dòng chữ đây là nơi tôi sống. Tôi chỉ đưa cho người cần biết, và tin cũng như kỳ vọng rằng nhìn chung nó sẽ được giữ gần như bí mật hoặc có giới hạn mục đích sử dụng
    • Điều này nghĩa là gì?
      Nếu không phải bí mật, không nhạy cảm, cũng không phải thông tin mật, thì vì sao phải chia sẻ cẩn thận?
    • Có lẽ câu “không được xem là thông tin bí mật, nhạy cảm hoặc mật” nên viết thêm là “theo tiêu chuẩn của chúng tôi
      Người dùng có thể nhìn nhận khác