--- date: '2024-02-06' tags: ['ctf', 'ctf-misc', 'shell'] title: 'DiceCTF 2024 Quals: misc/zshfuck' --- ## Task > **misc/zshfuck** > > may your code be under par. execute the `getflag` binary somewhere in the filesystem to win > > `nc mc.ax 31774` > > [`jail.zsh`](https://static.dicega.ng/uploads/53c6360b9ea7e5dba86f1d8d600de61b8601c1897b651eb88920906ff738f651/jail.zsh) - `Author: arxenix` - `Points: 127` - `Solves: 107 / 1040 (10.288%)` ## Writeup The challenge first prompts us to input a charset, which must contain at most 6 unique characters, and cannot contain `*`, `?`, or `` ` ``. Then we are given a `zsh` shell with the restriction that all commands can only contain characters from the charset we gave. First, let's try running the `find` command to find where `getflag` is. ``` Specify your charset: find OK! Got f i n d. find . ./y0u ./y0u/w1ll ./y0u/w1ll/n3v3r_g3t ./y0u/w1ll/n3v3r_g3t/th1s ./y0u/w1ll/n3v3r_g3t/th1s/getflag ./run ``` We see that the path to `getflag` contains more than 6 distinct characters, so we will not be able to execute the command by directly typing out the full path. Additionally, we cannot just use `*` or `?` to glob each name (through `*/*/*/*/*` or `???/????/?????????/????/???????` respectively), as those are banned characters. However, `zsh` can glob with more than just `*` and `?`. We can use a negated character set to glob a single character not in the set as a replacement for `?`. For example, `[^z]` will match a single character that is not `z`. Using this, we can run the command `[^z][^z][^z]/[^z][^z][^z][^z]/[^z][^z][^z][^z][^z][^z][^z][^z][^z]/[^z][^z][^z][^z]/[^z][^z][^z][^z][^z][^z][^z]`, which will expand to `y0u/w1ll/n3v3r_g3t/th1s/getflag`, getting us the flag: ``` Specify your charset: [^z]/ OK! Got [ ^ z ] /. [^z][^z][^z]/[^z][^z][^z][^z]/[^z][^z][^z][^z][^z][^z][^z][^z][^z]/[^z][^z][^z][^z]/[^z][^z][^z][^z][^z][^z][^z] dice{d0nt_u_jU5T_l00oo0ve_c0d3_g0lf?} ``` ## Reference - [globbing in zsh](https://zsh-manual.netlify.app/expansion#1481-glob-operators)