CTF Methodology
CTF Methodology
My CTF Methodology
In this post, I examine the steps I take to approach a typical CTF in the form of a vulnerable target (also known as boot2root), and elaborate on steps at
each phase.
nmap -h
Bash
Copy
Bash
Copy
Bash
Copy
sudo nmap -Pn -sU --top-ports 500 -A -T4 -oN udp-scan.txt <target_ip>
Bash
Copy
UDP scan example using '-T4', as going too fast may miss ports
❗
Don't miss an opportunity to begin collecting as much information about the target as you can — even at the initial nmap scan! There's a lot of good
information here to take note of.
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:
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.
Plain text
Copy
You 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.
⚠️
Note that for some services — like web servers — the system administrator can often alter or remove the **service banner**, so this may not always be
complete or accurate.
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?
Plain text
Copy
You can try to manually pull banners from the service, but in all likelihood, you'll just have to move on:
Bash
Copy
Try netcat with verbose output, press 'Enter' a couple times to see if there's any output
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 exploit
ProFTPD 1.3.3c exploit site:github.com
Exploit Database:
Command Line: searchsploit ProFTPD 1.3.3c
Web: https://www.exploit-db.com/
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.
If the target **is part of** an Active Directory domain, or a standalone domain controller, then I take a few additional steps **in addition to** following
my General Procedure below.
Plain text
Copy
A typical port signature for an Active Directory domain controller, especially apparent due to DNS, SMB, Kerberos, and LDAP being open on the box
target_ip='10.10.10.22'
sudo nmap -Pn --script ldap-rootdse.nse $target_ip
Bash
Copy
If 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}"
Bash
Copy
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_ip
Bash
Copy
Attempt 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 100
Bash
Copy
If 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, -)
Copy
If configured correctly, you should see an error saying that a successful bind must be completed, meaning you need a credential
Bash
Copy
However, if you are able to anonymously query LDAP, this is an example command to pull everything from LDAP
When to Use You’ll know when you’ve found a domain controller, because it will have several ports…
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_ip
Bash
Copy
If 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_name
Bash
Copy
Bash
Copy
If 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.
How it Works We can send a request for a TGT --- without a pre-authentication hash --- to the Kerbe…
Attempt to find valid usernames and save them to a log file, then testing for AS-REP hashes and attempting to crack them. If you manage to crack an AS-
REP hash for a user account, you could then spray this password around and see what you can access (or at a minimum, dump LDAP).
ℹ️
At this point, if your Active Directory specific testing hasn't produced any meaningful results, it's time to move onto the General Procedure
General Procedure
This is my generalized approach to every target:
1. File servers
2. Web servers
3. 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
2. Web — HTTP/HTTPS
3. Everything else
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_ip
Bash
Copy
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'
Copy
If the zone transfer fails, you can try and manually enumerate records in the target domain
💡
While the gobuster dns scan is running, go ahead and start your tests on other ports.
FTP — TCP/21
Bash
Copy
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:
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.
smbclient -N -L //10.10.100.44
Bash
Copy
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/myshare
Bash
Copy
Map the 'myshare' share anonymously
If you are able to map the share anonymously, try the following:
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.
Are there any noticeable differences between the http:// and the https:// versions of the apps running on the web server? In other words,
is http:// redirecting to https:// , are they duplicates, or 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?
http://10.10.100.44
https://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/80 to TCP/443
Only need to test TCP/443 (https)
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.
Copy
# Custom Entry
10.10.100.44 mysite.test dev.mysite.test admin.mysite.test
Plain text
Copy
Again, as before, test the server names against both HTTP and HTTPS and see if there are any behavioral differences.
](https://pwning.owasp-juice.shop/companion-guide/latest/part1/happy-path.html?ref=benheater.com)
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
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
http://10.10.100.44/robots.txt or https://mysite.test/robots.txt
https://10.10.100.44/sitemap.xml or https://mysite.test/sitemap.xml
robots.txt and sitemap.xml direct 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.txt may show an entry for the /admin directory or similar
A legitimate web crawler respects this and does not crawl the directory
Malicious users will see this an opportunity to explore
Bash
Copy
HTTP enumeration
Bash
Copy
Path traversal
Local and/or remote file inclusion
Content type filter bypass
SQL injection
Default credentials
Credential stuffing
Password spraying
Much, much more
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
Plain text
Copy
Plain text
Copy
Plain text
Copy
Plain text
Copy
Plain text
Copy
Plain text
Copy
(https://book.hacktricks.xyz/network-services-pentesting/1883-pentesting-mqtt-mosquitto?ref=benheater.com)
Plain text
Copy
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.
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.
✔️
All of the information gathering and preparation you've done up until this point should directly inform the exploit you're going to use.
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.
💡
Keep in mind that some of the usernames and/or passwords you enumerated before could be useful to you even at this point in the process.
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.
ℹ️
I try to enumerate as much as I can manually, and in a targeted fashion, before relying on privilege escalation scripts. In fact — for me at least —
privilege escalation scripts are always my last resort when all else fails.
You can find the most up-to-date list of post-exploit enumeration tricks here:
GitHub0xBEN
Operating Environment
OS & Kernel
Windows
systeminfo or Get-ComputerInfo or reg.exe query 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion' to print system overview
Check environment variables:
CMD: set
PowerShell: Get-ChildItem Env:\
*nix
uname -a to print kernel information
cat /etc/os-release to print OS release information
Check environment variables:
env or set
Current User
Windows
whoami /all to list:
Username
Group memberships
Privileges
*nix
id to list username and group memberships
sudo -l to check sudo permissions
Windows
net user or Get-LocalUser to list users
net user <username> or Get-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/passwd to list users
Local Groups
Document here any interesting group(s) after running the below commands:
Windows
net localgroup or Get-LocalGroup to list groups
net localgroup <group_name> or Get-LocalGroupMember <group_name> | Select-Object * to enumerate users of specific groups
*nix
cat /etc/group
cat /etc/group | grep <username> to check group memberships of specific users
Document here any interesting username(s) after running the below commands:
Windows
net user /domain or Get-ADUser -Filter * -Properties * output
net user <username> /domain or Get-ADUser -Identity <username> -Properties * to enumerate details about specific domain users
Not a local administrator and can't run PowerShell AD cmdlets?
See here: https://notes.benheater.com/books/active-directory/page/powershell-ad-module-on-any-domain-host-as-any-user
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?
*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
Validate findings:
Check if discovered usernames are valid: getent passwd <domain_username>
If valid, check user group memberships: List id <domain_username>
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'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
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 tdbtool or tdbdump
Windows
net group /domain or Get-ADGroup -Filter * -Properties * output
net group <group_name> /domain or Get-ADGroup -Identity <group_name> | Get-ADGroupMember -Recursive to enumerate members of
specific domain groups
Not a local administrator and can't run PowerShell AD cmdlets?
See here: https://notes.benheater.com/books/active-directory/page/powershell-ad-module-on-any-domain-host-as-any-user
*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: getent will 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'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='
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 tdbtool or tdbdump
Network Configurations
Network Interfaces
Windows
ipconfig or Get-NetAdapter
*nix
ip address or ifconfig
Open Ports
Looking for any ports listening internally, or any that may have been firewalled and unreachable at the initial nmap scan.
Windows
netstat -ano | findstr /i listening or Get-NetTCPConnection -State Listen
*nix
netstat -tanup | grep -i listen or ss -tanup | grep -i listen
Windows
arp -a or Get-NetNeighbor output
*nix
ip neigh or arp -a output
Windows
route print or Get-NetRoute output
*nix
ip route or route output
Windows
tasklist
Get-Process
Get-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
Then...
Focus on:
Interesting Services
Windows
First...
Enumerate services:
sc.exe query
Then sc.exe qc <service-name>
List the configuration for any interesting services
Get-CimInstance -ClassName Win32_Service | Select-Object Name, StartName, PathName | Sort-Object Name | Format-List
Then...
Check for things like:
Vulnerable service versions
Unquoted service path
Service path permissions too open?
Can you overwrite the service binary?
DLL injection?
*nix
First...
Enumerate services:
service --status-all or systemctl 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
Then...
Focus on:
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 -l
cat /etc/cron* 2>/dev/null
cat /var/spool/cron/crontabs/* 2>/dev/null
Then...
Focus on:
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 $PATH variable for current user for possible interesting locations
Also check for hidden items
PowerShell History File: (Get-PSReadLineOption).HistorySavePath
I reference %SYSTEMDRIVE% , as C: is not always the system volume
%SYSTEMDRIVE%\interesting_folder
%SYSTEMDRIVE%\Users\user_name
Desktop , Downloads , Documents , .ssh , etc
AppData (may also have some interesting things in Local , 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_MACHINE or HKLM
HKEY_CURRENT_USER or HKCU
Search the HKLM hive recursively for the word password
reg query HKLM /f password /t REG_SZ /s
*nix
Check for SUID binaries
find / -type f -perm /4000 -exec ls -l {} \; 2>/dev/null
Check for interesting / writable scripts, writable directories pr files
find /etc -writable -exec ls -l {} \; 2>/dev/null
find / -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 $PATH hijacking
Some interesting places to check (check for hidden items)
Check $PATH variable for current user for possible interesting locations
/interesting_folder
/home/user_name
.profile
.bashrc , .zshrc
.bash_history , .zsh_history
Desktop , 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
Privilege Escalation
Depending on the information you enumerated above, your path to privilege escalation could take any direction.