Merge branch 'wldap32_railgun' of https://github.com/Meatballs1/metasploit-framework into Meatballs1-wldap32_railgun
commit
1e1cbd7445
|
@ -0,0 +1,107 @@
|
|||
# -*- coding: binary -*-
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
module Extensions
|
||||
module Stdapi
|
||||
module Railgun
|
||||
module Def
|
||||
|
||||
class Def_wldap32
|
||||
|
||||
def self.create_dll(dll_path = 'wldap32')
|
||||
dll = DLL.new(dll_path, ApiConstants.manager)
|
||||
|
||||
dll.add_function('ldap_sslinitA', 'DWORD',[
|
||||
['PCHAR', 'HostName', 'in'],
|
||||
['DWORD', 'PortNumber', 'in'],
|
||||
['DWORD', 'secure', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_bind_sA', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['PCHAR', 'dn', 'in'],
|
||||
['PCHAR', 'cred', 'in'],
|
||||
['DWORD', 'method', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_search_sA', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['PCHAR', 'base', 'in'],
|
||||
['DWORD', 'scope', 'in'],
|
||||
['PCHAR', 'filter', 'in'],
|
||||
['PCHAR', 'attrs[]', 'in'],
|
||||
['DWORD', 'attrsonly', 'in'],
|
||||
['PDWORD', 'res', 'out']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_count_entries', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['DWORD', 'res', 'in']
|
||||
])
|
||||
dll.add_function('ldap_first_entry', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['DWORD', 'res', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_next_entry', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['DWORD', 'entry', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_first_attributeA', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['DWORD', 'entry', 'in'],
|
||||
['DWORD', 'ptr', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_next_attributeA', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['DWORD', 'entry', 'in'],
|
||||
['DWORD', 'ptr', 'inout']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_count_values', 'DWORD',[
|
||||
['DWORD', 'vals', 'in'],
|
||||
])
|
||||
|
||||
dll.add_function('ldap_get_values', 'DWORD',[
|
||||
['DWORD', 'ld', 'in'],
|
||||
['DWORD', 'entry', 'in'],
|
||||
['PCHAR', 'attr', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_value_free', 'DWORD',[
|
||||
['DWORD', 'vals', 'in'],
|
||||
])
|
||||
|
||||
dll.add_function('ldap_memfree', 'VOID',[
|
||||
['DWORD', 'block', 'in'],
|
||||
])
|
||||
|
||||
dll.add_function('ber_free', 'VOID',[
|
||||
['DWORD', 'pBerElement', 'in'],
|
||||
['DWORD', 'fbuf', 'in'],
|
||||
])
|
||||
|
||||
dll.add_function('LdapGetLastError', 'DWORD',[])
|
||||
|
||||
dll.add_function('ldap_err2string', 'DWORD',[
|
||||
['DWORD', 'err', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_msgfree', 'DWORD', [
|
||||
['DWORD', 'res', 'in']
|
||||
])
|
||||
|
||||
dll.add_function('ldap_unbind', 'DWORD', [
|
||||
['DWORD', 'ld', 'in']
|
||||
])
|
||||
return dll
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end; end; end; end; end; end; end
|
||||
|
||||
|
|
@ -77,6 +77,7 @@ class Railgun
|
|||
'netapi32',
|
||||
'crypt32',
|
||||
'wlanapi',
|
||||
'wldap32'
|
||||
].freeze
|
||||
|
||||
##
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
##
|
||||
# ## This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'rex'
|
||||
require 'msf/core'
|
||||
require 'msf/core/auxiliary/report'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Gather AD Enumerate Computers',
|
||||
'Description' => %q{
|
||||
This module will enumerate computers in the default AD directory.
|
||||
|
||||
Optional Attributes:
|
||||
objectClass, cn, description, distinguishedName, instanceType, whenCreated,
|
||||
whenChanged, uSNCreated, uSNChanged, name, objectGUID,
|
||||
userAccountControl, badPwdCount, codePage, countryCode,
|
||||
badPasswordTime, lastLogoff, lastLogon, localPolicyFlags,
|
||||
pwdLastSet, primaryGroupID, objectSid, accountExpires,
|
||||
logonCount, sAMAccountName, sAMAccountType, operatingSystem,
|
||||
operatingSystemVersion, operatingSystemServicePack, serverReferenceBL,
|
||||
dNSHostName, rIDSetPreferences, servicePrincipalName, objectCategory,
|
||||
netbootSCPBL, isCriticalSystemObject, frsComputerReferenceBL,
|
||||
lastLogonTimestamp, msDS-SupportedEncryptionTypes
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'Ben Campbell <eat_meatballs[at]hotmail.co.uk>' ],
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptInt.new('MAX_SEARCH', [true, 'Maximum values to retrieve, 0 for all.', 20]),
|
||||
OptBool.new('STORE', [true, 'Store file in loot.', false]),
|
||||
OptString.new('ATTRIBS', [true, 'Attributes to retrieve.', 'dNSHostName,distinguishedName,description,operatingSystem'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def read_value(addr)
|
||||
val_size = client.railgun.memread(addr-4,4).unpack('V*')[0]
|
||||
value = client.railgun.memread(addr, val_size)
|
||||
return value.strip
|
||||
end
|
||||
|
||||
def run
|
||||
unless session.platform == "x64/win64"
|
||||
print_error("Does not work in x86 meterpreter (use x64 instead) see: http://dev.metasploit.com/redmine/issues/7639");
|
||||
return
|
||||
end
|
||||
|
||||
print_status("Connecting to default LDAP server")
|
||||
session_handle = bind_default_ldap_server
|
||||
|
||||
return false unless session_handle
|
||||
|
||||
print_status("Querying default naming context")
|
||||
|
||||
query_result = query_ldap(session_handle, "", 0, "(objectClass=computer)", ["defaultNamingContext"])
|
||||
first_entry_attributes = query_result[0]['attributes']
|
||||
defaultNamingContext = first_entry_attributes[0]['values'] # Value from First Attribute of First Entry
|
||||
|
||||
print_status("Default Naming Context #{defaultNamingContext}")
|
||||
|
||||
attributes = datastore['ATTRIBS'].split(',')
|
||||
|
||||
print_status("Querying computer objects - Please wait...")
|
||||
results = query_ldap(session_handle, defaultNamingContext, 2, "(objectClass=computer)", attributes)
|
||||
|
||||
print_status("Unbinding from LDAP service.")
|
||||
wldap32.ldap_unbind(session_handle)
|
||||
|
||||
results_table = Rex::Ui::Text::Table.new(
|
||||
'Header' => 'AD Computers',
|
||||
'Indent' => 1,
|
||||
'SortIndex' => -1,
|
||||
'Columns' => attributes
|
||||
)
|
||||
|
||||
results.each do |result|
|
||||
row = []
|
||||
|
||||
result['attributes'].each do |attr|
|
||||
if attr['values'].nil?
|
||||
row << ""
|
||||
else
|
||||
row << attr['values']
|
||||
end
|
||||
end
|
||||
|
||||
results_table << row
|
||||
|
||||
end
|
||||
|
||||
print_line results_table.to_s
|
||||
if datastore['STORE']
|
||||
stored_path = store_loot('ad.computers', 'text/plain', session, results_table.to_csv)
|
||||
print_status("Results saved to: #{stored_path}")
|
||||
end
|
||||
end
|
||||
|
||||
def wldap32
|
||||
return client.railgun.wldap32
|
||||
end
|
||||
|
||||
def bind_default_ldap_server
|
||||
vprint_status ("Initializing LDAP connection.")
|
||||
session_handle = wldap32.ldap_sslinitA("\x00\x00\x00\x00", 389, 0)['return']
|
||||
vprint_status("LDAP Handle: #{session_handle}")
|
||||
|
||||
if session_handle == 0
|
||||
print_error("Unable to connect to LDAP server")
|
||||
wldap32.ldap_unbind(session_handle)
|
||||
return false
|
||||
end
|
||||
|
||||
vprint_status ("Binding to LDAP server.")
|
||||
bind = wldap32.ldap_bind_sA(session_handle, nil, nil, 0x0486)['return'] #LDAP_AUTH_NEGOTIATE 0x0486
|
||||
|
||||
if bind != 0
|
||||
print_error("Unable to bind to LDAP server")
|
||||
wldap32.ldap_unbind(session_handle)
|
||||
return false
|
||||
end
|
||||
|
||||
return session_handle
|
||||
end
|
||||
|
||||
def query_ldap(session_handle, base, scope, filter, attributes)
|
||||
vprint_status ("Searching LDAP directory.")
|
||||
search = wldap32.ldap_search_sA(session_handle, base, scope, filter, nil, 0, 4)
|
||||
vprint_status("search: #{search}")
|
||||
|
||||
if search['return'] != 0
|
||||
print_error("No results")
|
||||
wldap32.ldap_msgfree(search['res'])
|
||||
return
|
||||
end
|
||||
|
||||
search_count = wldap32.ldap_count_entries(session_handle, search['res'])['return']
|
||||
|
||||
if(search_count == 0)
|
||||
print_error("No entries retrieved")
|
||||
wldap32.ldap_msgfree(search['res'])
|
||||
return
|
||||
end
|
||||
|
||||
print_status("Entries retrieved: #{search_count}")
|
||||
|
||||
vprint_status("Retrieving results...")
|
||||
|
||||
entries = {}
|
||||
entry_results = []
|
||||
|
||||
if datastore['MAX_SEARCH'] == 0
|
||||
max_search = search_count
|
||||
else
|
||||
max_search = [datastore['MAX_SEARCH'], search_count].min
|
||||
end
|
||||
|
||||
0.upto(max_search - 1) do |i|
|
||||
print '.'
|
||||
|
||||
if(i==0)
|
||||
entries[0] = wldap32.ldap_first_entry(session_handle, search['res'])['return']
|
||||
else
|
||||
entries[i] = wldap32.ldap_next_entry(session_handle, entries[i-1])['return']
|
||||
end
|
||||
|
||||
if(entries[i] == 0)
|
||||
print_error("Failed to get entry.")
|
||||
wldap32.ldap_unbind(session_handle)
|
||||
wldap32.ldap_msgfree(search['res'])
|
||||
return
|
||||
end
|
||||
|
||||
vprint_status("Entry #{i}: #{entries[i]}")
|
||||
|
||||
attribute_results = []
|
||||
attributes.each do |attr|
|
||||
vprint_status("Attr: #{attr}")
|
||||
|
||||
pp_value = wldap32.ldap_get_values(session_handle, entries[i], attr)['return']
|
||||
vprint_status("ppValue: 0x#{pp_value.to_s(16)}")
|
||||
|
||||
if pp_value == 0
|
||||
vprint_error("No attribute value returned.")
|
||||
else
|
||||
count = wldap32.ldap_count_values(pp_value)['return']
|
||||
vprint_status "Value count: #{count}"
|
||||
|
||||
value_results = []
|
||||
if count < 1
|
||||
vprint_error("Bad Value List")
|
||||
else
|
||||
0.upto(count - 1) do |j|
|
||||
p_value = client.railgun.memread(pp_value+(j*4), 4).unpack('V*')[0]
|
||||
vprint_status "p_value: 0x#{p_value.to_s(16)}"
|
||||
value = read_value(p_value)
|
||||
vprint_status "Value: #{value}"
|
||||
if value.nil?
|
||||
value_results << ""
|
||||
else
|
||||
value_results << value
|
||||
end
|
||||
end
|
||||
value_results = value_results.join('|')
|
||||
end
|
||||
end
|
||||
|
||||
if pp_value != 0
|
||||
vprint_status("Free value memory.")
|
||||
wldap32.ldap_value_free(pp_value)
|
||||
# wldap32.ldap_memfree(attr) No need to free attributes as these are hardcoded
|
||||
end
|
||||
|
||||
attribute_results << {"name" => attr, "values" => value_results}
|
||||
end
|
||||
|
||||
entry_results << {"id" => i, "attributes" => attribute_results}
|
||||
end
|
||||
|
||||
print_line
|
||||
return entry_results
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue