Files
metasploit-gs/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb
T
Brent Cook c250740a81 Fixup finalizers to not double-close Meterpreter objects
We add finalizers to an assortment of Meterpreter-managed objects in order to
clean things up in the event that a post module crashes and does not clean
things up. However, this also means that even a properly-written post module
can lead to an object getting double-closed on the Meterpreter session when the
garbage collector kicks in. This can lead to quite non-deterministic behavior
and crashes.

This change modifies the instance close methods to unregister the finalizer on
close, ensuring we cannot do a double-close automatically if one is requested
explicitly first. As an additional measure, we check an instance variable to
see if we called close directly twice as well. This is not sufficient in
itself, since we do not have a reference to 'self' in the finalizer proc to
check the close state.

This also removes a couple of references to 'self' in the finalizer proc
itself, which may cure some memory leaks as well due to circular references.
2016-03-02 21:43:51 -06:00

199 lines
4.4 KiB
Ruby

# -*- coding: binary -*-
require 'rex/post/process'
require 'rex/post/meterpreter/packet'
require 'rex/post/meterpreter/client'
require 'rex/post/meterpreter/extensions/stdapi/constants'
require 'rex/post/meterpreter/extensions/stdapi/stdapi'
require 'rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record'
module Rex
module Post
module Meterpreter
module Extensions
module Stdapi
module Sys
###
#
# This class provides access to the Windows event log on the remote
# machine.
#
###
class EventLog
class << self
attr_accessor :client
end
#
# Opens the supplied event log.
#
#--
# NOTE: should support UNCServerName sometime
#++
#
def EventLog.open(name)
request = Packet.create_request('stdapi_sys_eventlog_open')
request.add_tlv(TLV_TYPE_EVENT_SOURCENAME, name);
response = client.send_request(request)
return self.new(response.get_tlv_value(TLV_TYPE_EVENT_HANDLE))
end
##
#
# Event Log Instance Stuffs!
#
##
attr_accessor :handle # :nodoc:
attr_accessor :client # :nodoc:
public
#
# Initializes an instance of the eventlog manipulator.
#
def initialize(hand)
self.client = self.class.client
self.handle = hand
# Ensure the remote object is closed when all references are removed
ObjectSpace.define_finalizer(self, self.class.finalize(client, hand))
end
def self.finalize(client,handle)
proc { self.close(client,handle) }
end
#
# Return the number of records in the event log.
#
def length
request = Packet.create_request('stdapi_sys_eventlog_numrecords')
request.add_tlv(TLV_TYPE_EVENT_HANDLE, self.handle);
response = client.send_request(request)
return response.get_tlv_value(TLV_TYPE_EVENT_NUMRECORDS)
end
#
# the low level read function (takes flags, not hash, etc).
#
def _read(flags, offset = 0)
request = Packet.create_request('stdapi_sys_eventlog_read')
request.add_tlv(TLV_TYPE_EVENT_HANDLE, self.handle)
request.add_tlv(TLV_TYPE_EVENT_READFLAGS, flags)
request.add_tlv(TLV_TYPE_EVENT_RECORDOFFSET, offset)
response = client.send_request(request)
EventLogSubsystem::EventRecord.new(
response.get_tlv_value(TLV_TYPE_EVENT_RECORDNUMBER),
response.get_tlv_value(TLV_TYPE_EVENT_TIMEGENERATED),
response.get_tlv_value(TLV_TYPE_EVENT_TIMEWRITTEN),
response.get_tlv_value(TLV_TYPE_EVENT_ID),
response.get_tlv_value(TLV_TYPE_EVENT_TYPE),
response.get_tlv_value(TLV_TYPE_EVENT_CATEGORY),
response.get_tlv_values(TLV_TYPE_EVENT_STRING),
response.get_tlv_value(TLV_TYPE_EVENT_DATA)
)
end
#
# Read the eventlog forwards, meaning from oldest to newest.
# Returns a EventRecord, and throws an exception after no more records.
#
def read_forwards
_read(EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ)
end
#
# Iterator for read_forwards.
#
def each_forwards
begin
loop do
yield(read_forwards)
end
rescue ::Exception
end
end
#
# Read the eventlog backwards, meaning from newest to oldest.
# Returns a EventRecord, and throws an exception after no more records.
#
def read_backwards
_read(EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ)
end
#
# Iterator for read_backwards.
#
def each_backwards
begin
loop do
yield(read_backwards)
end
rescue ::Exception
end
end
#
# Return the record number of the oldest event (not necessarily 1).
#
def oldest
request = Packet.create_request('stdapi_sys_eventlog_oldest')
request.add_tlv(TLV_TYPE_EVENT_HANDLE, self.handle);
response = client.send_request(request)
return response.get_tlv_value(TLV_TYPE_EVENT_RECORDNUMBER)
end
#
# Clear the specified event log (and return nil).
#
#--
# I should eventually support BackupFile
#++
#
def clear
request = Packet.create_request('stdapi_sys_eventlog_clear')
request.add_tlv(TLV_TYPE_EVENT_HANDLE, self.handle);
response = client.send_request(request)
return self
end
#
# Close the event log
#
def self.close(client, handle)
request = Packet.create_request('stdapi_sys_eventlog_close')
request.add_tlv(TLV_TYPE_EVENT_HANDLE, handle);
response = client.send_request(request, nil)
return nil
end
# Instance method
def close
unless self.handle.nil?
ObjectSpace.undefine_finalizer(self)
self.class.close(self.client, self.handle)
self.handle = nil
end
end
end
end end end end end end