Collaborative Development

Published: April 3, 2024

Description

My team has been working very hard on new features for our flag printing program! I wonder how they'll work together?

Download the provided challenge.zip archive.

Extract it locally and move into the drop-in repository where the Git history lives.

wget https://artifacts.picoctf.net/c_titan/71/challenge.zip && \
unzip challenge.zip && \
cd drop-in/

Solution

This challenge builds on the Git fundamentals from Time Machine and Commitment Issues. For file-specific investigation, see Blame Game. Each feature branch here contains a slice of the flag inside flag.py. You can either read them one at a time or merge them back into main to watch Git handle the conflicts.
  1. Step 1List every branch
    git branch -a reveals the feature/part-* branches that contain pieces of the flag. They're local copies already, so you can check them out directly.
    git branch -a
    Learn more

    Git branches are lightweight pointers to commits, enabling parallel lines of development. The -a flag (all) shows both local branches and remote-tracking branches (remotes/origin/...). In a distributed workflow, each developer typically works on a feature branch, preventing conflicts with others' work until an intentional merge.

    The branch naming convention feature/part-1 follows the GitFlow branching model, where feature branches are prefixed with feature/. Other common conventions include feat/, issue numbers (issue-123), or author initials. Consistent naming makes it easy to understand a branch's purpose at a glance.

    In security research, inspecting all branches of a repository can reveal sensitive information that was accidentally committed to a feature branch and never merged. Credentials, API keys, and partial implementations are sometimes found in abandoned branches that developers forgot existed. Tools like truffleHog and git-secrets automate this kind of branch-wide secret scanning.

  2. Step 2Inspect each feature branch
    Checkout each branch and read flag.py. Every branch prints a different slice of the flag, intentionally split to encourage review of multiple branches.
    git checkout feature/part-1 && cat flag.py
    Repeat for feature/part-2 and feature/part-3 to gather the middle and final segments.
    Learn more

    git checkout <branch> switches your working directory to a different branch, updating all tracked files to match that branch's latest commit. It's one of the most frequently used Git commands, and in modern Git (2.23+) the more explicit git switch <branch> command is preferred for branch switching while git checkout is reserved for file restoration.

    Splitting a secret across multiple branches demonstrates a real security concern: sensitive data spread across feature branches may be harder to detect than a single committed secret. Automated secrets scanners need to check every branch, not just the default branch, to provide complete coverage.

    This pattern also illustrates collaborative Git workflows: in practice, multiple developers submit pull requests (PRs) from feature branches. Code reviewers must examine each branch individually before approving a merge. Understanding how to navigate branches quickly is essential for both development productivity and security auditing.

  3. Step 3Optional: merge for a single view
    If you prefer one unified output, merge the feature branches into main (in any order) and resolve the minor conflicts. The combined flag prints once the merges complete.
    git checkout main && \
    git merge feature/part-1 feature/part-2 feature/part-3
    Learn more

    git merge integrates changes from one or more branches into the current branch. When multiple branches modify the same file in the same location, Git creates a merge conflict - it marks the conflicting sections and requires a human to choose how to resolve them. This is a fundamental part of collaborative development.

    Git uses a three-way merge algorithm: it finds the common ancestor commit of both branches and compares each branch's changes against that ancestor. Changes that don't overlap are merged automatically; overlapping changes become conflicts. Understanding this algorithm helps predict when conflicts will occur and how to structure commits to minimize them.

    In production workflows, merges are often done via pull requests on platforms like GitHub or GitLab, which add code review, CI/CD checks, and discussion threads before the merge happens. The --no-ff flag forces a merge commit even when a fast-forward is possible, preserving branch history in the commit graph for auditing purposes.

Flag

picoCTF{t3@mw0rk_m@k3s_th3_dr3@m_w0rk_4c2...}

Concatenate the outputs from each feature/part-* branch (or resolve the merged file) to reveal the full flag above.

Want more picoCTF 2024 writeups?

Useful tools for General Skills

Related reading

What to try next