rex 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex/arch/x86.rb +16 -0
  3. data/lib/rex/constants.rb +1 -0
  4. data/lib/rex/constants/windows.rb +147 -0
  5. data/lib/rex/encoder/xdr.rb +3 -2
  6. data/lib/rex/exceptions.rb +37 -5
  7. data/lib/rex/exploitation/cmdstager/bourne.rb +9 -1
  8. data/lib/rex/exploitation/cmdstager/tftp.rb +5 -5
  9. data/lib/rex/java.rb +3 -0
  10. data/lib/rex/java/serialization.rb +54 -0
  11. data/lib/rex/java/serialization/model.rb +20 -0
  12. data/lib/rex/java/serialization/model/annotation.rb +69 -0
  13. data/lib/rex/java/serialization/model/block_data.rb +70 -0
  14. data/lib/rex/java/serialization/model/block_data_long.rb +72 -0
  15. data/lib/rex/java/serialization/model/class_desc.rb +64 -0
  16. data/lib/rex/java/serialization/model/contents.rb +156 -0
  17. data/lib/rex/java/serialization/model/element.rb +44 -0
  18. data/lib/rex/java/serialization/model/end_block_data.rb +12 -0
  19. data/lib/rex/java/serialization/model/field.rb +172 -0
  20. data/lib/rex/java/serialization/model/long_utf.rb +48 -0
  21. data/lib/rex/java/serialization/model/new_array.rb +225 -0
  22. data/lib/rex/java/serialization/model/new_class_desc.rb +155 -0
  23. data/lib/rex/java/serialization/model/new_enum.rb +79 -0
  24. data/lib/rex/java/serialization/model/new_object.rb +223 -0
  25. data/lib/rex/java/serialization/model/null_reference.rb +12 -0
  26. data/lib/rex/java/serialization/model/reference.rb +61 -0
  27. data/lib/rex/java/serialization/model/reset.rb +12 -0
  28. data/lib/rex/java/serialization/model/stream.rb +123 -0
  29. data/lib/rex/java/serialization/model/utf.rb +69 -0
  30. data/lib/rex/mime/message.rb +9 -14
  31. data/lib/rex/payloads.rb +1 -0
  32. data/lib/rex/payloads/meterpreter.rb +2 -0
  33. data/lib/rex/payloads/meterpreter/patch.rb +136 -0
  34. data/lib/rex/payloads/win32/kernel/stager.rb +26 -25
  35. data/lib/rex/post/meterpreter/client.rb +50 -60
  36. data/lib/rex/post/meterpreter/client_core.rb +18 -25
  37. data/lib/rex/post/meterpreter/extensions/extapi/adsi/adsi.rb +102 -8
  38. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +24 -14
  39. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +18 -0
  40. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +1 -0
  41. data/lib/rex/post/meterpreter/packet_dispatcher.rb +1 -1
  42. data/lib/rex/post/meterpreter/ui/console.rb +1 -1
  43. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +43 -1
  44. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +1 -1
  45. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +9 -0
  46. data/lib/rex/proto/dcerpc/svcctl.rb +2 -0
  47. data/lib/rex/proto/dcerpc/svcctl/packet.rb +304 -0
  48. data/lib/rex/proto/kademlia.rb +8 -0
  49. data/lib/rex/proto/kademlia/bootstrap_request.rb +19 -0
  50. data/lib/rex/proto/kademlia/bootstrap_response.rb +79 -0
  51. data/lib/rex/proto/kademlia/message.rb +72 -0
  52. data/lib/rex/proto/kademlia/ping.rb +19 -0
  53. data/lib/rex/proto/kademlia/pong.rb +41 -0
  54. data/lib/rex/proto/kademlia/util.rb +22 -0
  55. data/lib/rex/proto/natpmp/packet.rb +30 -2
  56. data/lib/rex/proto/quake.rb +3 -0
  57. data/lib/rex/proto/quake/message.rb +73 -0
  58. data/lib/rex/proto/smb/client.rb +1 -0
  59. data/lib/rex/proto/smb/simpleclient.rb +4 -0
  60. data/lib/rex/proto/sunrpc/client.rb +14 -3
  61. data/lib/rex/socket/comm/local.rb +10 -7
  62. data/lib/rex/socket/ssl_tcp_server.rb +79 -40
  63. data/lib/rex/ui/text/input/readline.rb +33 -6
  64. data/lib/rex/ui/text/output/file.rb +2 -2
  65. data/lib/rex/ui/text/output/stdio.rb +70 -14
  66. data/rex.gemspec +1 -1
  67. metadata +38 -3
