rex 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
+