A Quick Few Points
- There are lots of CTFs and vulnerable boxes out there. One post is not going to cover every possible scenario, avenue, or approach.
- I do not proclaim to be the best at CTFs or vulnerable boxes. There is and will always be someone more skilled than me. But, I am motivated, curious, and very good at using Google.
- The more practice you get with a wide variety of targets, the better you'll get at finding patterns and forging your own methodology. At first, you'll likely mimic others' patterns, but will do so less as you get more practice.
Step 1. Nmap Scan
As is the case with most vulnerable boxes, we begin assessing the target by running a nmap scan to understand the following:
- What is running on the target, what server names, what versions?
- What client software would we need to connect and assess the target?
nmap -hNmap help message output
sudo nmap -Pn -p- -sC -sV -T4 -oN nmap-scan.txt <target_ip>Slower, but more reliable
sudo nmap -Pn -p- -sC -sV --min-rate 5000 -oN nmap-scan.txt <target_ip>Faster, target may drop packets, adjust the '--min-rate' if needed
sudo nmap -Pn -sU -sV -T3 --top-ports 25 -oN udp-nmap-scan.txt <target_ip>UDP scan example using '-T4', as going too fast may miss ports
nmap scan! There's a lot of good information here to take note of.Using the example nmap syntax above, this is going to run:
- Service version scan
- OS detection
- Default script scan
Example Nmap Output
Nmap Scan of Vulnhub Funbox: 1
PORT STATE SERVICE VERSION
21/tcp open ftp ProFTPD 1.3.3c
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 a6:0e:30:35:3b:ef:43:44:f5:1c:d7:c6:58:64:09:92 (RSA)
| 256 c2:d8:bd:62:bf:13:89:28:f8:61:e0:a6:c4:f7:a5:bf (ECDSA)
|_ 256 12:60:6e:58:ee:f2:bd:9c:ff:b0:35:05:83:08:71:b8 (ED25519)
25/tcp open smtp Postfix smtpd
|_smtp-commands: funbox11, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-generator: WordPress 5.7.2
|_http-title: Funbox: Scriptkiddie
|_http-server-header: Apache/2.4.18 (Ubuntu)
110/tcp open pop3 Dovecot pop3d
|_pop3-capabilities: RESP-CODES UIDL TOP SASL CAPA PIPELINING AUTH-RESP-CODE
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
143/tcp open imap Dovecot imapd
|_imap-capabilities: LOGINDISABLEDA0001 Pre-login more post-login have ENABLE LOGIN-REFERRALS SASL-IR capabilities IMAP4rev1 listed IDLE ID OK LITERAL+
445/tcp open 0�>_y Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94%E=4%D=7/22%OT=21%CT=1%CU=39079%PV=Y%DS=2%DC=T%G=Y%TM=64BB5A4
OS:8%P=x86_64-pc-linux-gnu)SEQ(SP=104%GCD=1%ISR=105%TI=Z%II=I%TS=8)SEQ(SP=1
OS:04%GCD=3%ISR=105%TI=Z%II=I%TS=8)OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B
OS:4NNT11NW7%O4=M5B4ST11NW7%O5=M5B4ST11NW7%O6=M5B4ST11)WIN(W1=7120%W2=7120%
OS:W3=7120%W4=7120%W5=7120%W6=7120)ECN(R=Y%DF=N%T=40%W=7210%O=M5B4NNSNW7%CC
OS:=Y%Q=)T1(R=Y%DF=N%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=N)T5(R=Y
OS:%DF=N%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=N)T7(R=N)U1(R=Y%DF=N%T=40%I
OS:PL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
Network Distance: 2 hops
Service Info: Hosts: funbox11, FUNBOX11; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
| Computer name: funbox11
| NetBIOS computer name: FUNBOX11\x00
| Domain name: \x00
| FQDN: funbox11
|_ System time: 2023-07-22T06:24:33+02:00
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-time:
| date: 2023-07-22T04:24:33
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
|_clock-skew: mean: -39m59s, deviation: 1h09m16s, median: 0s
|_nbstat: NetBIOS name: FUNBOX11, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
Breadcrumbs
Even running the default nmap scripts can reveal a good deal of information about the services running on the target. There are additional enum and brute scripts that often don't get run as a default scan.
Make sure you carefully look over the nmap script scan output, as this can have details such as:
- FTP file enumeration
- NFS share names
- HTTP robots.txt and redirects
- DNS names
- Emails
- Computer names
- OS versions
- And, much more
Open Ports
Identifying Services
Using the example nmap scan output from above, we can see that nmap was able to pull service banners for all open ports that it could connect to.
21/tcp open ftp ProFTPD 1.3.3c
^ ^ ^ ^
| | | '----------- Application and version (banner)
| | |
| | '----------------- Well-known service
| |
| '------------- Port state
|
'----------- Port number
and Transport protocolYou can find a list of well-known services that nmap tracks at /usr/share/nmap/nmap-services. It's this database that allows nmap to assume the service type running a particular port.
Take note of all the services running on the target and the version numbers of said services. By looking at the services, you'll also know which client software you'll need to do some manual testing. Based on the example nmap output above, we know we'll possibly need:
- FTP client
- SSH client
- SMTP / POP3 (mail) client
- HTTP (web) client
- SMB client
No Service Banners?
5040/tcp open unknownExample of an open, but unknown service
What if nmap was able to connect to the port, but was unable to pull a service name and version from the port? There could be various reasons for this, some of the most common being:
- The port was opened on the box in an attempt to trick you
- The port is coupled with another service and doesn't reveal banners
- The service running on the port may be malfunctioning
You can try to manually pull banners from the service, but in all likelihood, you'll just have to move on:
nc -nv <target-ip> <target-port>Try netcat with verbose output, press 'Enter' a couple times to see if there's any output
Cataloging Possible Exploits
When I want to get an idea of any public exploits that might be available for any service(s), I will typically search on Google or Exploit Database.
- Google:
ProFTPD 1.3.3c exploitProFTPD 1.3.3c exploit site:github.com
- Exploit Database:
- Command Line:
searchsploit ProFTPD 1.3.3c - Web: https://www.exploit-db.com/
- Command Line:
In the case of a CTF, a Denial of Service exploit wouldn't do us much good, but a Command Execution or File Inclusion exploit would be very interesting.
Step 2. Service Enumeration
Active Directory Specific
Check the Port Signature
PORT STATE SERVICE
53/tcp open domain
88/tcp open kerberos-sec
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPsslA typical port signature for an Active Directory domain controller, especially apparent due to DNS, SMB, Kerberos, and LDAP being open on the box
Identify the Local Domain
Next, we should check the nmap output for the RootDSE and any potential hostname (e.g. DC01.domain.tld). Once, established, we should add the domain and hostname to our /etc/hosts file.
target_ip='10.10.10.22'
sudo nmap -Pn --script ldap-rootdse.nse $target_ip | grep -E 'dnsHostName|defaultNamingContext' | sort -uIf you've only run a basic nmap scan and need to enumerate the RootDSE
target_ip='10.10.10.22'
target_domain='domain.tld'
target_hostname="DC01.${target_domain}"
echo -e "${target_ip}\t\t${target_hostname} ${target_domain}" | sudo tee -a /etc/hostsRun these commands to populate your /etc/hosts file. FQDN and then, shortname.
DNS
If we've established the local domain for the Active Directory environment, we should attempt to enumerate any DNS records for use when assessing other protocols.
target_ip='10.10.10.22'
target_domain='domain.tld'
host -T -l $target_domain $target_ipAttempt a zone transfer from the DNS server on the target. If configured correctly, the zone transfer should be refused.
target_ip='10.10.10.22'
target_domain='domain.tld'
dns_wordlist='/usr/share/seclists/Discovery/DNS/namelist.txt'
gobuster dns -r $target_ip -d $target_domain -w $dns_wordlist -t 100If the zone transfer fails, you can try and manually enumerate records in the target domain
LDAP
A quick win would be the ability to enumerate LDAP records anonymously, as this would allow us to gather a great deal of information about interesting users, groups, and other domain records.
target_domain='domain.tld'
target_hostname="DC01.${target_domain}"
domain_component=$(echo $target_domain | tr '\.', '\n' | xargs -I % echo "DC=%" | paste -sd, -)
ldapsearch -x -H ldap://$target_hostname -b $domain_componentIf configured correctly, you should see an error saying that a successful bind must be completed, meaning you need a credential
ldapsearch -x -H ldap://$target_hostname -b $domain_component 'objectClass=*'However, if you are able to anonymously query LDAP, this is an example command to pull everything from LDAP

More example commands here
SMB
If we can connect to SMB anonymously, it's worth checking to see if we can enumerate object RIDs anonymously as well. RID cycling would allow us to enumerate a list of users and groups on the computer for further use during testing.
target_ip='10.10.10.22'
smbclient -N -L //$target_ipIf you can connect to SMB with a null session (and maybe even list shares), we can try and enumerate more and potentially map shares
smbclient -N //$target_ip/share_nameConnect to a SMB share via null session
# nxc replaces crackmapexec
nxc smb $target_ip -u 'anonymous' -p '' --rid-brute 3000
nxc smb $target_ip -u '' -p '' --rid-brute 3000If configured correctly, you should see a permissions error, indicating the tests have failed
Kerberos
If you haven't yet managed to compile a list of users from one of the other methods above, we can attempt to use Kerberos pre-authentication and a word list to find usernames.
If we've found some usernames, we can then see if any of them are configured with UF_DONT_REQUIRE_PREAUTH, pull some AS-REP hashes, and attempt to crack them offline.

This will take a while to run depending on the word list used. If valid usernames are found, they will be saved to a log file.
- Extract the usernames from the
kerbrutelog - Test for AS-REP hashes and attempt to crack them
- If you manage to crack an AS-REP hash, spray the password around and see what you can access (or at a minimum, enumerate LDAP or Remote BloodHound)
General Procedure
This is my generalized approach to every target:
- File servers
- Web servers
- Everything else
I do it this way, because I work my way up by level of effort and amount of time involved to enumerate these services.
- File servers are quick and easy to assess, requiring only a widely available client
- Web servers require more work and enumeration due to more complex configurations that are possible on the server
- Everything else comes last when the first two aren't available or they haven't yielded enough info
1. File servers — FTP/SMB
- May allow anonymous access or may be configured with default credentials
- This is an excellent opportunity to gather more information from files
- Additional information may include usernames, passwords, config files, etc
- This information maybe useful when assessing other services
2. Web — HTTP/HTTPS
- Web is just as simple as opening your web browser
- Navigate to the target IP or domain name and just start clicking around
- Make a note of potential input points that could be abused
- Web pages may contain usernames, passwords, interesting source code, etc
3. Everything else
- Start probing other ports, try to understand how they behave
- Lots of Googling, probably something on HackTricks about it
- Try other
nmapscans to see if additional ports are revealed; UDP or X-Mas scans, for example.
DNS — UDP/53 & TCP/53
I'm putting this one at the top — above file servers — because this is one of those easy things you can try that can be potentially high-impact.
If you found — for example — in your nmap scan that a web server had a TLS certificate with a commonName=mysite.test and there is a DNS server running, you should test to see if a zone transfer is possible.
target_domain='mysite.test'
target_ip='10.10.100.44'
host -T -l $target_domain $target_ipUsing the host command -l requests a zone transfer
If the zone transfer is successful, you could potentially reveal additional HTTP server names to assess later.
target_ip='10.10.100.44'
target_domain='mysite.test'
dns_wordlist='/usr/share/seclists/Discovery/DNS/namelist.txt'
gobuster dns -r $target_ip -d $target_domain -w $dns_wordlist -t 100If the zone transfer fails, you can try and manually enumerate records in the target domain
gobuster dns scan is running, go ahead and start your tests on other ports.FTP — TCP/21
ftp anonymous@10.10.100.44Check for anonymous FTP access on the target
When prompted for a password, simply press the Enter key and see if it will allow you to login. If it does, try the following:
lsto list files on the servergetto retrieve files on the serverlessormoreto read files from the FTP shellcdto change into any potential directoriesputto test write permissions as a way to perhaps chain an exploit with another service
We're trying to uncover:
- Usernames
- Passwords
- Configuration files
- Source code
- Backups
- Anything interesting
If there's a lot of files and folders, you could do a recursive download and parse the files locally.
SMB — TCP/139 & TCP/445
List Shares
smbclient -N -L //10.10.100.44No username specified, and '-N' for passwordless authentication
If you are able to anonymously list shares, then there's a decent chance you may be able to map shares.
Shares that aren't interesting from a files perspective are, for example:
IPC$print$
Mapping Shares
smbclient -N //10.10.100.44/myshareMap the 'myshare' share anonymously
If you are able to map the share anonymously, try the following:
lsto list files on the servergetto retrieve files on the serverlessormoreto read files from the SMB shellcdto change into any potential directoriesputto test write permissions as a way to perhaps chain an exploit with another service
Like FTP, we're trying to discover anything interesting. If there's a lot of files and folders, you could do a recursive download and parse the files locally.
HTTP — TCP/80 & TCP/443
Initial Questions
The first things I want to establish with the web service are:
- Are there any noticeable differences between the
http://and thehttps://versions of the apps running on the web server? In other words, ishttp://redirecting tohttps://, are they duplicates, or are they completely different in behavior and presentation? - Is the server making use of any
ServerName(virtual host) directives that would cause different pages to load depending on the the hostname the client requests?
Test the Raw IP Address
http://10.10.100.44https://10.10.100.44
- If the server loads different content at each unique scheme
- There are distinct configurations per port
- Plan on testing the servers independently
- If the server redirects
TCP/80toTCP/443- Only need to test
TCP/443(https)
- Only need to test
Testing Virtual Hosts

The Host header is what the server is looking at to determine which virtual host configuration to serve content from. If you're interested in learning more about enumerating virtual hosts, you can see my notes here.
We can create a local name resolution entry by editing our /etc/hosts file, adding the DNS names we saw in the nmap output or any successful zone transfer.
sudo nano /etc/hostsEdit the /etc/hosts file
# Custom Entry
10.10.100.44 mysite.test dev.mysite.test admin.mysite.testAdd these hostnames pointing to '10.10.100.44'
Again, as before, test the server names against both HTTP and HTTPS and see if there are any behavioral differences.
http://mysite.testandhttps://mysite.testhttp://dev.mysite.testandhttps://dev.mysite.testhttp://admin.mysite.testandhttps://admin.mysite.test
- If different domain names load the same content
- No difference in page content between
http://mysite.testandhttp://subdomain.mysite.test - Safe to assume no virtual hosts are being used
- You can most likely test the server using the raw IP address
- No difference in page content between
- If different domain names load unique content
https://mysite.testandhttps://subdomain.mysite.testload completely different pages- More than likely this server is using virtual hosts
- Test each virtual host as an individual server
Walking the Application

At this stage, we just want to use the web page as a normal user would.
- Not doing anything malicious
- Click links and provide expected inputs in standard fields
- Doing things that a normal user would expectedly do
- Navigating to the URLs we've discovered at this point
- Raw IP addresses
- Domain names
- HTTP/HTTPS
- Just click around on links and interact
- Enter input as a normal user would
- Sign up for an account and view the application as an authenticated user
- Trying to understand the application behavior
Checking the Page Source
- Press
CTRL + U - Check the page source for any servers that need to be tested
- Raw IP address
- Domain names
- HTTP/HTTPS
- Look for anything interesting visible client side
- Typically in the HTML comments
- Usernames
- Passwords
- Directory names
- File names
- Etc
Check for Robots and Sitemap
http://10.10.100.44/robots.txtorhttps://mysite.test/robots.txthttps://10.10.100.44/sitemap.xmlorhttps://mysite.test/sitemap.xmlrobots.txtandsitemap.xmldirect legitimate web crawlers and search engines- They're only effective to the extent bots respect them
- Can also reveal some interesting and sensitive directories or pages
robots.txtmay show an entry for the/admindirectory or similar- A legitimate web crawler respects this and does not crawl the directory
- Malicious users will see this an opportunity to explore
Directory and File Enumeration
- Interesting files and directories may be "hidden" or not directly exposed
- We can send a series of HTTP requests to determine if a file or directory exists
HTTP 20xandHTTP 30xresponses would be interestingHTTP 403could be interesting from the perspective of, "What are we NOT allowed to access?"
- I typically use
gobusterorferoxbuster - Choose whichever tool is most comfortable for you
gobuster dir -u http://10.10.100.44 -w /usr/share/seclists/Discovery/Web-Content/directory-list-big.txt -x php,html -t 100 -o gobuster80.txtHTTP enumeration
gobuster dir -k -u https://dev.mysite.test -w /usr/share/seclists/Discovery/Web-Content/big.txt -x php,html -t 100 -o gobuster443.txtHTTPS domain-specific enumeration example
- These enumeration scans could reveal:
- "Hidden" pages or pages with unintended access
- Path-based applications such as CMS (eg. WordPress or Drupal)
- Blogs or CMS platforms may be unpatched or use unpatched plugins
- Should check the version numbers for public exploits
wp-scancan be helpful when enumerating WordPress
Testing the Application
By now, you should have plenty of places to begin looking for potential vulnerabilities with the web applications running on the server.
You want to begin testing the web applications at various points:
- Vulnerable service or plugin versions
- URL parameters
- Login forms
- Search fields
- File uploads
- Etc.
And, you could test for things like:
- Path traversal
- Local and/or remote file inclusion
- Content type filter bypass
- SQL injection
- Default credentials
- Credential stuffing
- Password spraying
- Much, much more
Unknown Ports and Services
Sometimes you will see uncommon services, uncommon port bindings, and high-number port bindings on certain CTF targets. The key here is being able to tell the difference between:
- An uncommon or high port bound to a service
- Often included by CTF authors to confuse you
- A dynamic port bound to something like RPC
- Just part of the operating system or another service like NFS
Fortunately, nmap does a good job of identifying services bound to ports, except for when it can't grab service banners from the port. So, you should be able to identify RPC from other port bindings with ease.
Examples
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49156/tcp open msrpc Microsoft Windows RPC- Very common to see on Windows targets
- These are dynamic RPC port bindings and can typically be ignored
2869/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
5357/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
10243/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)- These port bindings aid in network device discovery
- Can typically be ignored
8080/tcp open http Apache httpd 2.4.52 ((Ubuntu))- This is a very typical alternate HTTP port binding
- Explore this further if prior testing has been unsuccessful
5040/tcp open unknown- Showing an example of nmap failing to detect a service
- I would completely ignore this port unless everything else failed
- If you decide to probe this further, try:
- Manually grabbing a service banner using
netcatortelnet - Open Wireshark and interact with the service and inspect the packets
- Manually grabbing a service banner using
PORT STATE SERVICE VERSION
8014/tcp open http Apache httpd
60000/tcp open http Apache httpd 2.4.38nmaphas identified these as alternative Apache HTTP server bindings- Given the odd port numbers, I'd typically spend little time probing these until later
- You could use
curlor your browser to open them up briefly and see what they look like, but do so much later after testing more common services
PORT STATE SERVICE VERSION
1883/tcp open mqtt- An example of an atypical service you could see on a box
- When you encounter a new service for the first time, search on Google
- You could search something like:
tcp 1883 mqtt pentest - HackTricks often has excellent articles on getting you started with testing services with which you may be unfamiliar