@@ -48,14 +48,7 @@ class Adsi
48
48
 
49
49
  response = client.send_request(request)
50
50
 
51
- results = []
52
- response.each(TLV_TYPE_EXT_ADSI_RESULT) { |r|
53
- result = []
54
- r.each(TLV_TYPE_EXT_ADSI_VALUE) { |v|
55
- result << v.value
56
- }
57
- results << result
58
- }
51
+ results = extract_results(response)
59
52
 
60
53
  return {
61
54
  :fields => fields,
@@ -65,6 +58,107 @@ class Adsi
65
58
 
66
59
  attr_accessor :client
67
60
 
61
+ protected
62
+
63
+ #
64
+ # Retrieve the results of the query from the response
65
+ # packet that was returned from Meterpreter.
66
+ #
67
+ # @param response [Packet] Reference to the received
68
+ # packet that was returned from Meterpreter.
69
+ #
70
+ # @return [Array[Array[[Hash]]] Collection of results from
71
+ # the ADSI query.
72
+ #
73
+ def extract_results(response)
74
+ results = []
75
+
76
+ response.each(TLV_TYPE_EXT_ADSI_RESULT) do |r|
77
+ results << extract_values(r)
78
+ end
79
+
80
+ results
81
+ end
82
+
83
+ #
84
+ # Extract a single row of results from a TLV group.
85
+ #
86
+ # @param tlv_container [Packet] Reference to the TLV
87
+ # group to pull the values from.
88
+ #
89
+ # @return [Array[Hash]] Collection of values from
90
+ # the single ADSI query result row.
91
+ #
92
+ def extract_values(tlv_container)
93
+ values = []
94
+ tlv_container.get_tlvs(TLV_TYPE_ANY).each do |v|
95
+ values << extract_value(v)
96
+ end
97
+ values
98
+ end
99
+
100
+ #
101
+ # Convert a single ADSI result value into a usable
102
+ # value that also describes its type.
103
+ #
104
+ # @param v [TLV] The TLV item that contains the value.
105
+ #
106
+ # @return [Hash] The type/value pair from the TLV.
107
+ #
108
+ def extract_value(v)
109
+ value = {
110
+ :type => :unknown
111
+ }
112
+
113
+ case v.type
114
+ when TLV_TYPE_EXT_ADSI_STRING
115
+ value = {
116
+ :type => :string,
117
+ :value => v.value
118
+ }
119
+ when TLV_TYPE_EXT_ADSI_NUMBER, TLV_TYPE_EXT_ADSI_BIGNUMBER
120
+ value = {
121
+ :type => :number,
122
+ :value => v.value
123
+ }
124
+ when TLV_TYPE_EXT_ADSI_BOOL
125
+ value = {
126
+ :type => :bool,
127
+ :value => v.value
128
+ }
129
+ when TLV_TYPE_EXT_ADSI_RAW
130
+ value = {
131
+ :type => :raw,
132
+ :value => v.value
133
+ }
134
+ when TLV_TYPE_EXT_ADSI_ARRAY
135
+ value = {
136
+ :type => :array,
137
+ :value => extract_values(v.value)
138
+ }
139
+ when TLV_TYPE_EXT_ADSI_PATH
140
+ value = {
141
+ :type => :path,
142
+ :volume => v.get_tlv_value(TLV_TYPE_EXT_ADSI_PATH_VOL),
143
+ :path => v.get_tlv_value(TLV_TYPE_EXT_ADSI_PATH_PATH),
144
+ :vol_type => v.get_tlv_value(TLV_TYPE_EXT_ADSI_PATH_TYPE)
145
+ }
146
+ when TLV_TYPE_EXT_ADSI_DN
147
+ values = v.get_tlvs(TLV_TYPE_ALL)
148
+ value = {
149
+ :type => :dn,
150
+ :label => values[0].value
151
+ }
152
+
153
+ if values[1].type == TLV_TYPE_EXT_ADSI_STRING
154
+ value[:string] = value[1].value
155
+ else
156
+ value[:raw] = value[1].value
157
+ end
158
+ end
159
+
160
+ value
161
+ end
68
162
  end
69
163
 
70
164
  end; end; end; end; end; end
@@ -54,21 +54,31 @@ TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS = TLV_META_TYPE_STRING | (TLV_TYPE_E
54
54
  TLV_TYPE_EXT_CLIPBOARD_MON_DUMP = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 52)
55
55
  TLV_TYPE_EXT_CLIPBOARD_MON_PURGE = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 53)
