Land #5394, UUID registration and tracking

bug/bundler_fix
Brent Cook 2015-05-29 16:33:36 -05:00
commit c241018ff6
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
12 changed files with 210 additions and 23 deletions

View File

@ -589,8 +589,11 @@ class ReadableText
sess_via = session.via_exploit.to_s
sess_type = session.type.to_s
sess_uuid = session.payload_uuid.to_s
sess_puid = session.payload_uuid.respond_to?(:puid_hex) ? session.payload_uuid.puid_hex : nil
sess_checkin = "<none>"
sess_machine_id = session.machine_id.to_s
sess_registration = "No"
if session.respond_to? :platform
sess_type << (" " + session.platform)
@ -600,6 +603,13 @@ class ReadableText
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s ago @ #{session.last_checkin.to_s}"
end
if session.payload_uuid.respond_to?(:puid_hex) && (uuid_info = framework.uuid_db[sess_puid])
sess_registration = "Yes"
if uuid_info['name']
sess_registration << " - Name=\"#{uuid_info['name']}\""
end
end
out << " Session ID: #{sess_id}\n"
out << " Type: #{sess_type}\n"
out << " Info: #{sess_info}\n"
@ -608,6 +618,10 @@ class ReadableText
out << " UUID: #{sess_uuid}\n"
out << " MachineID: #{sess_machine_id}\n"
out << " CheckIn: #{sess_checkin}\n"
out << " Registered: #{sess_registration}\n"
out << "\n"
end

View File

@ -73,7 +73,7 @@ class Framework
require 'msf/core/plugin_manager'
require 'msf/core/db_manager'
require 'msf/core/event_dispatcher'
require 'rex/json_hash_file'
#
# Creates an instance of the framework context.
@ -91,6 +91,7 @@ class Framework
self.datastore = DataStore.new
self.jobs = Rex::JobContainer.new
self.plugins = PluginManager.new(self)
self.uuid_db = Rex::JSONHashFile.new(::File.join(Msf::Config.config_directory, "payloads.json"))
# Configure the thread factory
Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: self)
@ -187,6 +188,12 @@ class Framework
# unloading of plugins.
#
attr_reader :plugins
#
# The framework instance's payload uuid database. The payload uuid
# database is used to record and match the unique ID values embedded
# into generated payloads.
#
attr_reader :uuid_db
# The framework instance's db manager. The db manager
# maintains the database db and handles db events
@ -243,6 +250,7 @@ protected
attr_writer :jobs # :nodoc:
attr_writer :plugins # :nodoc:
attr_writer :db # :nodoc:
attr_writer :uuid_db # :nodoc:
end
class FrameworkEventSubscriber

View File

@ -56,7 +56,8 @@ module ReverseHttp
OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']),
OptInt.new('ReverseListenerBindPort', [ false, 'The port to bind to on the local system if different from LPORT' ]),
OptBool.new('OverrideRequestHost', [ false, 'Forces clients to connect to LHOST:LPORT instead of keeping original payload host', false ]),
OptString.new('HttpUnknownRequestResponse', [ false, 'The returned HTML response body when the handler receives a request that is not from a payload', '<html><body><h1>It works!</h1></body></html>' ])
OptString.new('HttpUnknownRequestResponse', [ false, 'The returned HTML response body when the handler receives a request that is not from a payload', '<html><body><h1>It works!</h1></body></html>' ]),
OptBool.new('IgnoreUnknownPayloads', [false, 'Whether to drop connections from payloads using unknown UUIDs', false])
], Msf::Handler::ReverseHttp)
end
@ -153,6 +154,10 @@ module ReverseHttp
print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}")
lookup_proxy_settings
if datastore['IgnoreUnknownPayloads']
print_status("Handler is ignoring unknown payloads, there are #{framework.uuid_db.keys.length} UUIDs whitelisted")
end
end
#
@ -228,6 +233,21 @@ protected
conn_id = generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
end
# Validate known UUIDs for all requests if IgnoreUnknownPayloads is set
if datastore['IgnoreUnknownPayloads'] && ! framework.uuid_db[uuid.puid_hex]
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Ignoring request with unknown UUID")
info[:mode] = :unknown_uuid
end
# Validate known URLs for all session init requests if IgnoreUnknownPayloads is set
if datastore['IgnoreUnknownPayloads'] && info[:mode].to_s =~ /^init_/
allowed_urls = framework.uuid_db[uuid.puid_hex]['urls'] || []
unless allowed_urls.include?(req.relative_resource)
print_status("#{cli.peerhost}:#{cli.peerport} (UUID: #{uuid.to_s}) Ignoring request with unknown UUID URL #{req.relative_resource}")
info[:mode] = :unknown_uuid_url
end
end
self.pending_connections += 1
# Process the requested resource.
@ -374,7 +394,9 @@ protected
})
else
print_status("#{cli.peerhost}:#{cli.peerport} Unknown request to #{req.relative_resource} #{req.inspect}...")
unless [:unknown_uuid, :unknown_uuid_url].include?(info[:mode])
print_status("#{cli.peerhost}:#{cli.peerport} Unknown request to #{req.relative_resource} with UA #{req.headers['User-Agent']}...")
end
resp.code = 200
resp.message = "OK"
resp.body = datastore['HttpUnknownRequestResponse'].to_s

