mirror of
https://github.com/mgeeky/Penetration-Testing-Tools.git
synced 2024-11-21 18:11:37 +01:00
Added identifyS3Bucket
This commit is contained in:
parent
3fdaea1342
commit
3257f13c0f
298
clouds/aws/identifyS3Bucket.rb
Normal file
298
clouds/aws/identifyS3Bucket.rb
Normal file
@ -0,0 +1,298 @@
|
||||
#!/usr/bin/ruby
|
||||
#
|
||||
# This script leverages couple of methods in order to validate that passed
|
||||
# domain is a S3 bucket indeed.
|
||||
#
|
||||
# Mariusz B., 2019, <mb@binary-offensive.com>
|
||||
#
|
||||
|
||||
require 'resolv'
|
||||
require 'uri'
|
||||
require 'net/http'
|
||||
|
||||
DEBUG = false
|
||||
|
||||
$cached_responses = {}
|
||||
$dns_records = {}
|
||||
$random_resource = (0...32).map { ('a'..'z').to_a[rand(26)] }.join
|
||||
|
||||
|
||||
class Resp
|
||||
attr_accessor :body
|
||||
attr_accessor :headers
|
||||
|
||||
def to_s
|
||||
return @body
|
||||
end
|
||||
|
||||
def to_str
|
||||
return @body
|
||||
end
|
||||
end
|
||||
|
||||
def dbg(x)
|
||||
if DEBUG
|
||||
puts "[dbg] #{x}"
|
||||
end
|
||||
end
|
||||
|
||||
def checkDnsRecords(bucket)
|
||||
begin
|
||||
Resolv::DNS.open do |dns|
|
||||
$dns_records['ip'] = dns.getaddress(bucket).to_s
|
||||
$dns_records['rev-dns'] = dns.getnames($dns_records['ip']).pop.to_s
|
||||
end
|
||||
rescue Resolv::ResolvError
|
||||
dbg "\tCould not resolve name #{bucket}."
|
||||
return false
|
||||
end
|
||||
|
||||
if $dns_records['rev-dns'].end_with? '.amazonaws.com' and $dns_records['rev-dns'].include? 's3'
|
||||
dbg "\tReverse-DNS record for IP (#{$dns_records['ip']}) points to AWS S3: #{$dns_records['rev-dns']}"
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def fetch(url)
|
||||
unless $cached_responses.key? url
|
||||
begin
|
||||
uri = URI.parse(url)
|
||||
response = Net::HTTP.get_response uri
|
||||
|
||||
resp = Resp.new
|
||||
resp.body = response.body
|
||||
resp.headers = response.each_header.to_h
|
||||
|
||||
$cached_responses[url] = resp
|
||||
|
||||
rescue Exception => e
|
||||
#puts "\tHTTP Request (#{url}) failed: #{e}"
|
||||
$cached_responses[url] = nil
|
||||
end
|
||||
end
|
||||
|
||||
return $cached_responses[url]
|
||||
end
|
||||
|
||||
def checkServerHeader(bucket)
|
||||
['http', 'https'].each do |scheme|
|
||||
out = fetch "#{scheme}://#{bucket}"
|
||||
if not out.nil? and out.headers.include? 'server' and out.headers['server'].downcase == 'amazons3'
|
||||
dbg "\tAmazon S3 bucket found by 'Server' HTTP response header contents."
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
['http', 'https'].each do |scheme|
|
||||
out = fetch "#{scheme}://#{bucket}.s3.amazonaws.com"
|
||||
if not out.nil? and out.headers.include? 'server' and out.headers['server'].downcase == 'amazons3'
|
||||
dbg "\tAmazon S3 bucket found by 'Server' HTTP response header contents."
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
['http', 'https'].each do |scheme|
|
||||
out = fetch "#{scheme}://s3.amazonaws.com/#{bucket}"
|
||||
if not out.nil? and out.headers.include? 'server' and out.headers['server'].downcase == 'amazons3'
|
||||
dbg "\tAmazon S3 bucket found by 'Server' HTTP response header contents."
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def checkAmzHeaders(bucket)
|
||||
out = fetch "http://#{bucket}.s3.amazonaws.com"
|
||||
if not out.nil? and out.headers.include? 'x-amz-request-id' and out.headers.include? 'x-amz-id-2'
|
||||
dbg "\tAmazon S3 found by 'x-amz-request-id' and 'x-amz-id-2' HTTP response headers existence."
|
||||
return true
|
||||
end
|
||||
|
||||
out = fetch "http://s3.amazonaws.com/#{bucket}"
|
||||
if not out.nil? and out.headers.include? 'x-amz-request-id' and out.headers.include? 'x-amz-id-2'
|
||||
dbg "\tAmazon S3 found by 'x-amz-request-id' and 'x-amz-id-2' HTTP response headers existence."
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def checkBucketRegionHeader(bucket)
|
||||
out = fetch "http://#{bucket}.s3.amazonaws.com"
|
||||
if not out.nil? and out.headers.include? 'x-amz-bucket-region'
|
||||
dbg "\tAmazon S3 bucket region found in 'x-amz-bucket-region' HTTP response header"
|
||||
return true
|
||||
end
|
||||
|
||||
out = fetch "http://s3.amazonaws.com/#{bucket}"
|
||||
if not out.nil? and out.headers.include? 'x-amz-bucket-region'
|
||||
dbg "\tAmazon S3 bucket region found in 'x-amz-bucket-region' HTTP response header"
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def checkBucketResponse(bucket)
|
||||
traces = [
|
||||
'ListBucketResult xmlns=',
|
||||
'</Contents></ListBucketResult>',
|
||||
'<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>',
|
||||
'<Error><Code>AllAccessDisabled</Code>',
|
||||
'<Error><Code>PermanentRedirect</Code><Message>',
|
||||
'</Endpoint><Bucket>',
|
||||
"<Name>#{bucket}</Name>",
|
||||
"<Bucket>#{bucket}</Bucket>"
|
||||
]
|
||||
|
||||
out = fetch "http://#{bucket}.s3.amazonaws.com"
|
||||
if not out.nil? and out.headers.include? 'content-type' and out.headers['content-type'].downcase == 'application/xml'
|
||||
traces.each do |trace|
|
||||
if out.body.include? trace
|
||||
dbg "\tAmazon S3 bucket identified by trace in body: '#{trace}'"
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
out = fetch "http://s3.amazonaws.com/#{bucket}"
|
||||
if not out.nil? and out.headers.include? 'content-type' and out.headers['content-type'].downcase == 'application/xml'
|
||||
traces.each do |trace|
|
||||
if out.body.include? trace
|
||||
dbg "\tAmazon S3 bucket identified by trace in body: '#{trace}'"
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def checkNonExistentResourceBucketResponse(bucket)
|
||||
traces = [
|
||||
'<li>Code: NoSuchKey</li>',
|
||||
'<Error><Code>NoSuchKey</Code><Message>',
|
||||
]
|
||||
|
||||
out = fetch "http://#{bucket}.s3.amazonaws.com/#{$random_resource}"
|
||||
unless out.nil?
|
||||
traces.each do |trace|
|
||||
if out.body.include? trace
|
||||
dbg "\tAmazon S3 bucket identified by trace in body of a non-existent resource: '#{trace}'"
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
out = fetch "http://s3.amazonaws.com/#{bucket}/#{$random_resource}"
|
||||
unless out.nil?
|
||||
traces.each do |trace|
|
||||
if out.body.include? trace
|
||||
dbg "\tAmazon S3 bucket identified by trace in body of a non-existent resource: '#{trace}'"
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
def checkIfBucketExists(bucket)
|
||||
traces = [
|
||||
'<Error><Code>NoSuchBucket</Code>',
|
||||
'<Message>The specified bucket does not exist</Message>',
|
||||
'<BucketName>flaws.cloudfsdsdfsdfdsf</BucketName>'
|
||||
]
|
||||
|
||||
found = 0
|
||||
|
||||
out = fetch "http://#{bucket}.s3.amazonaws.com"
|
||||
if not out.nil? and out.headers.include? 'content-type' and out.headers['content-type'].downcase == 'application/xml'
|
||||
traces.each do |trace|
|
||||
if out.body.include? trace
|
||||
found += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if found == traces.length
|
||||
dbg("Bucket verified to be non-existent.")
|
||||
return false
|
||||
end
|
||||
|
||||
out = fetch "http://s3.amazonaws.com/#{bucket}"
|
||||
if not out.nil? and out.headers.include? 'content-type' and out.headers['content-type'].downcase == 'application/xml'
|
||||
traces.each do |trace|
|
||||
if out.body.include? trace
|
||||
found += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if found == traces.length
|
||||
dbg("Bucket verified to be non-existent.")
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def main(args)
|
||||
|
||||
puts %{
|
||||
:: Identifies AWS S3 Buckets via couple of methods
|
||||
Mariusz B. 19', <mb@binary-offensive.com>
|
||||
}
|
||||
|
||||
if ARGV.length != 1
|
||||
puts "Usage: ./identifyS3Bucket.rb <name|domain>"
|
||||
exit
|
||||
end
|
||||
|
||||
points = 0
|
||||
|
||||
bucket = ARGV.pop
|
||||
puts "[.] Examining bucket with name: #{bucket}"
|
||||
|
||||
unless checkIfBucketExists bucket
|
||||
puts "[-] There is no such bucket."
|
||||
exit 1
|
||||
end
|
||||
|
||||
|
||||
if checkDnsRecords bucket
|
||||
puts "[+] S3 bucket identified via DNS records."
|
||||
points += 1
|
||||
end
|
||||
|
||||
if checkServerHeader bucket
|
||||
puts "[+] S3 Bucket identified by HTTP header 'Server' in response."
|
||||
points += 1
|
||||
end
|
||||
|
||||
if checkAmzHeaders bucket
|
||||
puts "[+] S3 Bucket identified by HTTP amz headers."
|
||||
points += 1
|
||||
end
|
||||
|
||||
if checkBucketResponse bucket
|
||||
puts "[+] S3 Bucket identified via traces in HTTP response body."
|
||||
points += 1
|
||||
end
|
||||
|
||||
if checkNonExistentResourceBucketResponse bucket
|
||||
puts "[+] S3 Bucket identified via traces in HTTP response of a non-existent resource."
|
||||
points += 1
|
||||
end
|
||||
|
||||
return 0 if points > 0
|
||||
return 1
|
||||
|
||||
end
|
||||
|
||||
if __FILE__ == $0
|
||||
main(ARGV)
|
||||
end
|
Loading…
Reference in New Issue
Block a user