Description
I have built my own Git server with my own rules! You want the flag - make sure to push the flag. Only flag.txt pushed by root (name: root, email: root@picoctf) will be updated with the flag.
Setup
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Clone the repository
ObservationThe instance page gives an HTTP Git URL and a password, so there is a remote repository to clone before anything else.Clone the repository using the command provided on the challenge page. Note the password.bashgit clone http://<HOST>:<PORT_FROM_INSTANCE>/repo.gitbashcd repoWhat didn't work first
Tried: Browsing to the repo URL in a browser to look for files or the flag directly
The server speaks the Git smart-HTTP protocol, not a file browser, so a browser gets an empty index page. The flag only appears after the right commit is pushed.
Tried: Cloning with SSH instead of the provided HTTP URL
The challenge instance does not expose an SSH port - only the HTTP port shown on the challenge page is open. An SSH clone attempt will time out or be refused. Use the exact URL format provided.
Learn more
This challenge has a server-side Git hook that runs when you push commits. The hook checks the committer name and email - it only updates flag.txt if the push comes from a commit with name root and email root@picoctf. Git allows you to set any name and email locally, so you can impersonate this identity.
Step 2Configure git identity as root
ObservationThe description says only a flag.txt pushed by a committer named root, at root@picoctf, triggers the flag. Set the local git identity to match before committing.Set your local git user name to 'root' and email to 'root@picoctf'. These values appear in commit metadata and the server hook checks them.bashgit config user.name rootbashgit config user.email root@picoctfWhat didn't work first
Tried: Setting the global git config (git config --global user.name root) instead of the local repo config
The global form writes to your user gitconfig and affects every repository you own. It works here, as long as you set it before committing, but it is easy to forget afterwards. Setting it locally inside the clone is safer.
Tried: Setting the GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL environment variables instead of the committer fields
Git separates the author, who wrote the change, from the committer, who recorded it, and the hook checks the committer. Set only the author variables and the committer still comes from your real config, so the push is rejected.
Learn more
Git commit metadata (author name and email) is entirely client-controlled. There is no authentication binding a git identity to an actual user. This is why signed commits (GPG or SSH signing) exist - to provide cryptographic proof that a commit came from a specific key, not just a self-reported name.
The challenge illustrates a real security risk: if a server grants permissions based on the committer name/email in the commit object, any client can impersonate any identity by simply changing their local git config.
Step 3Create flag.txt, commit, and push
ObservationThe hook watches for a flag.txt pushed under that identity, so creating the file and pushing it brings the real flag back in the push output.Create a flag.txt file, stage it, commit with the root identity, and push. The server hook will detect the commit came from 'root' and update flag.txt with the flag.bashtouch flag.txtbashgit add flag.txtbashgit commit -m 'add flag'bashgit pushbash# Enter the password from the challenge page when promptedExpected output
picoCTF{1mp3rs0n4t4_g17_345y_...}What didn't work first
Tried: Committing flag.txt with actual flag content (e.g. the placeholder picoCTF{...}) hoping the hook will accept it
The hook never looks inside flag.txt. It checks the committer identity, then overwrites the file with the real flag on its side. Whatever you put in the file changes nothing; the flag comes back in the push response.
Tried: Forgetting to enter the password and pressing Enter at the prompt, then trying to read flag.txt from the local clone
An empty password fails authentication and the push is rejected before the hook runs at all. And even on success, the flag arrives in the push output rather than in your working tree; a pull brings the file down.
Learn more
The server-side Git hook (typically a
post-receiveorupdatehook) runs after you push. It inspects the committer identity in the pushed commits. Since we configured our local git to use name "root" and email "root@picoctf", the hook recognizes this as the privileged identity and replaces flag.txt with the actual flag content, which the hook then echoes back in the push output.
Interactive tools
- Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
- Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
Flag
Reveal flag
picoCTF{1mp3rs0n4t4_g17_345y_...}
Configure git user.name=root and user.email=root@picoctf, create flag.txt, commit, and push. The server hook grants the flag to commits from 'root'.
Key takeaway
How to prevent this
How to prevent this
Git commit identity is completely client-controlled. Never grant permissions based on committer name or email.
- Use signed commits (GPG or SSH signing) if you need to verify who made a commit. The signature is cryptographically tied to a private key the committer controls, unlike the name/email which anyone can set to anything.
- Authenticate at the transport layer (SSH keys, HTTPS tokens) rather than inside commit metadata. The connection identity is harder to fake than the metadata inside the commit object.