View File

@ -3,7 +3,7 @@
require 'msf/core'
require 'msf/core/payload/php/send_uuid'
require 'msf/core/payload/uuid_options'
require 'msf/core/payload/uuid/options'
module Msf
@ -16,7 +16,7 @@ module Msf
module Payload::Php::ReverseTcp
include Msf::Payload::Php::SendUUID
include Msf::Payload::UUIDOptions
include Msf::Payload::UUID::Options
#
# Generate the first stage

View File

@ -1,6 +1,6 @@
# -*- coding: binary -*-
require 'msf/core/payload/uuid_options'
require 'msf/core/payload/uuid/options'
##
# This module contains helper functions for creating the transport
@ -8,7 +8,7 @@ require 'msf/core/payload/uuid_options'
##
module Msf::Payload::TransportConfig
include Msf::Payload::UUIDOptions
include Msf::Payload::UUID::Options
def transport_config_reverse_tcp(opts={})
config = transport_config_bind_tcp(opts)

View File

@ -7,7 +7,7 @@ require 'rex/payloads/meterpreter/uri_checksum'
#
# This module provides datastore option definitions and helper methods for payload modules that support UUIDs
#
module Msf::Payload::UUIDOptions
module Msf::Payload::UUID::Options
include Rex::Payloads::Meterpreter::UriChecksum
@ -17,6 +17,8 @@ module Msf::Payload::UUIDOptions
[
Msf::OptString.new('PayloadUUIDSeed', [ false, 'A string to use when generating the payload UUID (deterministic)']),
Msf::OptString.new('PayloadUUIDRaw', [ false, 'A hex string representing the raw 8-byte PUID value for the UUID']),
Msf::OptString.new('PayloadUUIDName', [ false, 'A human-friendly name to reference this unique payload (requires tracking)']),
Msf::OptBool.new('PayloadUUIDTracking', [ true, 'Whether or not to automatically register generated UUIDs', false]),
], self.class)
end
@ -31,7 +33,7 @@ module Msf::Payload::UUIDOptions
def generate_uri_uuid_mode(mode,len=nil)
sum = uri_checksum_lookup(mode)
# The URI length may not have room for an embedded checksum
# The URI length may not have room for an embedded UUID
if len && len < URI_CHECKSUM_UUID_MIN_LEN
# Throw an error if the user set a seed, but there is no room for it
if datastore['PayloadUUIDSeed'].to_s.length > 0 ||datastore['PayloadUUIDRaw'].to_s.length > 0
@ -40,7 +42,11 @@ module Msf::Payload::UUIDOptions
return "/" + generate_uri_checksum(sum, len, prefix="")
end
generate_uri_uuid(sum, generate_payload_uuid, len)
uuid = generate_payload_uuid
uri = generate_uri_uuid(sum, uuid, len)
record_payload_uuid_url(uuid, uri)
uri
end
# Generate a Payload UUID
@ -66,7 +72,48 @@ module Msf::Payload::UUIDOptions
conf[:puid] = puid_raw
end
Msf::Payload::UUID.new(conf)
if datastore['PayloadUUIDName'].to_s.length > 0 && ! datastore['PayloadUUIDTracking']
raise ArgumentError, "The PayloadUUIDName value is ignored unless PayloadUUIDTracking is enabled"
end
# Generate the UUID object
uuid = Msf::Payload::UUID.new(conf)
record_payload_uuid(uuid)
uuid
end
# Store a UUID in the JSON database if tracking is enabled
def record_payload_uuid(uuid, info={})
return unless datastore['PayloadUUIDTracking']
uuid_info = info.merge({
arch: uuid.arch,
platform: uuid.platform,
timestamp: uuid.timestamp,
payload: self.fullname,
datastore: self.datastore
})
if datastore['PayloadUUIDSeed'].to_s.length > 0
uuid_info[:seed] = datastore['PayloadUUIDSeed']
end
if datastore['PayloadUUIDName'].to_s.length > 0
uuid_info[:name] = datastore['PayloadUUIDName']
end
framework.uuid_db[uuid.puid_hex] = uuid_info
end
# Store a UUID URL in the JSON database if tracking is enabled
def record_payload_uuid_url(uuid, url)
return unless datastore['PayloadUUIDTracking']
uuid_info = framework.uuid_db[uuid.puid_hex]
uuid_info['urls'] ||= []
uuid_info['urls'] << url
uuid_info['urls'].uniq!
framework.uuid_db[uuid.puid_hex] = uuid_info
end
end