56
56
 
57
- TLV_TYPE_EXT_ADSI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 55)
58
- TLV_TYPE_EXT_ADSI_FILTER = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 56)
59
- TLV_TYPE_EXT_ADSI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 57)
60
- TLV_TYPE_EXT_ADSI_VALUE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 58)
61
- TLV_TYPE_EXT_ADSI_RESULT = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 59)
62
- TLV_TYPE_EXT_ADSI_MAXRESULTS = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 60)
63
- TLV_TYPE_EXT_ADSI_PAGESIZE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 61)
57
+ TLV_TYPE_EXT_ADSI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 54)
58
+ TLV_TYPE_EXT_ADSI_FILTER = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 55)
59
+ TLV_TYPE_EXT_ADSI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 56)
60
+ TLV_TYPE_EXT_ADSI_RESULT = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 57)
61
+ TLV_TYPE_EXT_ADSI_MAXRESULTS = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 58)
62
+ TLV_TYPE_EXT_ADSI_PAGESIZE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 59)
63
+ TLV_TYPE_EXT_ADSI_ARRAY = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 60)
64
+ TLV_TYPE_EXT_ADSI_STRING = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 61)
65
+ TLV_TYPE_EXT_ADSI_NUMBER = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 62)
66
+ TLV_TYPE_EXT_ADSI_BIGNUMBER = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 63)
67
+ TLV_TYPE_EXT_ADSI_BOOL = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 64)
68
+ TLV_TYPE_EXT_ADSI_RAW = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 65)
69
+ TLV_TYPE_EXT_ADSI_PATH = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 66)
70
+ TLV_TYPE_EXT_ADSI_PATH_VOL = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 67)
71
+ TLV_TYPE_EXT_ADSI_PATH_PATH = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 68)
72
+ TLV_TYPE_EXT_ADSI_PATH_TYPE = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 69)
73
+ TLV_TYPE_EXT_ADSI_DN = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 70)
64
74
 
65
- TLV_TYPE_EXT_WMI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 65)
66
- TLV_TYPE_EXT_WMI_QUERY = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 66)
67
- TLV_TYPE_EXT_WMI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 67)
68
- TLV_TYPE_EXT_WMI_VALUE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 68)
69
- TLV_TYPE_EXT_WMI_FIELDS = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 69)
70
- TLV_TYPE_EXT_WMI_VALUES = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 70)
71
- TLV_TYPE_EXT_WMI_ERROR = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 71)
75
+ TLV_TYPE_EXT_WMI_DOMAIN = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 90)
76
+ TLV_TYPE_EXT_WMI_QUERY = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 91)
77
+ TLV_TYPE_EXT_WMI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 92)
78
+ TLV_TYPE_EXT_WMI_VALUE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 93)
79
+ TLV_TYPE_EXT_WMI_FIELDS = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 94)
80
+ TLV_TYPE_EXT_WMI_VALUES = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 95)
81
+ TLV_TYPE_EXT_WMI_ERROR = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 96)
72
82
 
