PASSWORD_SPRAY not working
msf6 auxiliary(scanner/ldap/ldap_login) > options
Module options (auxiliary/scanner/ldap/ldap_login):
Name Current Setting Required Description
---- --------------- -------- -----------
ANONYMOUS_LOGIN true yes Attempt to login with a blank username and password
BRUTEFORCE_SPEED 5 yes How fast to bruteforce, from 0 to 5
DB_ALL_CREDS false no Try each user/password couple stored in the current database
DB_ALL_PASS false no Add all passwords in the current database to the list
DB_ALL_USERS false no Add all users in the current database to the list
DB_SKIP_EXISTING none no Skip existing credentials stored in the current database (Accepted: none, user, user&realm)
DOMAIN testdomain.com no The domain to authenticate to
PASSWORD no The password to authenticate with
PASS_FILE /opt/rockyou.txt no File containing passwords, one per line
RHOSTS 10.1.1.100 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
RPORT 389 yes The target port
SSL false no Enable SSL on the LDAP connection
STOP_ON_SUCCESS false yes Stop guessing when a credential works for a host
THREADS 1 yes The number of concurrent threads (max one per host)
USERNAME no The username to authenticate with
USERPASS_FILE no File containing users and passwords separated by space, one pair per line
USER_AS_PASS false no Try the username as the password for all users
USER_FILE /root/users.txt no File containing usernames, one per line
VERBOSE true yes Whether to print output for all attempts
When LDAP::Auth is one of auto,plaintext:
Name Current Setting Required Description
---- --------------- -------- -----------
APPEND_DOMAIN true yes Appends `@<DOMAIN> to the username for authentication`
View the full module info with the info, or info -d command.
msf6 auxiliary(scanner/ldap/ldap_login) > set PASSWORD_SPRAY
PASSWORD_SPRAY => true
Results in still hitting users
[-] 10.1.1.100:389 - LOGIN FAILED: username1:123456 (Incorrect: Bind Result: {:extended_response=>nil, :code=>34, :error_message=>"invalid DN", :matched_dn=>"", :message=>"Invalid DN Syntax"})
[-] 10.1.1.100:389 - LOGIN FAILED: [email protected]:123456 (Incorrect: Bind Result: {:extended_response=>nil, :code=>34, :error_message=>"invalid DN", :matched_dn=>"", :message=>"Invalid DN Syntax"})
[-] 10.1.1.100:389 - LOGIN FAILED: username1:12345 (Incorrect: Bind Result: {:extended_response=>nil, :code=>34, :error_message=>"invalid DN", :matched_dn=>"", :message=>"Invalid DN Syntax"})
[-] 10.1.1.100:389 - LOGIN FAILED: [email protected]:12345 (Incorrect: Bind Result: {:extended_response=>nil, :code=>34, :error_message=>"invalid DN", :matched_dn=>"", :message=>"Invalid DN Syntax"})
[-] 10.1.1.100:389 - LOGIN FAILED: username1:123456789 (Incorrect: Bind Result: {:extended_response=>nil, :code=>34, :error_message=>"invalid DN", :matched_dn=>"", :message=>"Invalid DN Syntax"})
[-] 10.1.1.100:389 - LOGIN FAILED: [email protected]:123456789 (Incorrect: Bind Result: {:extended_response=>nil, :code=>34, :error_message=>"invalid DN", :matched_dn=>"", :message=>"Invalid DN Syntax"})
What the log doesn't show is it getting to username2
What's the behavior you were expecting? 👀
msf6 auxiliary(scanner/ldap/ldap_login) > cat users.txt
[*] exec: cat users.txt
user1
vagrant
msf6 auxiliary(scanner/ldap/ldap_login) > cat pass.txt
[*] exec: cat pass.txt
pass1
pass2
pass3
vagrant
pass4
msf6 auxiliary(scanner/ldap/ldap_login) > run rhost=192.168.123.136 user_file=./users.txt pass_file=pass.txt verbose=true password_spray=true domain=demo.local stop_on_success=false
[!] No active DB -- Credential data will not be saved!
[-] 192.168.123.136:389 - LOGIN FAILED: user1:pass1 (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[-] 192.168.123.136:389 - LOGIN FAILED: user1:pass2 (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[-] 192.168.123.136:389 - LOGIN FAILED: user1:pass3 (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[-] 192.168.123.136:389 - LOGIN FAILED: user1:vagrant (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[-] 192.168.123.136:389 - LOGIN FAILED: user1:pass4 (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[-] 192.168.123.136:389 - LOGIN FAILED: vagrant:pass1 (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[-] 192.168.123.136:389 - LOGIN FAILED: vagrant:pass2 (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[-] 192.168.123.136:389 - LOGIN FAILED: vagrant:pass3 (Incorrect: Bind Result: {:extended_response=>nil, :code=>49, :error_message=>"80090308: LdapErr: DSID-0C090569, comment: AcceptSecurityContext error, data 52e, v4f7c\u0000", :matched_dn=>"", :message=>"Invalid Credentials"})
[+] 192.168.123.136:389 - Success: 'vagrant:vagrant'
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf6 auxiliary(scanner/ldap/ldap_login) >
Edit: Race condition between our posts; I see a difference in my error versus yours
I'm assuming /root/users.txt is correctly new line delimited? Running locally on my setup appears to work as you intended - but let me know if I've misunderstood
Regular password brute force attack would try user1 with every password before moving on. Password spraying would try the first password with every user before moving on.
#9634 introduced this option, either ldap_login implementation did not take into account this option or there is some regression.
I think the difference between ldap_login and owa_login (which seems to have been the target for #9634 enhancement) is that one uses each_user_pass while former does not (the latter generates its own set of user/pass sets)
@jmartin-tech what do you think?
Maybe all that is needed is to generate an array of user and pass using combine_users_and_passwords function which based on PASSWORD_SPRAY decides whether to do:
user1:pass2
....
user2:pass1
...
Or
user1:pass1
user2:pass1
...
user1:pass2
user2:pass2
...```
Maybe we can fix each_unfiltered inside lib/metasploit/framework/credential_collection.rb to do this in one centralized place
Though it doesn't seem to have access to the datastore
@mubix try to see if this PR fixes your issue
We might want to remove the deregister found in modules/auxiliary/scanner/ftp/ftp_login.rb
I also tried it with pure-ftpd:
docker run --rm -d --name ftpd_server -p 21:21 -p 30000-30009:30000-30009 stilliard/pure-ftpd bash /run.sh -c 30 -C 10 -l puredb:/etc/pure-ftpd/pureftpd.pdb -E -j -R -P localhost -p 30000:30059
msf6 auxiliary(scanner/ftp/ftp_login) > set
Global
======
No entries in data store.
Module: scanner/ftp/ftp_login
=============================
Name Value
---- -----
ANONYMOUS_LOGIN false
BLANK_PASSWORDS false
BRUTEFORCE_SPEED 5
CHOST
CPORT
ConnectTimeout 30
DB_ALL_CREDS false
DB_ALL_PASS false
DB_ALL_USERS false
DB_SKIP_EXISTING none
FTPDEBUG false
FTPTimeout 16
MaxGuessesPerService 0
MaxGuessesPerUser 0
MaxMinutesPerService 0
PASSWORD
PASSWORD_SPRAY true
PASS_FILE /tmp/passwords.txt
PassiveMode false
Proxies
RECORD_GUEST false
REMOVE_PASS_FILE false
REMOVE_USERPASS_FILE false
REMOVE_USER_FILE false
RHOSTS 127.0.0.1
RPORT 21
SINGLE_SESSION false
SSL false
SSLCipher
SSLServerNameIndication
SSLVerifyMode PEER
SSLVersion Auto
STOP_ON_SUCCESS false
ShowProgress true
ShowProgressPercent 10
TCP::max_send_size 0
TCP::send_delay 0
THREADS 1
TRANSITION_DELAY 0
USERNAME
USERPASS_FILE
USER_AS_PASS false
USER_FILE /tmp/users.txt
VERBOSE true
WORKSPACE
msf6 auxiliary(scanner/ftp/ftp_login) > run
[*] 127.0.0.1:21 - 127.0.0.1:21 - Starting FTP login sweep
[!] 127.0.0.1:21 - No active DB -- Credential data will not be saved!
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user1:password1 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user2:password1 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user3:password1 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user1:password2 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user2:password2 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user3:password2 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user1:password3 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user2:password3 (Incorrect: )
[-] 127.0.0.1:21 - 127.0.0.1:21 - LOGIN FAILED: user3:password3 (Incorrect: )
[*] 127.0.0.1:21 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
@mubix there is a PR in the works, can you look into it? and see if it is what you expected?
@nrathaus Fix worked for me thanks!
This is wired up now for the other modules - not just ldap, extra PRs: https://github.com/rapid7/metasploit-framework/pull/19158 and https://github.com/rapid7/metasploit-framework/pull/19156 :+1: