@@ -22,7 +22,8 @@ def http_options_for(datastores)
2222 mysql_keys = %w[ RHOSTS RPORT USERNAME PASSWORD ]
2323 postgres_keys = %w[ RHOSTS RPORT USERNAME PASSWORD DATABASE ]
2424 ssh_keys = %w[ RHOSTS RPORT USERNAME PASSWORD ]
25- required_keys = dynamic_keys + http_keys + smb_keys + mysql_keys + postgres_keys + ssh_keys
25+ ldap_keys = %w[ RHOSTS RPORT SSL LDAPDomain LDAPUsername LDAPPassword BASE_DN ]
26+ required_keys = dynamic_keys + http_keys + smb_keys + mysql_keys + postgres_keys + ssh_keys + ldap_keys
2627 datastores . map do |datastore |
2728 # Workaround: Manually convert the datastore to a hash ourselves as `datastore.to_h` coerces all datatypes into strings
2829 # which prevents this test suite from validating types correctly. i.e. The tests need to ensure that RPORT is correctly
@@ -154,6 +155,33 @@ def initialize
154155 mod
155156 end
156157
158+ let ( :ldap_mod ) do
159+ mod_klass = Class . new ( Msf ::Auxiliary ) do
160+ include Msf ::Exploit ::Remote ::LDAP
161+ include Msf ::Exploit ::Remote ::LDAP ::Queries
162+
163+ def initialize
164+ super (
165+ 'Name' => 'mock ldap module' ,
166+ 'Description' => 'mock ldap module' ,
167+ 'Author' => [ 'Unknown' ] ,
168+ 'License' => MSF_LICENSE
169+ )
170+
171+ register_options ( [
172+ Msf ::OptString . new ( 'BASE_DN' , [ false , 'LDAP base DN if you already have it' ] )
173+ ] )
174+ end
175+ end
176+
177+ mod = mod_klass . new
178+ datastore = Msf ::ModuleDataStore . new ( mod )
179+ allow ( mod ) . to receive ( :framework ) . and_return ( nil )
180+ mod . send ( :datastore= , datastore )
181+ datastore . import_options ( mod . options )
182+ mod
183+ end
184+
157185 let ( :mysql_mod ) do
158186 mod_klass = Class . new ( Msf ::Auxiliary ) do
159187 include Msf ::Exploit ::Remote ::MYSQL
@@ -908,6 +936,74 @@ def create_tempfile(content)
908936 expect ( each_host_for ( ssh_mod ) ) . to have_datastore_values ( expected )
909937 end
910938 end
939+
940+ context 'when using the ldap scheme' do
941+ it 'enumerates ldap schemes for scanners when no user or password are specified' do
942+ ldap_mod . datastore [ 'RHOSTS' ] = 'ldap://example.com/ ldaps://example.com/'
943+ expected = [
944+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => nil , 'LDAPUsername' => nil , 'LDAPPassword' => nil , 'BASE_DN' => nil } ,
945+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 636 , 'SSL' => true , 'LDAPDomain' => nil , 'LDAPUsername' => nil , 'LDAPPassword' => nil , 'BASE_DN' => nil }
946+ ]
947+ expect ( each_host_for ( ldap_mod ) ) . to have_datastore_values ( expected )
948+ end
949+
950+ it 'enumerates ldap schemes for scanners when a port is specified' do
951+ ldap_mod . datastore [ 'RHOSTS' ] = 'ldap://example.com:1389/ ldaps://example.com:1636/'
952+ expected = [
953+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 1389 , 'SSL' => false , 'LDAPDomain' => nil , 'LDAPUsername' => nil , 'LDAPPassword' => nil , 'BASE_DN' => nil } ,
954+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 1636 , 'SSL' => true , 'LDAPDomain' => nil , 'LDAPUsername' => nil , 'LDAPPassword' => nil , 'BASE_DN' => nil }
955+ ]
956+ expect ( each_host_for ( ldap_mod ) ) . to have_datastore_values ( expected )
957+ end
958+
959+ it 'enumerates ldap schemes for scanners when no user or password are specified and uses the default option values instead' do
960+ ldap_mod . datastore . import_options (
961+ Msf ::OptionContainer . new (
962+ [
963+ Msf ::OptString . new ( 'LDAPUsername' , [ true , 'The username to authenticate as' , 'db2admin' ] , fallbacks : [ 'USERNAME' ] ) ,
964+ Msf ::OptString . new ( 'LDAPPassword' , [ true , 'The password for the specified username' , 'db2admin' ] , fallbacks : [ 'PASSWORD' ] ) ,
965+ ]
966+ ) ,
967+ ldap_mod . class ,
968+ true
969+ )
970+ ldap_mod . datastore [ 'RHOSTS' ] = 'ldap://example.com/ ldap://[email protected] / ldap://user:[email protected] ldap://:@example.com' 971+ expected = [
972+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => nil , 'LDAPUsername' => 'db2admin' , 'LDAPPassword' => 'db2admin' , 'BASE_DN' => nil } ,
973+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => '' , 'LDAPUsername' => 'user' , 'LDAPPassword' => 'db2admin' , 'BASE_DN' => nil } ,
974+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => '' , 'LDAPUsername' => 'user' , 'LDAPPassword' => 'password' , 'BASE_DN' => nil } ,
975+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => '' , 'LDAPUsername' => '' , 'LDAPPassword' => '' , 'BASE_DN' => nil }
976+ ]
977+ expect ( each_host_for ( ldap_mod ) ) . to have_datastore_values ( expected )
978+ end
979+
980+ it 'enumerates ldap schemes for scanners when a user and password are specified' do
981+ ldap_mod . datastore [ 'RHOSTS' ] = 'ldap://user:[email protected] /' 982+ expected = [
983+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => '' , 'LDAPUsername' => 'user' , 'LDAPPassword' => 'pass' , 'BASE_DN' => nil } ,
984+ ]
985+ expect ( each_host_for ( ldap_mod ) ) . to have_datastore_values ( expected )
986+ end
987+
988+ it 'enumerates ldap schemes for scanners when a domain, user and password are specified' do
989+ ldap_mod . datastore [ 'RHOSTS' ] = 'ldap://domain;user:[email protected] /' 990+ expected = [
991+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => 'domain' , 'LDAPUsername' => 'user' , 'LDAPPassword' => 'pass' , 'BASE_DN' => nil } ,
992+ ]
993+ expect ( each_host_for ( ldap_mod ) ) . to have_datastore_values ( expected )
994+ end
995+
996+ it 'enumerates ldap schemes for when the module has BASE_DN available' do
997+ ldap_mod . datastore [ 'RHOSTS' ] = 'ldap://[email protected] ldap://[email protected] / ldap://[email protected] /dc=msflab,dc=local' 998+ expected = [
999+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => '' , 'LDAPUsername' => 'user' , 'LDAPPassword' => nil , 'BASE_DN' => nil } ,
1000+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => '' , 'LDAPUsername' => 'user' , 'LDAPPassword' => nil , 'BASE_DN' => nil } ,
1001+ { 'RHOSTNAME' => 'example.com' , 'RHOSTS' => '192.0.2.2' , 'RPORT' => 389 , 'SSL' => false , 'LDAPDomain' => '' , 'LDAPUsername' => 'user' , 'LDAPPassword' => nil , 'BASE_DN' => 'dc=msflab,dc=local' }
1002+ ]
1003+ expect ( each_host_for ( ldap_mod ) ) . to have_datastore_values ( expected )
1004+ end
1005+ end
1006+
9111007 # TODO: Discuss adding a test for the datastore containing an existing TARGETURI,and running with a HTTP url without a path. Should the TARGETURI be overridden to '/', '', or unaffected, and the default value is used instead?
9121008
9131009 it 'enumerates a combination of all syntaxes' do
0 commit comments