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.
- checksums.yaml +4 -4
- data/lib/rex/arch/x86.rb +16 -0
- data/lib/rex/constants.rb +1 -0
- data/lib/rex/constants/windows.rb +147 -0
- data/lib/rex/encoder/xdr.rb +3 -2
- data/lib/rex/exceptions.rb +37 -5
- data/lib/rex/exploitation/cmdstager/bourne.rb +9 -1
- data/lib/rex/exploitation/cmdstager/tftp.rb +5 -5
- data/lib/rex/java.rb +3 -0
- data/lib/rex/java/serialization.rb +54 -0
- data/lib/rex/java/serialization/model.rb +20 -0
- data/lib/rex/java/serialization/model/annotation.rb +69 -0
- data/lib/rex/java/serialization/model/block_data.rb +70 -0
- data/lib/rex/java/serialization/model/block_data_long.rb +72 -0
- data/lib/rex/java/serialization/model/class_desc.rb +64 -0
- data/lib/rex/java/serialization/model/contents.rb +156 -0
- data/lib/rex/java/serialization/model/element.rb +44 -0
- data/lib/rex/java/serialization/model/end_block_data.rb +12 -0
- data/lib/rex/java/serialization/model/field.rb +172 -0
- data/lib/rex/java/serialization/model/long_utf.rb +48 -0
- data/lib/rex/java/serialization/model/new_array.rb +225 -0
- data/lib/rex/java/serialization/model/new_class_desc.rb +155 -0
- data/lib/rex/java/serialization/model/new_enum.rb +79 -0
- data/lib/rex/java/serialization/model/new_object.rb +223 -0
- data/lib/rex/java/serialization/model/null_reference.rb +12 -0
- data/lib/rex/java/serialization/model/reference.rb +61 -0
- data/lib/rex/java/serialization/model/reset.rb +12 -0
- data/lib/rex/java/serialization/model/stream.rb +123 -0
- data/lib/rex/java/serialization/model/utf.rb +69 -0
- data/lib/rex/mime/message.rb +9 -14
- data/lib/rex/payloads.rb +1 -0
- data/lib/rex/payloads/meterpreter.rb +2 -0
- data/lib/rex/payloads/meterpreter/patch.rb +136 -0
- data/lib/rex/payloads/win32/kernel/stager.rb +26 -25
- data/lib/rex/post/meterpreter/client.rb +50 -60
- data/lib/rex/post/meterpreter/client_core.rb +18 -25
- data/lib/rex/post/meterpreter/extensions/extapi/adsi/adsi.rb +102 -8
- data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +24 -14
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +18 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +1 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +43 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +9 -0
- data/lib/rex/proto/dcerpc/svcctl.rb +2 -0
- data/lib/rex/proto/dcerpc/svcctl/packet.rb +304 -0
- data/lib/rex/proto/kademlia.rb +8 -0
- data/lib/rex/proto/kademlia/bootstrap_request.rb +19 -0
- data/lib/rex/proto/kademlia/bootstrap_response.rb +79 -0
- data/lib/rex/proto/kademlia/message.rb +72 -0
- data/lib/rex/proto/kademlia/ping.rb +19 -0
- data/lib/rex/proto/kademlia/pong.rb +41 -0
- data/lib/rex/proto/kademlia/util.rb +22 -0
- data/lib/rex/proto/natpmp/packet.rb +30 -2
- data/lib/rex/proto/quake.rb +3 -0
- data/lib/rex/proto/quake/message.rb +73 -0
- data/lib/rex/proto/smb/client.rb +1 -0
- data/lib/rex/proto/smb/simpleclient.rb +4 -0
- data/lib/rex/proto/sunrpc/client.rb +14 -3
- data/lib/rex/socket/comm/local.rb +10 -7
- data/lib/rex/socket/ssl_tcp_server.rb +79 -40
- data/lib/rex/ui/text/input/readline.rb +33 -6
- data/lib/rex/ui/text/output/file.rb +2 -2
- data/lib/rex/ui/text/output/stdio.rb +70 -14
- data/rex.gemspec +1 -1
- 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 +
|
58
|
-
TLV_TYPE_EXT_ADSI_FILTER = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
59
|
-
TLV_TYPE_EXT_ADSI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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 +
|
66
|
-
TLV_TYPE_EXT_WMI_QUERY = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
67
|
-
TLV_TYPE_EXT_WMI_FIELD = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
68
|
-
TLV_TYPE_EXT_WMI_VALUE = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
69
|
-
TLV_TYPE_EXT_WMI_FIELDS = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
70
|
-
TLV_TYPE_EXT_WMI_VALUES = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
71
|
-
TLV_TYPE_EXT_WMI_ERROR = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS +
|
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.
|
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::
|
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
|
-
|
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,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
|
+
|