metasploit-framework/lib/rex/proto/dcerpc/svcctl/packet.rb

308 lines
9.5 KiB
Ruby
Raw Normal View History

2014-04-02 20:21:45 +00:00
# -*- coding: binary -*-
module Rex
2014-04-02 20:21:45 +00:00
###
# This module implements MSRPC functions that control creating, deleting,
# starting, stopping, and querying system services.
###
module Proto::DCERPC::SVCCTL
2014-04-02 20:21:45 +00:00
require 'windows_error'
require 'windows_error/win32'
require 'msf/core/exploit/windows_constants'
2014-04-02 20:21:45 +00:00
NDR = Rex::Encoder::NDR
2014-04-05 17:38:12 +00:00
class Client
2014-04-02 20:21:45 +00:00
include WindowsError::Win32
include Msf::Exploit::Windows_Constants
2014-04-05 17:38:12 +00:00
attr_accessor :dcerpc_client
2014-04-05 17:38:12 +00:00
def initialize(dcerpc_client)
self.dcerpc_client = dcerpc_client
end
2014-04-05 17:38:12 +00:00
# Returns the Windows Error Code in numeric format
#
# @param raw_error [String] the raw error code in binary format.
#
# @return [Integer] the Windows Error Code integer.
def error_code(raw_error)
raw_error.unpack('V').first
end
2014-04-02 20:21:45 +00:00
# Calls OpenSCManagerW() to obtain a handle to the service control manager.
#
# @param rhost [String] the target host.
# @param access [Integer] the access flags requested.
2014-04-02 20:21:45 +00:00
#
2014-05-23 20:16:11 +00:00
# @return [Array<String,Integer>] the handle to the service control manager or nil if
2014-04-02 21:52:07 +00:00
# the call is not successful and the Windows error code
def openscmanagerw(rhost, access = SC_MANAGER_ALL_ACCESS)
2014-04-02 20:21:45 +00:00
scm_handle = nil
scm_status = nil
stubdata =
NDR.uwstring("\\\\#{rhost}") +
NDR.long(0) +
NDR.long(access)
2014-04-02 20:34:36 +00:00
begin
response = dcerpc_client.call(OPEN_SC_MANAGER_W, stubdata)
2014-04-02 20:34:36 +00:00
if response
2014-04-05 17:38:12 +00:00
scm_status = error_code(response[20,4])
2014-04-02 21:41:31 +00:00
if scm_status == ERROR_SUCCESS
2014-04-02 20:34:36 +00:00
scm_handle = response[0,20]
end
end
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error getting scm handle: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-05-23 20:16:11 +00:00
[scm_handle, scm_status]
2014-04-02 20:21:45 +00:00
end
# Calls CreateServiceW() to create a system service. Returns a handle to
# the service on success, or nil.
#
2014-05-23 19:47:52 +00:00
# @param scm_handle [String] the SCM handle (from {#openscmanagerw}).
2014-04-02 20:21:45 +00:00
# @param service_name [String] the service name.
# @param display_name [String] the display name.
# @param binary_path [String] the path of the binary to run.
2014-05-23 19:47:52 +00:00
# @param opts [Hash] arguments for CreateServiceW()
# @option opts [Integer] :access (SERVICE_ALL_ACCESS) the access level.
# @option opts [Integer] :type (SERVICE_WIN32_OWN_PROCESS ||
2014-05-23 19:47:52 +00:00
# SERVICE_INTERACTIVE_PROCESS) the type of service.
# @option opts [Integer] :start (SERVICE_DEMAND_START) the start options.
# @option opts [Integer] :errors (SERVICE_ERROR_IGNORE) the error options.
# @option opts [Integer] :load_order_group (0) the load order group.
# @option opts [Integer] :dependencies (0) the dependencies of the service.
# @option opts [Integer] :service_start (0)
# @option opts [Integer] :password1 (0)
# @option opts [Integer] :password2 (0)
# @option opts [Integer] :password3 (0)
# @option opts [Integer] :password4 (0)
2014-04-02 20:21:45 +00:00
#
2014-04-02 21:41:31 +00:00
# @return [String, Integer] a handle to the created service, windows
# error code.
def createservicew(scm_handle, service_name, display_name, binary_path, opts)
2014-04-02 20:21:45 +00:00
default_opts = {
2014-04-05 17:38:12 +00:00
:access => SERVICE_ALL_ACCESS,
:type => SERVICE_WIN32_OWN_PROCESS || SERVICE_INTERACTIVE_PROCESS,
:start => SERVICE_DEMAND_START,
:errors => SERVICE_ERROR_IGNORE,
2014-04-02 20:21:45 +00:00
:load_order_group => 0,
:dependencies => 0,
:service_start => 0,
:password1 => 0,
:password2 => 0,
:password3 => 0,
:password4 => 0
}.merge(opts)
svc_handle = nil
svc_status = nil
stubdata = scm_handle +
NDR.wstring(service_name) +
NDR.uwstring(display_name) +
NDR.long(default_opts[:access]) +
NDR.long(default_opts[:type]) +
NDR.long(default_opts[:start]) +
NDR.long(default_opts[:errors]) +
NDR.wstring(binary_path) +
NDR.long(default_opts[:load_order_group]) +
NDR.long(default_opts[:dependencies]) +
NDR.long(default_opts[:service_start]) +
NDR.long(default_opts[:password1]) +
NDR.long(default_opts[:password2]) +
NDR.long(default_opts[:password3]) +
NDR.long(default_opts[:password4])
2014-04-02 21:41:31 +00:00
begin
response = dcerpc_client.call(CREATE_SERVICE_W, stubdata)
2014-04-02 21:41:31 +00:00
if response
2014-04-05 17:38:12 +00:00
svc_status = error_code(response[24,4])
2014-04-02 20:21:45 +00:00
2014-04-02 21:41:31 +00:00
if svc_status == ERROR_SUCCESS
svc_handle = response[4,20]
end
end
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error creating service: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
return svc_handle, svc_status
2014-04-02 20:21:45 +00:00
end
2014-04-02 22:16:58 +00:00
# Calls ChangeServiceConfig2() to change the service description.
#
# @param svc_handle [String] the service handle to change.
# @param service_description [String] the service description.
#
# @return [Integer] Windows error code
def changeservicedescription(svc_handle, service_description)
2014-04-02 22:16:58 +00:00
svc_status = nil
stubdata =
svc_handle +
2014-04-05 17:38:12 +00:00
NDR.long(SERVICE_CONFIG_DESCRIPTION) +
2014-04-02 22:16:58 +00:00
NDR.long(1) + # lpInfo -> *SERVICE_DESCRIPTION
NDR.long(0x0200) + # SERVICE_DESCRIPTION struct
NDR.long(0x04000200) +
NDR.wstring(service_description)
begin
response = dcerpc_client.call(CHANGE_SERVICE_CONFIG2_W, stubdata) # ChangeServiceConfig2
2014-04-05 17:38:12 +00:00
svc_status = error_code(response)
2014-04-02 22:16:58 +00:00
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error changing service description : #{e}")
2014-04-02 22:16:58 +00:00
end
svc_status
end
2014-04-02 21:41:31 +00:00
# Calls CloseHandle() to close a handle.
2014-04-02 20:21:45 +00:00
#
# @param handle [String] the handle to close.
#
2014-04-02 21:41:31 +00:00
# @return [Integer] Windows error code
def closehandle(handle)
2014-04-02 21:41:31 +00:00
svc_status = nil
begin
response = dcerpc_client.call(CLOSE_SERVICE_HANDLE, handle)
2014-04-02 21:41:31 +00:00
if response
2014-04-05 17:38:12 +00:00
svc_status = error_code(response[20,4])
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error closing service handle: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
svc_status
2014-04-02 20:21:45 +00:00
end
# Calls OpenServiceW to obtain a handle to an existing service.
#
2014-05-23 19:47:52 +00:00
# @param scm_handle [String] the SCM handle (from {#openscmanagerw}).
2014-04-02 20:21:45 +00:00
# @param service_name [String] the name of the service to open.
# @param access [Integer] the level of access requested (default is maximum).
2014-04-02 20:21:45 +00:00
#
# @return [String, nil] the handle of the service opened, or nil on failure.
def openservicew(scm_handle, service_name, access = SERVICE_ALL_ACCESS)
2014-04-02 20:21:45 +00:00
svc_handle = nil
svc_status = nil
stubdata = scm_handle + NDR.wstring(service_name) + NDR.long(access)
2014-04-02 21:41:31 +00:00
begin
response = dcerpc_client.call(OPEN_SERVICE_W, stubdata)
2014-04-02 21:41:31 +00:00
if response
2014-04-05 17:38:12 +00:00
svc_status = error_code(response[20,4])
2014-04-02 21:41:31 +00:00
if svc_status == ERROR_SUCCESS
svc_handle = response[0,20]
end
end
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error opening service handle: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
svc_handle
2014-04-02 20:21:45 +00:00
end
# Calls StartService() on a handle to an existing service in order to start
# it. Returns true on success, or false.
#
2014-05-23 19:47:52 +00:00
# @param svc_handle [String] the handle of the service (from {#openservicew}).
# @param magic1 [Integer] an unknown value.
# @param magic2 [Integer] another unknown value.
2014-04-02 20:21:45 +00:00
#
2014-04-02 21:41:31 +00:00
# @return [Integer] Windows error code
def startservice(svc_handle, magic1 = 0, magic2 = 0)
2014-04-02 21:41:31 +00:00
svc_status = nil
2014-04-02 20:21:45 +00:00
stubdata = svc_handle + NDR.long(magic1) + NDR.long(magic2)
2014-04-02 21:41:31 +00:00
begin
response = dcerpc_client.call(0x13, stubdata)
2014-04-02 21:41:31 +00:00
if response
2014-04-05 17:38:12 +00:00
svc_status = error_code(response)
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error starting service: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
svc_status
2014-04-02 20:21:45 +00:00
end
# Stops a running service.
#
2014-05-23 19:47:52 +00:00
# @param svc_handle [String] the handle of the service (from {#openservicew}).
2014-04-02 20:21:45 +00:00
#
2014-04-02 21:41:31 +00:00
# @return [Integer] Windows error code
def stopservice(svc_handle)
dce_controlservice(svc_handle, SERVICE_CONTROL_STOP)
2014-04-02 20:21:45 +00:00
end
# Controls an existing service.
#
2014-05-23 19:47:52 +00:00
# @param svc_handle [String] the handle of the service (from {#openservicew}).
# @param operation [Integer] the operation number to perform (1 = stop
2014-04-02 20:21:45 +00:00
# service; others are unknown).
#
2014-04-02 21:41:31 +00:00
# @return [Integer] Windows error code
def controlservice(svc_handle, operation)
2014-04-02 21:41:31 +00:00
svc_status = nil
begin
response = dcerpc_client.call(CONTROL_SERVICE, svc_handle + NDR.long(operation))
2014-04-02 21:41:31 +00:00
if response
2014-04-05 17:38:12 +00:00
svc_status = error_code(response[28,4])
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error controlling service: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
svc_status
2014-04-02 20:21:45 +00:00
end
# Calls DeleteService() to delete a service.
#
2014-05-23 19:47:52 +00:00
# @param svc_handle [String] the handle of the service (from {#openservicew}).
2014-04-02 20:21:45 +00:00
#
2014-04-02 21:41:31 +00:00
# @return [Integer] Windows error code
def deleteservice(svc_handle)
2014-04-02 21:41:31 +00:00
svc_status = nil
begin
response = dcerpc_client.call(DELETE_SERVICE, svc_handle)
2014-04-02 21:41:31 +00:00
if response
2014-04-05 17:38:12 +00:00
svc_status = error_code(response)
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error deleting service: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
svc_status
2014-04-02 20:21:45 +00:00
end
# Calls QueryServiceStatus() to query the status of a service.
#
2014-05-23 19:47:52 +00:00
# @param svc_handle [String] the handle of the service (from {#openservicew}).
2014-04-02 20:21:45 +00:00
#
# @return [Integer] Returns 0 if the query failed (i.e.: a state was returned
2014-04-02 20:21:45 +00:00
# that isn't implemented), 1 if the service is running, and
# 2 if the service is stopped.
def queryservice(svc_handle)
2014-04-02 20:21:45 +00:00
ret = 0
2014-04-02 21:41:31 +00:00
begin
response = dcerpc_client.call(QUERY_SERVICE_STATUS, svc_handle)
2014-04-02 21:41:31 +00:00
if response[0,9] == "\x10\x00\x00\x00\x04\x00\x00\x00\x01"
ret = 1
elsif response[0,9] == "\x10\x00\x00\x00\x01\x00\x00\x00\x00"
ret = 2
end
rescue Rex::Proto::DCERPC::Exceptions::Fault => e
2016-01-28 19:58:24 +00:00
print_error("Error deleting service: #{e}")
2014-04-02 20:21:45 +00:00
end
2014-04-02 21:41:31 +00:00
ret
2014-04-02 20:21:45 +00:00
end
end
end
end
2014-04-02 21:41:31 +00:00