Skip to content

Commit f55d78c

Browse files
committed
Pull in @jtesta's DCERPC Services work
1 parent 410b1c6 commit f55d78c

File tree

2 files changed

+247
-0
lines changed

2 files changed

+247
-0
lines changed

lib/msf/core/exploit/dcerpc.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require 'msf/core/exploit/dcerpc_epm'
55
require 'msf/core/exploit/dcerpc_mgmt'
66
require 'msf/core/exploit/dcerpc_lsa'
7+
require 'msf/core/exploit/dcerpc_services'
78

89
module Msf
910

@@ -32,6 +33,7 @@ module Exploit::Remote::DCERPC
3233
include Exploit::Remote::DCERPC_EPM
3334
include Exploit::Remote::DCERPC_MGMT
3435
include Exploit::Remote::DCERPC_LSA
36+
include Exploit::Remote::DCERPC_SERVICES
3537

3638
def initialize(info = {})
3739
super
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# -*- coding: binary -*-
2+
module Msf
3+
4+
###
5+
# This module implements MSRPC functions that control creating, deleting,
6+
# starting, stopping, and querying system services.
7+
###
8+
module Exploit::Remote::DCERPC_SERVICES
9+
10+
NDR = Rex::Encoder::NDR
11+
12+
13+
# Calls OpenSCManagerW() to obtain a handle to the service control manager.
14+
#
15+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
16+
# @param rhost [String] the target host.
17+
# @param access [Fixnum] the access flags requested.
18+
#
19+
# @return [String] the handle to the service control manager.
20+
def dce_openscmanagerw(dcerpc, rhost, access = 0xF003F)
21+
scm_handle = nil
22+
scm_status = nil
23+
stubdata =
24+
NDR.uwstring("\\\\#{rhost}") +
25+
NDR.long(0) +
26+
NDR.long(access)
27+
response = dcerpc.call(0x0f, stubdata)
28+
if dcerpc.last_response and dcerpc.last_response.stub_data
29+
scm_handle = dcerpc.last_response.stub_data[0,20]
30+
scm_status = dcerpc.last_response.stub_data[20,4]
31+
end
32+
33+
if scm_status.to_i != 0
34+
scm_handle = nil
35+
end
36+
return scm_handle
37+
end
38+
39+
40+
# Calls CreateServiceW() to create a system service. Returns a handle to
41+
# the service on success, or nil.
42+
#
43+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
44+
# @param scm_handle [String] the SCM handle (from dce_openscmanagerw()).
45+
# @param service_name [String] the service name.
46+
# @param display_name [String] the display name.
47+
# @param binary_path [String] the path of the binary to run.
48+
# @param opts [Hash] a hash containing the following keys and values:
49+
# access [Fixnum] the access level (default is maximum).
50+
# type [Fixnum] the type of service (default is interactive,
51+
# own process).
52+
# start [Fixnum] the start options (default is on demand).
53+
# errors [Fixnum] the error options (default is ignore).
54+
# load_order_group [Fixnum] the load order group.
55+
# dependencies [Fixnum] the dependencies of the service.
56+
# service_start [Fixnum]
57+
# password1 [Fixnum]
58+
# password2 [Fixnum]
59+
# password3 [Fixnum]
60+
# password4 [Fixnum]
61+
#
62+
# @return [String] a handle to the created service.
63+
def dce_createservicew(dcerpc, scm_handle, service_name, display_name, binary_path, opts)
64+
default_opts = {
65+
:access => 0x0F01FF, # Maximum access.
66+
:type => 0x00000110, # Interactive, own process.
67+
:start => 0x00000003, # Start on demand.
68+
:errors => 0x00000000,# Ignore errors.
69+
:load_order_group => 0,
70+
:dependencies => 0,
71+
:service_start => 0,
72+
:password1 => 0,
73+
:password2 => 0,
74+
:password3 => 0,
75+
:password4 => 0
76+
}.merge(opts)
77+
78+
svc_handle = nil
79+
svc_status = nil
80+
stubdata = scm_handle +
81+
NDR.wstring(service_name) +
82+
NDR.uwstring(display_name) +
83+
NDR.long(default_opts[:access]) +
84+
NDR.long(default_opts[:type]) +
85+
NDR.long(default_opts[:start]) +
86+
NDR.long(default_opts[:errors]) +
87+
NDR.wstring(binary_path) +
88+
NDR.long(default_opts[:load_order_group]) +
89+
NDR.long(default_opts[:dependencies]) +
90+
NDR.long(default_opts[:service_start]) +
91+
NDR.long(default_opts[:password1]) +
92+
NDR.long(default_opts[:password2]) +
93+
NDR.long(default_opts[:password3]) +
94+
NDR.long(default_opts[:password4])
95+
response = dcerpc.call(0x0c, stubdata)
96+
if dcerpc.last_response and dcerpc.last_response.stub_data
97+
svc_handle = dcerpc.last_response.stub_data[4,20]
98+
svc_status = dcerpc.last_response.stub_data[20,4]
99+
end
100+
101+
if svc_status.to_i != 0
102+
svc_handle = nil
103+
end
104+
return svc_handle
105+
end
106+
107+
# Calls CloseHandle() to close a handle. Returns true on success, or false.
108+
#
109+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
110+
# @param handle [String] the handle to close.
111+
#
112+
# @return [Boolean] true if the handle was successfully closed, or false if
113+
# not.
114+
def dce_closehandle(dcerpc, handle)
115+
ret = false
116+
response = dcerpc.call(0x0, handle)
117+
if dcerpc.last_response and dcerpc.last_response.stub_data
118+
if dcerpc.last_response.stub_data[20,4].to_i == 0
119+
ret = true
120+
end
121+
end
122+
return ret
123+
end
124+
125+
# Calls OpenServiceW to obtain a handle to an existing service.
126+
#
127+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
128+
# @param scm_handle [String] the SCM handle (from dce_openscmanagerw()).
129+
# @param service_name [String] the name of the service to open.
130+
# @param access [Fixnum] the level of access requested (default is maximum).
131+
#
132+
# @return [String, nil] the handle of the service opened, or nil on failure.
133+
def dce_openservicew(dcerpc, scm_handle, service_name, access = 0xF01FF)
134+
svc_handle = nil
135+
svc_status = nil
136+
stubdata = scm_handle + NDR.wstring(service_name) + NDR.long(access)
137+
response = dcerpc.call(0x10, stubdata)
138+
if dcerpc.last_response and dcerpc.last_response.stub_data
139+
svc_handle = dcerpc.last_response.stub_data[0,20]
140+
svc_status = dcerpc.last_response.stub_data[20,4]
141+
end
142+
143+
if svc_status.to_i != 0
144+
svc_handle = nil
145+
end
146+
return svc_handle
147+
end
148+
149+
# Calls StartService() on a handle to an existing service in order to start
150+
# it. Returns true on success, or false.
151+
#
152+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
153+
# @param svc_handle [String] the handle of the service to start (from
154+
# dce_openservicew()).
155+
# @param magic1 [Fixnum] an unknown value.
156+
# @param magic2 [Fixnum] another unknown value.
157+
#
158+
# @return [Boolean] true if the service was successfully started, false if
159+
# it was not.
160+
def dce_startservice(dcerpc, svc_handle, magic1 = 0, magic2 = 0)
161+
ret = false
162+
stubdata = svc_handle + NDR.long(magic1) + NDR.long(magic2)
163+
response = dcerpc.call(0x13, stubdata)
164+
if dcerpc.last_response and dcerpc.last_response.stub_data
165+
if dcerpc.last_response.stub_data[0,4].to_i == 0
166+
ret = true
167+
end
168+
end
169+
return ret
170+
end
171+
172+
# Stops a running service.
173+
#
174+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
175+
# @param svc_handle [String] the handle of the service to stop (from
176+
# dce_openservicew()).
177+
#
178+
# @return [Boolean] true if the service was successfully stopped, false if
179+
# it was not.
180+
def dce_stopservice(dcerpc, svc_handle)
181+
return dce_controlservice(dcerpc, svc_handle, 1)
182+
end
183+
184+
# Controls an existing service.
185+
#
186+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
187+
# @param svc_handle [String] the handle of the service to control
188+
# (from dce_openservicew()).
189+
# @param operation [Fixnum] the operation number to perform (1 = stop
190+
# service; others are unknown).
191+
#
192+
# @return [Boolean] true if the operation was successful, false if it was
193+
# not.
194+
def dce_controlservice(dcerpc, svc_handle, operation)
195+
ret = false
196+
response = dcerpc.call(0x01, svc_handle + NDR.long(operation))
197+
if dcerpc.last_response and dcerpc.last_response.stub_data
198+
if dcerpc.last_response.stub_data[28,4].to_i == 0
199+
ret = true
200+
end
201+
end
202+
return ret
203+
end
204+
205+
# Calls DeleteService() to delete a service.
206+
#
207+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
208+
# @param svc_handle [String] the handle of the service to delete (from
209+
# dce_openservicew()).
210+
#
211+
# @return [Boolean] true if the service was successfully deleted, false if
212+
# it was not.
213+
def dce_deleteservice(dcerpc, svc_handle)
214+
ret = false
215+
response = dcerpc.call(0x02, svc_handle)
216+
if dcerpc.last_response and dcerpc.last_response.stub_data
217+
if dcerpc.last_response.stub_data[0,4].to_i == 0
218+
ret = true
219+
end
220+
end
221+
return ret
222+
end
223+
224+
# Calls QueryServiceStatus() to query the status of a service.
225+
#
226+
# @param dcerpc [Rex::Proto::DCERPC::Client] the DCERPC client to use.
227+
# @param svc_handle [String] the handle of the service to query (from
228+
# dce_openservicew()).
229+
#
230+
# @return [Fixnum] Returns 0 if the query failed (i.e.: a state was returned
231+
# that isn't implemented), 1 if the service is running, and
232+
# 2 if the service is stopped.
233+
def dce_queryservice(dcerpc, svc_handle)
234+
ret = 0
235+
response = dcerpc.call(0x06, svc_handle)
236+
if response[0,9] == "\x10\x00\x00\x00\x04\x00\x00\x00\x01"
237+
ret = 1
238+
elsif response[0,9] == "\x10\x00\x00\x00\x01\x00\x00\x00\x00"
239+
ret = 2
240+
end
241+
return ret
242+
end
243+
244+
end
245+
end

0 commit comments

Comments
 (0)