c250740a81
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.
199 lines
4.4 KiB
Ruby
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
|