Skip to main content
  1. My Blog Posts and Stories/

LakeCTF Writeup (Misc: curl | zsh)

··455 words·3 mins

NOTE: I did not solve this during the CTF as another teammate solved it.

I am trying to resolve it after the CTF.

I heard that piping random scripts to your shell
is bad so I'm only letting you install versions
of oh-my-zsh. Flag location: /app/flag.txt

Solving the challenge doesn't require opening a
PR on the official repo. Please don't do it as
it might spam the ohmyzsh authors.

nc chall.polygl0ts.ch 3100

A script was also attached for the challenge. The script is pretty short so I’ll just paste it here.

#!/usr/bin/env python3
import subprocess
import re
import sys

print("Solving the challenge doesn't require opening a PR on the official repo. Please don't do it as it might spam the ohmyzsh authors. Thanks!")
commit = input("Commit: ")
if not re.match(r'^[a-f0-9]{40}$', commit):
    print("Invalid commit")
    exit(1)

command = f'curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/{commit}/tools/install.sh | zsh'
print(command, flush=True)
subprocess.run(command, shell=True, stdout=sys.stdout, stderr=sys.stderr)

It takes in a commit hash as a user input and pipes it to the command zsh. The script also checks if the commit hash is valid. It must be 40 hex characters.

Also note that the script that they are using is from /tools/install.sh. This is the script that is used to install oh-my-zsh officially.

My initial thought was that we can look for vulnerable versions of install.sh within the commit history / PRs for the fork.

However, after spending some time looking through the commit history and thinking about it, there will be no way they would have a command inside that will be useful to read the flag.

To determine how to solve this challenge, we have to take a look at how github commit hashes work.

raw.githubusercontent url
Raw.github user content url

When a user commits a change to a repository, a commit hash is generated. When we take a look at the raw github content, the url looks something like this:

https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/{40 char hash}/tools/install.sh

For brevity I will be omitting the domain part of the url

However, if you take a look at it from our own fork of the repo, we have a hash allocated to us for a particular commit IE: /Jh123x/ohmyzsh/7dcabbe6826073ef6069c8a4b6f9a943f00d2df0/tools/install.sh

The hash is generated based on the content of the commit. If we change the content of the commit, the hash will change.

After changing install.sh to cat /app/flag.txt, we can see that the raw.githubusercontent website has changed to /Jh123x/ohmyzsh/d85dc97fa12747bb85786e0362e2473cb804fb09/tools/install.sh

The hash of the commit in our own fork also works on the /ohmyzsh/ohmyzsh/{40 char hash}/tools/install.sh url.

So if we do /ohmyzsh/ohmyzsh/d85dc97fa12747bb85786e0362e2473cb804fb09/tools/install.sh, we can see that the content of the file has changed to cat /app/flag.txt.

With this we can submit the flag and the install script will run cat /app/flag.txt and we can get the flag.

solve image
Solved Image

Flag: EPFL{1t_i5_n0t_4_bug_1t_i5_4_f3atur3_4cc0rd1ng_t0_6ithub}