Skip to content

Commit 23c9aea

Browse files
committed
Add tests for the new URI schemes
1 parent 70df033 commit 23c9aea

File tree

1 file changed

+97
-1
lines changed

1 file changed

+97
-1
lines changed

spec/lib/msf/core/rhosts_walker_spec.rb

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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 smb module',
166+
'Description' => 'mock smb 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

Comments
 (0)