- Jh123x: Blog, Code, Fun and everything in between./
- My Blog Posts and Stories/
- LakeCTF Writeup (Misc: curl | zsh)/
LakeCTF Writeup (Misc: curl | zsh)
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.
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.
Flag: EPFL{1t_i5_n0t_4_bug_1t_i5_4_f3atur3_4cc0rd1ng_t0_6ithub}