PORT STATE SERVICE VERSION
2222/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)- An example of an atypical SSH server binding
- The same SSH principles apply to this server as well
- Do not try and pentest this service early on, just ignore it initially
- If you come across a SSH key or a username and password later, that would be a good time to test those credentials on something like this
Information Re-Use
If you've discovered useful information while probing HTTP or some other service, you should always consider how this information may be able to be used with services you previously looked at.
For example, maybe you found:
- Usernames and/or passwords
- SSH private keys
- Wordlists
- Backups
Can any of this be used to go back and get more information from another service?
Step 3. Exploit
By now, you should have plenty of information and a very educated guess about the potential exploit you're planning to use against the target.
You may end up using a publicly available exploit or you may end up chaining multiple vulnerabilities together. For example, you may have a FTP file upload and local file inclusion chained exploit to get a reverse shell.
Step 4. Post-Exploit Enumeration and Privilege Escalation
Congratulations! You've got a shell on the target and you're probably full of adrenaline. Now's the time keep a level head and methodically enumerate the target environment to plot the path to full system ownership.
Another thing to keep in mind is to go back and check the configuration files for the service you got your initial shell on.
For example, if you got your reverse shell via a web app such as WordPress, once you've got your shell established, check the wp-config.php file for things like database credentials. The password may be re-used on another user account or you may be able to authenticate the database and find more usernames and hashes to crack.
Post-Exploit Enumeration
At this phase, we want to take inventory of the environment. We want to get a lay of the land and figure out as much as we can before we start attacking anything internally.
You can find the most up-to-date list of post-exploit enumeration tricks here:
Operating Environment
OS & Kernel
-
Windows
systeminfoorGet-ComputerInfoorreg.exe query 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion'to print system overview- Check environment variables:
- CMD:
set - PowerShell:
Get-ChildItem Env:\
- CMD:
-
*nix
uname -ato print kernel informationcat /etc/os-releaseto print OS release information- Check environment variables:
envorset
Current User
-
Windows
whoami /allto list:- Username
- Group memberships
- Privileges
-
*nix
idto list username and group membershipssudo -lto checksudopermissions
Users and Groups
Local Users
-
Windows
net userorGet-LocalUserto list usersnet user <username>orGet-LocalUser <username> | Select-Object *to enumerate details about specific users- Can you dump and pass/crack hashes from SAM using your current access?
-
*nix
cat /etc/passwdto list users
Local Groups
Document here any interesting group(s) after running the below commands:
-
Windows
net localgrouporGet-LocalGroupto list groupsnet localgroup <group_name>orGet-LocalGroupMember <group_name> | Select-Object *to enumerate users of specific groups
-
*nix
cat /etc/groupcat /etc/group | grep <username>to check group memberships of specific users
Domain Users (if domain-joined)
Document here any interesting username(s) after running the below commands:
-
Windows
net user /domainorGet-ADUser -Filter * -Properties *outputnet user <username> /domainorGet-ADUser -Identity <username> -Properties *to enumerate details about specific domain users- Not a local administrator and can't run PowerShell AD cmdlets?
- Can you dump and pass/crack local user/admin hashses from SAM using your current access?
- Can you dump and pass/crack hashes from LSA using your current access?
- Any deleted objects in AD?
Get-ADObject -IncludeDeletedObjects -Filter 'Deleted -eq $true'- Can you restore them?
Get-ADObject -IncludeDeletedObjects -Filter 'Deleted -eq $true' | Restore-ADObject
- Re-run BloodHound. Does this open any new attack paths?
-
*nix
-
Check if joined to a domain
/usr/sbin/realm list -a/usr/sbin/adcli info <realm_domain_name>
-
No credential:
-
Check for log entries containing possible usernames
-
find /var/log -type f -readable -exec grep -ail '<realm_domain_name>' {} \; 2>/dev/null -
Then, grep through each log file and remove any garbage from potential binary files:
- Using strings:
strings /var/log/filename | grep -i '<realm_domain_name>' - If strings not available, try using od:
od -An -S 1 /var/log/filename | grep -i '<realm_domain_name>' - If od not available, try grep standalone:
grep -iao '.*<realm_domain_name>.*' /var/log/filename
- Using strings:
-
Validate findings:
- Check if discovered usernames are valid:
getent passwd <domain_username> - If valid, check user group memberships: List
id <domain_username>
- Check if discovered usernames are valid:
-
Check domain password and lockout policy for password spray feasibility
-
-
See
Domain Groups, as certain commands there can reveal some additional usernames
-
-
With a domain credential:
- If you have a valid domain user credential, you can try
ldapsearch - Dump all objects from LDAP:
ldapsearch -x -H ldap://dc-ip-here -D 'CN=username,DC=realmDomain,DC=realmTLD' -W -b 'DC=realmDomain,DC=realmTLD' 'objectClass=*' - Dump all users from LDAP:
ldapsearch -x -H ldap://dc-ip-here -D 'CN=username,DC=realmDomain,DC=realmTLD' -W -b 'DC=realmDomain,DC=realmTLD' 'objectClass=account'
- If you have a valid domain user credential, you can try
-
If you're root on the domain-joined host:
-
You can try best-effort dumping the SSSD cache:
- Using strings:
strings /var/lib/sss/db/cache_<realm_domain_name>.ldb | grep -iE '[ou|cn]=.*user.*' | grep -iv 'disabled' | sort -u - If strings not available, try using od:
od -An -S 1 /var/lib/sss/db/cache_<realm_domain_name>.ldb | grep -iE '[ou|cn]=.*user.*' | grep -iv 'disabled' | sort -u - If od not available, try grep standalone:
grep -iao '.*<realm_domain_name>.*' /var/lib/sss/db/cache_<realm_domain_name>.ldb | sed 's/[^[:print:]\r\t]/\n/g' | grep -iE '[ou|cn]=.*user.*' | grep -iv disabled
- Using strings:
-
You can transfer the SSSD TDB cache for local parsing
- Default file path:
/var/lib/sss/db/cache_<realm_domain_name>.tdb - You can dump this file with tools such as
tdbtoolortdbdump
- Default file path:
-
-
Domain Groups (if domain-joined)
Document here any interesting group(s) after running the below commands:
-
Windows
net group /domainorGet-ADGroup -Filter * -Properties *outputnet group <group_name> /domainorGet-ADGroup -Identity <group_name> | Get-ADGroupMember -Recursiveto enumerate members of specific domain groups- Not a local administrator and can't run PowerShell AD cmdlets?
- Any deleted objects in AD?
Get-ADObject -IncludeDeletedObjects -Filter 'Deleted -eq $true'- Can you restore them?
Get-ADObject -IncludeDeletedObjects -Filter 'Deleted -eq $true' | Restore-ADObject
- Re-run BloodHound. Does this open any new attack paths?
-
*nix
-
Check if joined to a domain
/usr/sbin/realm list -a/usr/sbin/adcli info <realm_domain_name>
-
No credential:
-
Enumerate default Active Directory security groups: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-groups#default-active-directory-security-groups
getent group 'Domain Admins@<realm_domain_name>'getent group 'Domain Users@<realm_domain_name>'- NOTE:
getentwill only return domain group members that have been cached on the local system, not all group members in the domain - This can still build a substantial user list for password spraying (check domain password and lockout policy)
-
-
With a domain credential:
- If you have a valid domain user credential, you can try
ldapsearch - Dump all objects from LDAP:
ldapsearch -x -H ldap://dc-ip-here -D 'CN=username,DC=realmDomain,DC=realmTLD' -W -b 'DC=realmDomain,DC=realmTLD' 'objectClass=*' - Dump all groups from LDAP:
ldapsearch -x -H ldap://dc-ip-here -D 'CN=username,DC=realmDomain,DC=realmTLD' -W -b 'DC=realmDomain,DC=realmTLD' 'objectClass=group'
- If you have a valid domain user credential, you can try
-
If you're root on the domain-joined host:
-
You can try dumping the SSSD cache:
- Using strings:
strings /var/lib/sss/db/cache_<realm_domain_name>.ldb | grep -i '<realm_domain_name>' - If strings not available, try using od:
od -An -S 1 /var/lib/sss/db/cache_<realm_domain_name>.ldb | grep -i '<realm_domain_name>' - If od not available, try grep standalone:
grep -iao '.*<realm_domain_name>.*' /var/lib/sss/db/cache_<realm_domain_name>.ldb | sed 's/[^[:print:]\r\t]/\n/g' | grep -iE '[ou|cn]=.*group.*' | grep -i '^CN='
- Using strings:
-
You can transfer the SSSD TDB cache for local parsing
- Default file path:
/var/lib/sss/db/cache_<realm_domain_name>.tdb - You can dump this file with tools such as
tdbtoolortdbdump
- Default file path:
-
-
Network Configurations
Network Interfaces
-
Document current IP configuration and check for:
- Alternate NIC configurations
- Are there any Docker networks?
-
Windows
ipconfigorGet-NetAdapter
-
*nix
ip addressorifconfig- If in a stripped down environment and no
iporifconfighostname -Icat /var/lib/dhcp/dhclient.eth0.leases
Open Ports
-
Check for:
- Ports firewalled from initial
nmapscan - Ports bound to loopback
- Ports bound to Docker hosts
- Ports bound to other NICs
- Ports firewalled from initial
-
Windows
netstat -ano | findstr /i listeningorGet-NetTCPConnection -State Listen
-
*nix
netstat -tanup | grep -i listenorss -tanup | grep -i listen- If in a stripped down environment and no
netstatorss- See this shell one-liner
ARP Table (if pivoting to other hosts)
-
ARP table caches hosts at layer 2
- Any recent hosts with connectivity via configured NIC are cached
- Check for:
- Docker IPs
- Hosts on alternate NICs
-
Windows
arp -aorGet-NetNeighboroutput
-
*nix
ip neighorarp -aoutput- If in a stripped down environment and now
iporarpcat /proc/net/arp
Routes (if pivoting to other hosts)
-
Check for:
- Routes providing access to additional subnets
- Docker subnets
-
Windows
route printorGet-NetRouteoutput
-
*nix
ip routeorrouteoutput- If in a stripped down environment and no
iporroute- See this shell one-liner
Ping Sweep (if pivoting to other hosts)
-
Scope
- Always ensure the target hosts / subnets are in scope!
-
Layer 2 Host Discovery
- Is the subnet accessible via a NIC on the host?
- ARP scan will work
- Almost zero chance that ARP will be filtered
- Is the subnet accessible via a NIC on the host?
-
Layer 3 Host Discovery
- Perhaps you saw some alternate IPs in configuration files
- Or, maybe you saw IPs in the
netstatstate table - If the subnets exist, but don't have a direct path via NIC
- The host is going to send the traffic to default gateway
- Default gateway will route the traffic to the target
- To ping sweep these subnets, you'll need to use:
- ICMP (ping)
- TCP / UDP scans (as ICMP may be blocked)
-
Methodology:
- Look at the IP address space and network mask
- Layer 2
arp-scan(Linux)nmap -n -sn(ARP if NIC exists, Linux & Windows)
- Layer 3
pingnmap -n -sn(ICMP when no NIC, Linux & Windows)- Some other ideas here
- Layer 4
- Perform a port scan through tunnel / SOCKS on the target
- Transfer or use existing
nmapbinary on the target to port scan
Processes and Services
Interesting Processes
First...
Enumerate processes:
-
Windows
tasklistGet-ProcessGet-CimInstance -ClassName Win32_Process | Select-Object Name, @{Name = 'Owner' ; Expression = {$owner = $_ | Invoke-CimMethod -MethodName GetOwner -ErrorAction SilentlyContinue ; if ($owner.ReturnValue -eq 0) {$owner.Domain + '\' + $owner.User}}}, CommandLine | Sort-Object Owner | Format-List
-
*nix
ps aux --sort user- Or, filter noise with
ps aux --sort user | grep -v '\ \[.*\]$'
Then...
Focus on:
- Any interesting processes run by users/administrators
- Any vulnerable applications
- Any intersting command line arguments visible
Interesting Services
-
Windows
- First...
Enumerate services:sc.exe query- Then
sc.exe qc <service-name>- List the configuration for any interesting services
- Then
- Or
Get-CimInstance -ClassName Win32_Service | Select-Object Name, StartName, PathName | Sort-Object Name | Format-List - Or
reg.exe query 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services'- Then
reg.exe query 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\service_name'
- Then
- Then...
Check for things like:- Vulnerable service versions
- Unquoted service path
- Service path permissions too open?
- Can you overwrite the service binary?
- DLL injection?
- First...
-
*nix
- First...
Enumerate services:service --status-allorsystemctl list-units --type=service --state=running
- Then...
Check for things like:- Vulnerable service versions
- Configuration files with passwords or other information
- Writable unit files:
systemctl list-units --state=running --type=service | grep '\.service' | awk -v FS=' ' '{print $1}' | xargs -I % systemctl status % | grep 'Loaded:' | cut -d '(' -f 2 | cut -d ';' -f 1 | xargs -I % find % -writable 2>/dev/null - Writable service binaries
- First...
Then...
Focus on:
- Any interesting services or vulnerabilities
- Any vulnerable service versions
- Any intersting configuration files
Scheduled Tasks
Interesting Scheduled Tasks
First...
Enumerate scheduled tasks:
-
Windows
schtasks /QUERY /FO LIST /V | findstr /i /c:taskname /c:"run as user" /c:"task to run"Get-CimInstance -Namespace Root/Microsoft/Windows/TaskScheduler -ClassName MSFT_ScheduledTask | Select-Object TaskName, @{Name = 'User' ; Expression = {$_.Principal.UserId}}, @{Name = 'Action' ; Expression = {($_.Actions.Execute + ' ' + $_.Actions.Arguments)}} | Format-List
-
*nix
crontab -lcat /etc/cron* 2>/dev/nullcat /var/spool/cron/crontabs/* 2>/dev/null
Then...
Focus on:
- Any interesting scheduled tasks
- Any writable paths in the scheduled task
- Any intersting command line arguments visible
Interesting Files
C:\InterestingDir\Interesting-File1.txt
-
Windows
- Check for writable files and directories
- See this script I wrote for enumerating interesting permissions in specified directories
- Check for configuration files with passwords and other interesting info
- Check for scripts with external dependencies that can be overwritten or changed
- Some interesting places to check
- Check
$PATHvariable for current user for possible interesting locations - Also check for hidden items
- PowerShell History File:
(Get-PSReadLineOption).HistorySavePath - Check for DPAPI cached credentials
- Credential Blobs
"%USERPROFILE%\AppData\Local\Microsoft\Credentials""%USERPROFILE%\AppData\Roaming\Microsoft\Credentials"
- Master Keys
"%USERPROFILE%\AppData\Local\Microsoft\Protect""%USERPROFILE%\AppData\Roaming\Microsoft\Protect"
- Credential Blobs
- I reference
%SYSTEMDRIVE%, asC:is not always the system volume%SYSTEMDRIVE%\interesting_folder%SYSTEMDRIVE%\$RECYCLE.BINGet-ChildItem -Force -File -Recurse "$env:SystemDrive\`$RECYCLE.BIN"
%SYSTEMDRIVE%\Users\user_nameDesktop,Downloads,Documents,.ssh, etcAppData(may also have some interesting things inLocal,Roaming)
%SYSTEMDRIVE%\Windows\System32\drivers\etc\hosts%SYSTEMDRIVE%\inetpub%SYSTEMDRIVE%\Program Files\program_name%SYSTEMDRIVE%\Program Files (x86)\program_name%SYSTEMDRIVE%\ProgramData%SYSTEMDRIVE%\Temp%SYSTEMDRIVE%\Windows\Temp
- Check the Registry for passwords, configurations, interesting text
HKEY_LOCAL_MACHINEorHKLMHKEY_CURRENT_USERorHKCU- Search the
HKLMhive recursively for the wordpasswordreg query HKLM /f password /t REG_SZ /s
- Check
- Check for writable files and directories
-
*nix
- Check for SUID binaries
find / -type f -perm /4000 -exec ls -l {} \; 2>/dev/null
- Check binary capabilities
getcap -r / 2>/dev/null- If
getcapcommand not found, check/usr/bin/getcapor/usr/sbin/getcap(probably$PATHissue)
- If
- Check for interesting / writable scripts, writable directories or files
find / -path /proc -prune -o -path /sys -prune -o -type f -writable -ls 2>/dev/nullfind / -type f \( -user $(whoami) -o -group $(whoami) \) -exec ls -l {} \; 2>/dev/null
- Check for configuration files with passwords and other interesting info
- Check for scripts with external dependencies that can be overwritten or changed
- Use strings on interesting binaries to check for relative binary names and
$PATHhijacking - Some interesting places to check (check for hidden items)
- Check
$PATHvariable for current user for possible interesting locations /interesting_folder/home/user_name.profile.bashrc,.zshrc.bash_history,.zsh_historyDesktop,Downloads,Documents,.ssh, etc.- PowerShell History File:
(Get-PSReadLineOption).HistorySavePath
/var/www/interesting_folder/var/mail/user_name/opt/interesting_folder/usr/local/interesting_folder/usr/local/bin/interesting_folder/usr/local/share/interesting_folder/etc/hosts/tmp/mnt/media/etc- Look for interesting service folders
- Check for readable and/or writable configuration files
- May find cleartext passwords
- Check
- Check for SUID binaries
Privilege Escalation
Depending on the information you enumerated above, your path to privilege escalation could take any direction.
- You might find a server listening internally running vulnerable software
- An internal service might be using default credentials, leading to some other exploit
- You might find a SUID binary that gives you
rootaccess - You might have access to run a command with
sudowhich can be abused to pivot to another user or root - You might find an interesting file such as a configuration file with database credentials or a sqlite database from which you can dump password or hashes
- You might find a configuration file with a password and this password may be reused on another user account on the system or another service
- You might have
SeImpersonatePrivilegeallowing for a Potato attack - You may find a kernel exploit
- The possibilities are endless and that's why putting all of your effort into solid enumeration strategies will always pay off