73
83
  end
74
84
  end
@@ -20,6 +20,8 @@ module Sys
20
20
  ###
21
21
  class Config
22
22
 
23
+ SYSTEM_SID = 'S-1-5-18'
24
+
23
25
  def initialize(client)
24
26
  self.client = client
25
27
  end
@@ -33,6 +35,22 @@ class Config
33
35
  client.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_USER_NAME) )
34
36
  end
35
37
 
38
+ #
39
+ # Gets the SID of the current process/thread.
40
+ #
41
+ def getsid
42
+ request = Packet.create_request('stdapi_sys_config_getsid')
43
+ response = client.send_request(request)
44
+ response.get_tlv_value(TLV_TYPE_SID)
45
+ end
46
+
47
+ #
48
+ # Determine if the current process/thread is running as SYSTEM
49
+ #
50
+ def is_system?
51
+ getsid == SYSTEM_SID
52
+ end
53
+
36
54
  #
37
55
  # Returns a hash of requested environment variables, along with their values.
38
56
  # If a requested value doesn't exist in the response, then the value wasn't found.
@@ -116,6 +116,7 @@ TLV_TYPE_OS_NAME = TLV_META_TYPE_STRING | 1041
116
116
  TLV_TYPE_USER_NAME = TLV_META_TYPE_STRING | 1042
117
117
  TLV_TYPE_ARCHITECTURE = TLV_META_TYPE_STRING | 1043
118
118
  TLV_TYPE_LANG_SYSTEM = TLV_META_TYPE_STRING | 1044
119
+ TLV_TYPE_SID = TLV_META_TYPE_STRING | 1045
119
120
 
120
121
  # Environment
121
122
  TLV_TYPE_ENV_VARIABLE = TLV_META_TYPE_STRING | 1100
@@ -96,7 +96,7 @@ module PacketDispatcher
96
96
 
97
97
  # If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
98
98
  if req.body[0,4] == "RECV"
99
- rpkt = send_queue.pop
99
+ rpkt = send_queue.shift
100
100
  resp.body = rpkt || ''
101
101
  begin
102
102
  cli.send_response(resp)
@@ -106,7 +106,7 @@ class Console
106
106
  log_error("Operation timed out.")
107
107
  rescue RequestError => info
108
108
  log_error(info.to_s)
109
- rescue Rex::AddressInUse => e
109
+ rescue Rex::InvalidDestination => e
110
110
  log_error(e.message)
111
111
  rescue ::Errno::EPIPE, ::OpenSSL::SSL::SSLError, ::IOError
112
112
  self.client.kill
@@ -176,7 +176,7 @@ class Console::CommandDispatcher::Extapi::Adsi
176
176
  )
177
177
 
178
178
  objects[:results].each do |c|
179
- table << c
179
+ table << to_table_row(c)
180
180
  end
181
181
 
182
182
  print_line
@@ -189,6 +189,48 @@ class Console::CommandDispatcher::Extapi::Adsi
189
189
  return true
190
190
  end
191
191
 
192
+ protected
193
+
194
+ #
195
+ # Convert an ADSI result row to a table row so that it can
196
+ # be rendered to screen appropriately.
197
+ #
198
+ # @param result [Array[Hash]] Array of type/value pairs.
199
+ #
200
+ # @return [Array[String]] Renderable view of the value.
201
+ #
202
+ def to_table_row(result)
203
+ values = []
204
+
205
+ result.each do |v|
206
+ case v[:type]
207
+ when :string, :number, :bool
208
+ values << v[:value].to_s
209
+ when :raw
210
+ # for UI level stuff, rendering raw as hex is really the only option
211
+ values << Rex::Text.to_hex(v[:value], '')
212
+ when :array
213
+ val = "#{to_table_row(v[:value]).join(", ")}"
214
+
215
+ # we'll truncate the output of the array because it could be excessive if we
216
+ # don't. Users who want the detail of this stuff should probably script it.
217
+ if val.length > 50
218
+ val = "<#{val[0,50]}..."
219
+ end
220
+
221
+ values << val
222
+ when :dn
223
+ values << "#{value[:label]}: #{value[:string] || Rex::Text.to_hex(value[:raw], '')}"
224
+ when :path
225
+ values << "Vol: #{v[:volume]}, Path: #{v[:path]}, Type: #{v[:vol_type]}"
226
+ when :unknown
227
+ values << "(unknown)"
228
+ end
229
+ end
230
+
231
+ values
232
+ end
233
+
192
234
  end
193
235
 
194
236
  end
@@ -221,7 +221,7 @@ class Console::CommandDispatcher::Incognito
221
221
  end
222
222
 
223
223
  def system_privilege_check
224
- if (client.sys.config.getuid != "NT AUTHORITY\\SYSTEM")
224
+ unless client.sys.config.is_system?
225
225
  print_line("[-] Warning: Not currently running as SYSTEM, not all tokens will be available")
226
226
  print_line(" Call rev2self if primary process token is SYSTEM")
227
227
  end
@@ -88,6 +88,7 @@ class Console::CommandDispatcher::Stdapi::Sys
88
88
  "getpid" => "Get the current process identifier",
89
89
  "getprivs" => "Attempt to enable all privileges available to the current process",
90
90
  "getuid" => "Get the user that the server is running as",
91
+ "getsid" => "Get the SID of the user that the server is running as",
91
92
  "getenv" => "Get one or more environment variable values",
92
93
  "kill" => "Terminate a process",
93
94
  "ps" => "List running processes",
@@ -107,6 +108,7 @@ class Console::CommandDispatcher::Stdapi::Sys
107
108
  "getpid" => [ "stdapi_sys_process_getpid" ],
108
109
  "getprivs" => [ "stdapi_sys_config_getprivs" ],
109
110
  "getuid" => [ "stdapi_sys_config_getuid" ],
111
+ "getsid" => [ "stdapi_sys_config_getsid" ],
110
112
  "getenv" => [ "stdapi_sys_config_getenv" ],
111
113
  "kill" => [ "stdapi_sys_process_kill" ],
112
114
  "ps" => [ "stdapi_sys_process_get_processes" ],
@@ -279,6 +281,13 @@ class Console::CommandDispatcher::Stdapi::Sys
279
281
  print_line("Server username: #{client.sys.config.getuid}")
280
282
  end
281
283
 
284
+ #
285
+ # Display the SID of the user that the server is running as.
286
+ #
287
+ def cmd_getsid(*args)
288
+ print_line("Server SID: #{client.sys.config.getsid}")
289
+ end
290
+
282
291
  #
283
292
  # Get the value of one or more environment variables from the target.
284
293
  #
