Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb
Views: 11794
# -*- coding: binary -*-1# Copyright (c) 2010, [email protected]2# All rights reserved.3#4# Redistribution and use in source and binary forms, with or without5# modification, are permitted provided that the following conditions are met:6# * Redistributions of source code must retain the above copyright7# notice, this list of conditions and the following disclaimer.8# * Redistributions in binary form must reproduce the above copyright9# notice, this list of conditions and the following disclaimer in the10# documentation and/or other materials provided with the distribution.11# * The names of the author may not be used to endorse or promote products12# derived from this software without specific prior written permission.13#14# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND15# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED16# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE17# DISCLAIMED. IN NO EVENT SHALL [email protected] BE LIABLE FOR ANY18# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES19# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;20# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND21# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT22# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS23# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2425#26# sf - Sept 2010 - Modified for x64 support and merged into the stdapi extension.27#2829#30# chao - June 2011 - major overhaul of dll lazy loading, caching, and bit of everything31#3233#34# zeroSteiner - April 2017 - added support for non-windows platforms35#3637require 'pp'38require 'enumerator'3940require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv'41require 'rex/post/meterpreter/extensions/stdapi/railgun/util'42require 'rex/post/meterpreter/extensions/stdapi/railgun/const_manager'43require 'rex/post/meterpreter/extensions/stdapi/railgun/multicall'44require 'rex/post/meterpreter/extensions/stdapi/railgun/library'45require 'rex/post/meterpreter/extensions/stdapi/railgun/library_wrapper'4647module Rex48module Post49module Meterpreter50module Extensions51module Stdapi52module Railgun535455#56# The Railgun class to dynamically expose the Windows API.57#58class Railgun5960#61# Railgun::Library's that have builtin definitions.62#63# If you want to add additional library definitions to be preloaded create a64# definition class 'rex/post/meterpreter/extensions/stdapi/railgun/def/$platform/'.65# Naming is important and should follow convention. For example, if your66# library's name was "my_library"67# file name: def_my_library.rb68# class name: Def_my_library69# entry below: 'my_library'70#71BUILTIN_LIBRARIES = {72'linux' => [73'libc'74].freeze,75'osx' => [76'libc',77'libobjc'78].freeze,79'windows' => [80'kernel32',81'ntdll',82'user32',83'ws2_32',84'iphlpapi',85'advapi32',86'shell32',87'netapi32',88'crypt32',89'wlanapi',90'wldap32',91'version',92'psapi',93'dbghelp',94'winspool',95'spoolss',96'secur32'97].freeze98}.freeze99100##101# Returns a Hash containing libraries added to this instance with #add_library102# as well as references to any frozen cached libraries added directly in103# #get_library and copies of any frozen libraries (added directly with104# #add_function) that the user attempted to modify with #add_function.105#106# Keys are friendly library names and values are the corresponding library instance107attr_accessor :libraries108109##110# Contains a reference to the client that corresponds to this instance of railgun111attr_accessor :client112113##114# These libraries are loaded lazily and then shared amongst all railgun115# instances. For safety reasons this variable should only be read/written116# within #get_library.117@@cached_libraries = {}118119# if you are going to touch @@cached_libraries, wear protection120@@cache_semaphore = Mutex.new121122def initialize(client)123self.client = client124self.libraries = {}125end126127def self.builtin_libraries128BUILTIN_LIBRARIES[client.platform]129end130131#132# Return this Railgun's Util instance.133#134def util135if @util.nil?136@util = Util.new(self, client.native_arch)137end138139return @util140end141142#143# Return this Railgun's platform specific ApiConstants class.144#145def api_constants146if @api_constants.nil?147require "rex/post/meterpreter/extensions/stdapi/railgun/def/#{client.platform}/api_constants"148@api_constants = Def.const_get('DefApiConstants_' << client.platform)149end150151return @api_constants152end153154#155# Return this Railgun's ConstManager instance, initially populated with156# constants defined in ApiConstants.157#158def constant_manager159# Loads lazily160return api_constants.manager161end162163#164# Read data from a memory address on the host (useful for working with165# LPVOID parameters)166#167def memread(address, length)168169raise "Invalid parameters." if(not address or not length)170171request = Packet.create_request(COMMAND_ID_STDAPI_RAILGUN_MEMREAD)172173request.add_tlv(TLV_TYPE_RAILGUN_MEM_ADDRESS, address)174request.add_tlv(TLV_TYPE_RAILGUN_MEM_LENGTH, length)175176response = client.send_request(request)177if(response.result == 0)178return response.get_tlv_value(TLV_TYPE_RAILGUN_MEM_DATA)179end180181return nil182end183184#185# Write data to a memory address on the host (useful for working with186# LPVOID parameters)187#188def memwrite(address, data, length=nil)189data = data.to_binary_s if data.is_a?(BinData::Struct)190length = data.length if length.nil?191raise "Invalid parameters." if(not address or not data or not length)192193request = Packet.create_request(COMMAND_ID_STDAPI_RAILGUN_MEMWRITE)194request.add_tlv(TLV_TYPE_RAILGUN_MEM_ADDRESS, address)195request.add_tlv(TLV_TYPE_RAILGUN_MEM_DATA, data)196request.add_tlv(TLV_TYPE_RAILGUN_MEM_LENGTH, length)197198response = client.send_request(request)199return response.result == 0200end201202#203# Adds a function to an existing library definition.204#205# If the library definition is frozen (ideally this should be the case for all206# cached libraries) an unfrozen copy is created and used henceforth for this207# instance.208#209def add_function(lib_name, function_name, return_type, params, remote_name=nil, calling_conv='stdcall')210unless known_library_names.include?(lib_name)211raise "Library #{lib_name} not found. Known libraries: #{PP.pp(known_library_names, '')}"212end213214lib = get_library(lib_name)215216# For backwards compatibility, we ensure the library is thawed217if lib.frozen?218# Duplicate not only the library, but its functions as well, frozen status will be lost219lib = Marshal.load(Marshal.dump(lib))220221# Update local libraries with the modifiable duplicate222libraries[lib_name] = lib223end224225lib.add_function(function_name, return_type, params, remote_name, calling_conv)226end227228#229# Adds a library to this Railgun.230#231# The +remote_name+ is the name used on the remote system and should be232# set appropriately if you want to include a path or the library name contains233# non-ruby-approved characters.234#235# Raises an exception if a library with the given name has already been236# defined.237#238def add_library(lib_name, remote_name=lib_name)239if libraries.has_key? lib_name240raise "A library of name #{lib_name} has already been loaded."241end242243libraries[lib_name] = Library.new(remote_name, constant_manager)244end245alias_method :add_dll, :add_library246247def known_library_names248return BUILTIN_LIBRARIES[client.platform] | libraries.keys249end250251#252# Attempts to provide a library instance of the given name. Handles lazy253# loading and caching. Note that if a library of the given name does not exist254# then nil is returned.255#256def get_library(lib_name)257# If the library is not local, we now either load it from cache or load it258# lazily. In either case, a reference to the library is stored in the259# collection "libraries". If the library can not be found/created, no260# actions are taken.261unless libraries.has_key? lib_name262# use a platform-specific name for caching to avoid conflicts with263# libraries that exist on multiple platforms, e.g. libc.264cached_lib_name = "#{client.platform}.#{lib_name}"265# We read and write to @@cached_libraries and rely on state consistency266@@cache_semaphore.synchronize do267if @@cached_libraries.has_key? cached_lib_name268libraries[lib_name] = @@cached_libraries[cached_lib_name]269elsif BUILTIN_LIBRARIES[client.platform].include? lib_name270# I highly doubt this case will ever occur, but I am paranoid271if lib_name !~ /^\w+$/272raise "Library name #{lib_name} is bad. Correct Railgun::BUILTIN_LIBRARIES['#{client.platform}']"273end274275require "rex/post/meterpreter/extensions/stdapi/railgun/def/#{client.platform}/def_#{lib_name}"276lib = Def.const_get("Def_#{client.platform}_#{lib_name}").create_library(constant_manager).freeze277278@@cached_libraries[cached_lib_name] = lib279libraries[lib_name] = lib280end281end282283end284285return libraries[lib_name]286end287alias_method :get_dll, :get_library288289#290# Fake having members like user32 and kernel32.291# reason is that292# ...user32.MessageBoxW()293# is prettier than294# ...libraries["user32"].functions["MessageBoxW"]()295#296def method_missing(lib_symbol, *args)297lib_name = lib_symbol.to_s298299unless known_library_names.include? lib_name300raise "Library #{lib_name} not found. Known libraries: #{PP.pp(known_library_names, '')}"301end302303lib = get_library(lib_name)304305return LibraryWrapper.new(lib, client)306end307308#309# Return a constant matching +str+.310#311def const(str)312return constant_manager.parse(str)313end314315#316# The multi-call shorthand (["kernel32", "ExitProcess", [0]])317#318def multi(functions)319if @multicaller.nil?320@multicaller = MultiCaller.new(client, self, constant_manager)321end322323return @multicaller.call(functions)324end325end326327end; end; end; end; end; end328329330