## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'aws-sdk-s3' class MetasploitModule < Msf::Auxiliary def initialize(info = {}) super( update_info( info, 'Name' => 'Amazon Web Services S3 instance enumeration', 'Description' => %q( Provided AWS credentials, this module will call the authenticated API of Amazon Web Services to list all S3 buckets associated with the account ), 'Author' => ['Aaron Soto '], 'License' => MSF_LICENSE ) ) register_options( [ OptString.new('REGION', [false, 'AWS Region (eg. "us-west-2")']), OptString.new('ACCESS_KEY_ID', [true, 'AWS Access Key ID (eg. "AKIAXXXXXXXXXXXXXXXX")', '']), OptString.new('SECRET_ACCESS_KEY', [true, 'AWS Secret Access Key (eg. "CA1+XXXXXXXXXXXXXXXXXXXXXX6aYDHHCBuLuV79")', '']) ] ) end def handle_aws_errors(e) if e.class.module_parents.include?(Aws) fail_with(Failure::UnexpectedReply, e.message) else raise e end end def describe_s3_bucket(i) print_good " Name: #{i.name}" print_good " Creation Date: #{i.creation_date}" print_good " # of Objects: #{@s3.list_objects_v2(bucket: i.name).contents.length}" print_good " Region: #{@s3.get_bucket_location(bucket: i.name).location_constraint}" begin print_good " Website: /#{@s3.get_bucket_website(bucket: i.name).index_document.suffix}" rescue Aws::S3::Errors::NoSuchWebsiteConfiguration print_good " Website: (None)" end acl = @s3.get_bucket_acl(bucket: i.name) print_good " Owner: #{acl.owner.display_name}" print_good " Permissions:" acl.grants.each do |i| grantee = i.grantee.type == "CanonicalUser" ? "User" : i.grantee.type grantee << " '#{i.grantee.display_name}'" grantee << " (#{i.grantee.email_address})" unless i.grantee.email_address.nil? grantee << " (#{i.grantee.uri})" unless i.grantee.uri.nil? print_good " #{grantee} granted #{i.permission}" end print_status '' end def run region = datastore['REGION'] @s3 = Aws::S3::Client.new( region: "us-west-2", # This doesn't actually filter anything, but # it's still required. Thanks AWS. :-( access_key_id: datastore['ACCESS_KEY_ID'], secret_access_key: datastore['SECRET_ACCESS_KEY'] ) buckets = @s3.list_buckets.buckets unless buckets.length > 0 print_status 'No buckets found.' return end print_good "Found #{buckets.count} buckets." if region.nil? buckets.each do |i| describe_s3_bucket(i) end else print_good "Listing buckets that match REGION '#{datastore['REGION']}':" buckets.each do |i| if @s3.get_bucket_location(bucket: i.name).location_constraint.starts_with? region describe_s3_bucket(i) end end end print_status 'Done.' rescue ::Exception => e handle_aws_errors(e) end end