@@ -0,0 +1,2 @@
1
+ # -*- coding: binary -*-
2
+ require 'rex/proto/dcerpc/svcctl/packet'
@@ -0,0 +1,304 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+
4
+ ###
5
+ # This module implements MSRPC functions that control creating, deleting,
6
+ # starting, stopping, and querying system services.
7
+ ###
8
+ module Proto::DCERPC::SVCCTL
9
+
10
+ require 'rex/constants/windows'
11
+ NDR = Rex::Encoder::NDR
12
+
13
+
14
+ class Client
15
+
16
+ include Rex::Constants::Windows
17
+
18
+ attr_accessor :dcerpc_client
19
+
20
+ def initialize(dcerpc_client)
21
+ self.dcerpc_client = dcerpc_client
22
+ end
23
+
24
+ # Returns the Windows Error Code in numeric format
25
+ #
26
+ # @param raw_error [String] the raw error code in binary format.
27
+ #
28
+ # @return [Integer] the Windows Error Code integer.
29
+ def error_code(raw_error)
30
+ raw_error.unpack('V').first
31
+ end
32
+
33
+ # Calls OpenSCManagerW() to obtain a handle to the service control manager.
34
+ #
35
+ # @param rhost [String] the target host.
36
+ # @param access [Fixnum] the access flags requested.
37
+ #
38
+ # @return [Array<String,Integer>] the handle to the service control manager or nil if
39
+ # the call is not successful and the Windows error code
40
+ def openscmanagerw(rhost, access = SC_MANAGER_ALL_ACCESS)
41
+ scm_handle = nil
42
+ scm_status = nil
43
+ stubdata =
44
+ NDR.uwstring("\\\\#{rhost}") +
45
+ NDR.long(0) +
46
+ NDR.long(access)
47
+ begin
48
+ response = dcerpc_client.call(OPEN_SC_MANAGER_W, stubdata)
49
+ if response
50
+ scm_status = error_code(response[20,4])
51
+ if scm_status == ERROR_SUCCESS
52
+ scm_handle = response[0,20]
53
+ end
54
+ end
55
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
56
+ print_error("#{peer} - Error getting scm handle: #{e}")
57
+ end
58
+
59
+ [scm_handle, scm_status]
60
+ end
61
+
62
+ # Calls CreateServiceW() to create a system service. Returns a handle to
63
+ # the service on success, or nil.
64
+ #
65
+ # @param scm_handle [String] the SCM handle (from {#openscmanagerw}).
66
+ # @param service_name [String] the service name.
67
+ # @param display_name [String] the display name.
68
+ # @param binary_path [String] the path of the binary to run.
69
+ # @param opts [Hash] arguments for CreateServiceW()
70
+ # @option opts [Fixnum] :access (SERVICE_ALL_ACCESS) the access level.
71
+ # @option opts [Fixnum] :type (SERVICE_WIN32_OWN_PROCESS ||
72
+ # SERVICE_INTERACTIVE_PROCESS) the type of service.
73
+ # @option opts [Fixnum] :start (SERVICE_DEMAND_START) the start options.
74
+ # @option opts [Fixnum] :errors (SERVICE_ERROR_IGNORE) the error options.
75
+ # @option opts [Fixnum] :load_order_group (0) the load order group.
76
+ # @option opts [Fixnum] :dependencies (0) the dependencies of the service.
77
+ # @option opts [Fixnum] :service_start (0)
78
+ # @option opts [Fixnum] :password1 (0)
79
+ # @option opts [Fixnum] :password2 (0)
80
+ # @option opts [Fixnum] :password3 (0)
81
+ # @option opts [Fixnum] :password4 (0)
82
+ #
83
+ # @return [String, Integer] a handle to the created service, windows
84
+ # error code.
85
+ def createservicew(scm_handle, service_name, display_name, binary_path, opts)
86
+ default_opts = {
87
+ :access => SERVICE_ALL_ACCESS,
88
+ :type => SERVICE_WIN32_OWN_PROCESS || SERVICE_INTERACTIVE_PROCESS,
89
+ :start => SERVICE_DEMAND_START,
90
+ :errors => SERVICE_ERROR_IGNORE,
91
+ :load_order_group => 0,
92
+ :dependencies => 0,
93
+ :service_start => 0,
94
+ :password1 => 0,
95
+ :password2 => 0,
96
+ :password3 => 0,
97
+ :password4 => 0
98
+ }.merge(opts)
99
+
100
+ svc_handle = nil
101
+ svc_status = nil
102
+ stubdata = scm_handle +
103
+ NDR.wstring(service_name) +
104
+ NDR.uwstring(display_name) +
105
+ NDR.long(default_opts[:access]) +
106
+ NDR.long(default_opts[:type]) +
107
+ NDR.long(default_opts[:start]) +
108
+ NDR.long(default_opts[:errors]) +
109
+ NDR.wstring(binary_path) +
110
+ NDR.long(default_opts[:load_order_group]) +
111
+ NDR.long(default_opts[:dependencies]) +
112
+ NDR.long(default_opts[:service_start]) +
113
+ NDR.long(default_opts[:password1]) +
114
+ NDR.long(default_opts[:password2]) +
115
+ NDR.long(default_opts[:password3]) +
116
+ NDR.long(default_opts[:password4])
117
+ begin
118
+ response = dcerpc_client.call(CREATE_SERVICE_W, stubdata)
119
+ if response
120
+ svc_status = error_code(response[24,4])
121
+
122
+ if svc_status == ERROR_SUCCESS
123
+ svc_handle = response[4,20]
124
+ end
125
+ end
126
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
127
+ print_error("#{peer} - Error creating service: #{e}")
128
+ end
129
+
130
+ return svc_handle, svc_status
131
+ end
132
+
133
+ # Calls ChangeServiceConfig2() to change the service description.
134
+ #
135
+ # @param svc_handle [String] the service handle to change.
136
+ # @param service_description [String] the service description.
137
+ #
138
+ # @return [Integer] Windows error code
139
+ def changeservicedescription(svc_handle, service_description)
140
+ svc_status = nil
141
+ stubdata =
142
+ svc_handle +
143
+ NDR.long(SERVICE_CONFIG_DESCRIPTION) +
144
+ NDR.long(1) + # lpInfo -> *SERVICE_DESCRIPTION
145
+ NDR.long(0x0200) + # SERVICE_DESCRIPTION struct
146
+ NDR.long(0x04000200) +
147
+ NDR.wstring(service_description)
148
+ begin
149
+ response = dcerpc_client.call(CHANGE_SERVICE_CONFIG2_W, stubdata) # ChangeServiceConfig2
150
+ svc_status = error_code(response)
151
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
152
+ print_error("#{peer} - Error changing service description : #{e}")
153
+ end
154
+
155
+ svc_status
156
+ end
157
+
158
+
159
+ # Calls CloseHandle() to close a handle.
160
+ #
161
+ # @param handle [String] the handle to close.
162
+ #
163
+ # @return [Integer] Windows error code
164
+ def closehandle(handle)
165
+ svc_status = nil
166
+ begin
167
+ response = dcerpc_client.call(CLOSE_SERVICE_HANDLE, handle)
168
+ if response
169
+ svc_status = error_code(response[20,4])
170
+ end
171
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
172
+ print_error("#{peer} - Error closing service handle: #{e}")
173
+ end
174
+
175
+ svc_status
176
+ end
177
+
178
+ # Calls OpenServiceW to obtain a handle to an existing service.
179
+ #
180
+ # @param scm_handle [String] the SCM handle (from {#openscmanagerw}).
181
+ # @param service_name [String] the name of the service to open.
182
+ # @param access [Fixnum] the level of access requested (default is maximum).
183
+ #
184
+ # @return [String, nil] the handle of the service opened, or nil on failure.
185
+ def openservicew(scm_handle, service_name, access = SERVICE_ALL_ACCESS)
186
+ svc_handle = nil
187
+ svc_status = nil
188
+ stubdata = scm_handle + NDR.wstring(service_name) + NDR.long(access)
189
+ begin
190
+ response = dcerpc_client.call(OPEN_SERVICE_W, stubdata)
191
+ if response
192
+ svc_status = error_code(response[20,4])
193
+ if svc_status == ERROR_SUCCESS
194
+ svc_handle = response[0,20]
195
+ end
196
+ end
197
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
198
+ print_error("#{peer} - Error opening service handle: #{e}")
199
+ end
200
+
201
+ svc_handle
202
+ end
203
+
204
+ # Calls StartService() on a handle to an existing service in order to start
205
+ # it. Returns true on success, or false.
206
+ #
207
+ # @param svc_handle [String] the handle of the service (from {#openservicew}).
208
+ # @param magic1 [Fixnum] an unknown value.
209
+ # @param magic2 [Fixnum] another unknown value.
210
+ #
211
+ # @return [Integer] Windows error code
212
+ def startservice(svc_handle, magic1 = 0, magic2 = 0)
213
+ svc_status = nil
214
+ stubdata = svc_handle + NDR.long(magic1) + NDR.long(magic2)
215
+
216
+ begin
217
+ response = dcerpc_client.call(0x13, stubdata)
218
+ if response
219
+ svc_status = error_code(response)
220
+ end
221
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
222
+ print_error("#{peer} - Error starting service: #{e}")
223
+ end
224
+
225
+ svc_status
226
+ end
227
+
228
+ # Stops a running service.
229
+ #
230
+ # @param svc_handle [String] the handle of the service (from {#openservicew}).
231
+ #
232
+ # @return [Integer] Windows error code
233
+ def stopservice(svc_handle)
234
+ dce_controlservice(svc_handle, SERVICE_CONTROL_STOP)
235
+ end
236
+
237
+ # Controls an existing service.
238
+ #
239
+ # @param svc_handle [String] the handle of the service (from {#openservicew}).
240
+ # @param operation [Fixnum] the operation number to perform (1 = stop
241
+ # service; others are unknown).
242
+ #
243
+ # @return [Integer] Windows error code
244
+ def controlservice(svc_handle, operation)
245
+ svc_status = nil
246
+ begin
247
+ response = dcerpc_client.call(CONTROL_SERVICE, svc_handle + NDR.long(operation))
248
+ if response
249
+ svc_status = error_code(response[28,4])
250
+ end
251
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
252
+ print_error("#{peer} - Error controlling service: #{e}")
253
+ end
254
+
255
+ svc_status
256
+ end
257
+
258
+ # Calls DeleteService() to delete a service.
259
+ #
260
+ # @param svc_handle [String] the handle of the service (from {#openservicew}).
261
+ #
262
+ # @return [Integer] Windows error code
263
+ def deleteservice(svc_handle)
264
+ svc_status = nil
265
+ begin
266
+ response = dcerpc_client.call(DELETE_SERVICE, svc_handle)
267
+ if response
268
+ svc_status = error_code(response)
269
+ end
270
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
271
+ print_error("#{peer} - Error deleting service: #{e}")
272
+ end
273
+
274
+ svc_status
275
+ end
276
+
277
+ # Calls QueryServiceStatus() to query the status of a service.
278
+ #
279
+ # @param svc_handle [String] the handle of the service (from {#openservicew}).
280
+ #
281
+ # @return [Fixnum] Returns 0 if the query failed (i.e.: a state was returned
282
+ # that isn't implemented), 1 if the service is running, and
283
+ # 2 if the service is stopped.
284
+ def queryservice(svc_handle)
285
+ ret = 0
286
+
287
+ begin
288
+ response = dcerpc_client.call(QUERY_SERVICE_STATUS, svc_handle)
289
+ if response[0,9] == "\x10\x00\x00\x00\x04\x00\x00\x00\x01"
290
+ ret = 1
291
+ elsif response[0,9] == "\x10\x00\x00\x00\x01\x00\x00\x00\x00"
292
+ ret = 2
293
+ end
294
+ rescue Rex::Proto::DCERPC::Exceptions::Fault => e
295
+ print_error("#{peer} - Error deleting service: #{e}")
296
+ end
297
+
298
+ ret
299
+ end
300
+
301
+ end
302
+ end
303
+ end
304
+