Files
metasploit-gs/lib/msf/core/post/windows/services.rb
T
Tab Assassin 7e5e0f7fc8 Retab lib
2013-08-30 16:28:33 -05:00

314 lines
9.6 KiB
Ruby

# -*- coding: binary -*-
require 'msf/core/post/windows/registry'
module Msf
class Post
module Windows
# @deprecated Use {Services} instead
module WindowsServices
def self.included(base)
include Services
end
def setup
print_error("The Windows::WindowsServices mixin is deprecated, use Windows::Services instead")
super
end
end
#
# Post module mixin for dealing with Windows services
#
module Services
include ::Msf::Post::Windows::Registry
#
# Open the service manager with advapi32.dll!OpenSCManagerA on the
# given host or the local machine if :host option is nil. If called
# with a block, yields the manager and closes it when the block
# returns.
#
# @param opts [Hash]
# @option opts [String] :host (nil) The host on which to open the
# service manager. May be a hostname or IP address.
# @option opts [Fixnum] :access (0xF003F) Bitwise-or of the
# SC_MANAGER_* constants (see
# {http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx})
#
# @return [Fixnum] Opaque Windows handle SC_HANDLE as returned by
# OpenSCManagerA()
# @yield [manager] Gives the block a manager handle as returned by
# advapi32.dll!OpenSCManagerA. When the block returns, the handle
# will be closed with {#close_sc_manager}.
# @raise [RuntimeError] if OpenSCManagerA returns a NULL handle
#
def open_sc_manager(opts={})
host = opts[:host] || nil
access = opts[:access] || 0xF003F
machine_str = host ? "\\\\#{host}" : nil
# SC_HANDLE WINAPI OpenSCManager(
# _In_opt_ LPCTSTR lpMachineName,
# _In_opt_ LPCTSTR lpDatabaseName,
# _In_ DWORD dwDesiredAccess
# );
manag = session.railgun.advapi32.OpenSCManagerA(machine_str,nil,access)
if (manag["return"] == 0)
raise RuntimeError.new("Unable to open service manager, GetLastError: #{manag["GetLastError"]}")
end
if (block_given?)
begin
yield manag["return"]
ensure
close_sc_manager(manag["return"])
end
else
return manag["return"]
end
end
#
# Call advapi32.dll!CloseServiceHandle on the given handle
#
def close_sc_manager(handle)
if handle
session.railgun.advapi32.CloseServiceHandle(handle)
end
end
#
# List all Windows Services present
#
# @return [Array] The names of the services.
#
# @todo Rewrite to allow operating on a remote host
#
def service_list
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
a =[]
services = []
keys = registry_enumkeys(serviceskey)
keys.each do |s|
if a.length >= 10
a.first.join
a.delete_if {|x| not x.alive?}
end
t = framework.threads.spawn(self.refname+"-ServiceRegistryList",false,s) { |sk|
begin
srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type").to_s
if srvtype == "32" or srvtype == "16"
services << sk
end
rescue
end
}
a.push(t)
end
return services
end
#
# Get Windows Service information.
#
# Information returned in a hash with display name, startup mode and
# command executed by the service. Service name is case sensitive. Hash
# keys are Name, Start, Command and Credentials.
#
# @param name [String] The target service's name (not to be confused
# with Display Name). Case sensitive.
#
# @return [Hash]
#
# @todo Rewrite to allow operating on a remote host
#
def service_info(name)
service = {}
servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}"
service["Name"] = registry_getvaldata(servicekey,"DisplayName").to_s
srvstart = registry_getvaldata(servicekey,"Start").to_i
if srvstart == 2
service["Startup"] = "Auto"
elsif srvstart == 3
service["Startup"] = "Manual"
elsif srvstart == 4
service["Startup"] = "Disabled"
end
service["Command"] = registry_getvaldata(servicekey,"ImagePath").to_s
service["Credentials"] = registry_getvaldata(servicekey,"ObjectName").to_s
return service
end
#
# Changes a given service startup mode, name must be provided and the mode.
#
# Mode is a string with either auto, manual or disable for the
# corresponding setting. The name of the service is case sensitive.
#
# @todo Rewrite to allow operating on a remote host
#
def service_change_startup(name,mode)
servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}"
case mode.downcase
when "auto" then
registry_setvaldata(servicekey,"Start","2","REG_DWORD")
when "manual" then
registry_setvaldata(servicekey,"Start","3","REG_DWORD")
when "disable" then
registry_setvaldata(servicekey,"Start","4","REG_DWORD")
end
end
#
# Create a service that runs +executable_on_host+ on the session host
#
# @param name [String] Name of the service to be used as the key
# @param display_name [String] Name of the service as displayed by mmc
# @param executable_on_host [String] EXE on the remote filesystem to
# be used as the service executable
# @param startup [Fixnum] Constant used by CreateServiceA for startup
# type: 2 for Auto, 3 for Manual, 4 for Disable. Default is Auto
# @param server [String,nil] A hostname or IP address. Default is the
# remote localhost
#
# @return [true,false] True if there were no errors, false otherwise
#
def service_create(name, display_name, executable_on_host, startup=2, server=nil)
adv = session.railgun.advapi32
# SC_MANAGER_CONNECT 0x01
# SC_MANAGER_CREATE_SERVICE 0x02
# SC_MANAGER_QUERY_LOCK_STATUS 0x10
open_sc_manager(:host=>server, :access=>0x13) do |manager|
# SC_HANDLE WINAPI CreateService(
# __in SC_HANDLE hSCManager,
# __in LPCTSTR lpServiceName,
# __in_opt LPCTSTR lpDisplayName,
# __in DWORD dwDesiredAccess,
# __in DWORD dwServiceType,
# __in DWORD dwStartType,
# __in DWORD dwErrorControl,
# __in_opt LPCTSTR lpBinaryPathName,
# __in_opt LPCTSTR lpLoadOrderGroup,
# __out_opt LPDWORD lpdwTagId,
# __in_opt LPCTSTR lpDependencies,
# __in_opt LPCTSTR lpServiceStartName,
# __in_opt LPCTSTR lpPassword
#);
newservice = adv.CreateServiceA(manager, name, display_name,
0x0010, 0X00000010, startup, 0, executable_on_host,
nil, nil, nil, nil, nil)
adv.CloseServiceHandle(newservice["return"])
if newservice["GetLastError"] == 0
return true
else
return false
end
end
end
#
# Start a service.
#
# @param name [String] Service name (not display name)
# @param server [String,nil] A hostname or IP address. Default is the
# remote localhost
#
# @return [Fixnum] 0 if service started successfully, 1 if it failed
# because the service is already running, 2 if it is disabled
#
# @raise [RuntimeError] if OpenServiceA failed
#
def service_start(name, server=nil)
adv = session.railgun.advapi32
open_sc_manager(:host=>server, :access=>1) do |manager|
# SC_HANDLE WINAPI OpenService(
# _In_ SC_HANDLE hSCManager,
# _In_ LPCTSTR lpServiceName,
# _In_ DWORD dwDesiredAccess
# );
# open with access SERVICE_START (0x0010)
handle = adv.OpenServiceA(manager, name, 0x10)
if(handle["return"] == 0)
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
end
retval = adv.StartServiceA(handle["return"],0,nil)
adv.CloseServiceHandle(handle["return"])
# This is terrible. Magic return values should be refactored to
# something meaningful.
case retval["GetLastError"]
when 0; return 0 # everything worked
when 1056; return 1 # service already started
when 1058; return 2 # service disabled
end
end
end
#
# Stop a service.
#
# @param (see #service_start)
# @return [Fixnum] 0 if service stopped successfully, 1 if it failed
# because the service is already stopped or disabled, 2 if it
# cannot be stopped for some other reason.
#
# @raise (see #service_start)
#
def service_stop(name, server=nil)
adv = session.railgun.advapi32
# SC_MANAGER_SERVICE_STOP (0x0020)
open_sc_manager(:host=>server, :access=>1) do |manager|
# open with SERVICE_STOP (0x0020)
handle = adv.OpenServiceA(manager, name, 0x20)
if(handle["return"] == 0)
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
end
retval = adv.ControlService(handle["return"],1,56)
adv.CloseServiceHandle(handle["return"])
case retval["GetLastError"]
when 0; return 0 # worked
when 1062; return 1 # already stopped or disabled
when 1052; return 2 # cannot be stopped
end
end
end
#
# Delete a service.
#
# @param (see #service_start)
#
def service_delete(name, server=nil)
adv = session.railgun.advapi32
open_sc_manager(:host=>server) do |manager|
# Now to grab a handle to the service.
# Thank you, Wine project for defining the DELETE constant since it,
# and all its friends, are missing from the MSDN docs.
# #define DELETE 0x00010000
handle = adv.OpenServiceA(manager, name, 0x10000)
if (handle["return"] == 0)
raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}")
end
# Lastly, delete it
adv.DeleteService(handle["return"])
adv.CloseServiceHandle(handle["return"])
handle["GetLastError"]
end
end
end
end
end
end