View File

@ -4,7 +4,7 @@ require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/windows/block_api'
require 'msf/core/payload/windows/exitfunk'
require 'msf/core/payload/uuid_options'
require 'msf/core/payload/uuid/options'
module Msf
@ -20,7 +20,7 @@ module Payload::Windows::ReverseHttp
include Msf::Payload::Windows
include Msf::Payload::Windows::BlockApi
include Msf::Payload::Windows::Exitfunk
include Msf::Payload::UUIDOptions
include Msf::Payload::UUID::Options
#
# Register reverse_http specific options

View File

@ -4,7 +4,7 @@ require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/windows/x64/block_api'
require 'msf/core/payload/windows/x64/exitfunk'
require 'msf/core/payload/uuid_options'
require 'msf/core/payload/uuid/options'
module Msf
@ -20,7 +20,7 @@ module Payload::Windows::ReverseHttp_x64
include Msf::Payload::Windows
include Msf::Payload::Windows::BlockApi_x64
include Msf::Payload::Windows::Exitfunk_x64
include Msf::Payload::UUIDOptions
include Msf::Payload::UUID::Options
#
# Register reverse_http specific options

96
lib/rex/json_hash_file.rb Normal file
View File

@ -0,0 +1,96 @@
# -*- coding => binary -*-
require 'json'
require 'fileutils'
#
# This class provides a thread-friendly hash file store in JSON format
#
module Rex
class JSONHashFile
attr_accessor :path
def initialize(path)
self.path = path
@lock = Mutex.new
@hash = {}
@last = 0
::FileUtils.mkdir_p(::File.dirname(path))
synced_update
end
def [](k)
synced_update
@hash[k]
end
def []=(k,v)
synced_update do
@hash[k] = v
end
end
def keys
synced_update
@hash.keys
end
def delete(k)
synced_update do
@hash.delete(k)
end
end
def clear
synced_update do
@hash.clear
end
end
private
# Save the file, but prevent thread & process contention
def synced_update(&block)
@lock.synchronize do
::File.open(path, ::File::RDWR|::File::CREAT) do |fd|
fd.flock(::File::LOCK_EX)
# Reload and merge if the file has changed recently
if fd.stat.mtime.to_f > @last
parse_data(fd.read).merge(@hash).each_pair do |k,v|
@hash[k] = v
end
end
res = nil
# Update the file on disk if new data is written
if block_given?
res = block.call
fd.rewind
fd.write(JSON.pretty_generate(@hash))
fd.sync
fd.truncate(fd.pos)
end
@last = fd.stat.mtime.to_f
res
end
end
end
def parse_data(data)
return {} if data.to_s.strip.length == 0
begin
JSON.parse(data)
rescue JSON::ParserError => e
# elog("JSONHashFile @ #{path} was corrupt: #{e.class} #{e}"
{}
end
end
end
end

View File

@ -5,7 +5,7 @@
require 'msf/core'
require 'msf/core/handler/reverse_https'
require 'msf/core/payload/uuid_options'
require 'msf/core/payload/uuid/options'
module Metasploit3
@ -13,7 +13,7 @@ module Metasploit3
include Msf::Payload::Stager
include Msf::Payload::Java
include Msf::Payload::UUIDOptions
include Msf::Payload::UUID::Options
def initialize(info = {})
super(merge_info(info,

View File

@ -5,14 +5,14 @@
require 'msf/core'
require 'msf/core/handler/reverse_https'
require 'msf/core/payload/uuid_options'
require 'msf/core/payload/uuid/options'
module Metasploit3
CachedSize = 742
include Msf::Payload::Stager
include Msf::Payload::UUIDOptions
include Msf::Payload::UUID::Options
def initialize(info = {})
super(merge_info(info,

View File

@ -5,7 +5,7 @@
require 'msf/core'
require 'msf/core/handler/reverse_http'
require 'msf/core/payload/uuid_options'
require 'msf/core/payload/uuid/options'
module Metasploit3
@ -13,7 +13,7 @@ module Metasploit3
include Msf::Payload::Stager
include Msf::Payload::Windows
include Msf::Payload::UUIDOptions
include Msf::Payload::UUID::Options
def self.handler_type_alias
"reverse_http_proxy_pstore"