Authors:
- yvie (Yvonne K.)
- bazumo (Moritz S.)
Categories:
- Web
- Pwn
- Rev
Git management platform, inspired by similar platforms such as github, gitlab, etc.
Features:
- Create and manage git repositories in a web frontend
- Clone repositories via SSH
Tech-Stack:
The service consists of three loosely-coupled parts:
- frontend:
Publically accessible web frontend and backend using Next.js/typescript running in Bun. This is the main component users interact with, when accessing the website. - ssh:
OpenSSH daemon running a custom login shell (/opt/gitter-shell). The SSH wrapper is written in C++ and queries an internal API to implement user restrictions (described below).
The wrapper matches users according to the public key they used during SSH login. Permission to access the repository is checked, before a push or pull is allowed. - internal:
API used by the SSH wrapper. Non-public and without authentication. Can query metadata of users and repositories. Written in JS using express and running in Bun.
Flag is stored as a file in a repository. The path to the repository and file is given as attack info.
Flag is stored in the repository's metadata (private description). The path to the repository is given as attack info.
In the web frontend, the target file is obtained using git checkout <revision> and then subsequently read from the filesystem. If an attacker adds a symbolic link to their repository, they can read the link target by requesting that file's content.
- Difficulty: easy
- Discoverability: easy
- Patchability: easy
- Categories: misc
There is a path traversal when reading repository files:
const filepath = filepath_encoded.map(s => decodeURIComponent(s));
const repo = await getRepository(
organization,
repository
);
...You can read other repository files by ..%2f..%2f<username>%2f<repo>%2f<file>, e.g. for extracting flags..%2f..%2f<username>%2fflag%2fflag.txt
- Difficulty: easy
- Discoverability: easy
- Patchability: easy
- Categories: web
The SSH configuration allows port forwarding using ssh -L <port>:localhost:<port>. This enables an attacker to access the internal API. An attacker can then read the metadata of all repositories that belong to a given user by querying http://internal:3000/get-repositories?user=<user>
- Difficulty: easy
- Discoverability: hard
- Patchability: easy
- Categories: misc
The ssh-wrapper binary parses the invoked git command and returns an std::optional<GitCommand>. However, this optional is not validated before access. If an invalid command line is given, an uninitialized GitCommand-struct is accessed.
The GitCommand overlaps the same stack location as the base64-decoded ssh public key used for authentication. The struct starts at offset 0x40 of the buffer. The struct looks like this:
enum class GitPermission {
READ = 0,
WRITE = 1,
};
struct GitCommand {
GitPermission permission;
std::string repository;
std::string user;
};
Therefore a carefully crafted public key can replace the user's name. Furthermore, the binary uses libc++ instead of libstdc++ (which is normally the default). This enables us to use the short-string optimization in order to change the user string without any address leak. Then, when access permissions are checked, the repositories of the changed user are loaded and the private description will be printed.
Note that this vuln does not enable access to the repository contents of the other user, as the optional is validated before granting repository access (but still after the access check).
- Difficulty: medium
- Discoverability: hard
- Patchability: medium
- Categories: pwn, rev
In the web frontend, the function addContributor is called inside an event handler. This means that this code runs in the browser and not in the backend. Therefore addContributor is exposed a next.js server action.
The additional argument to addContributor allows adding yourself to any repo. Need to figure out that this server function is called as a next.js server action and that you can just pass an additional argument in it.
- Difficulty: medium
- Discoverability: medium
- Patchability: easy
- Categories: web
Use the output of git show <revision>:<path> instead of reading the file content manually.
Check if file name contains ../ after url decode and abort in this case.
Add
AllowTcpForwarding No
to /etc/ssh/sshd_config
Invoke a small script as ssh entrypoint, before calling the binary to validate whether the given command is valid
For example in python:
import sys
import subprocess
import re
if re.match("^'(git-receive-pack|git-upload-pack) .+'$", sys.argv[2]):
subprocess.call(["/opt/gitter-shell"] + sys.argv[1:])
remove third argument in
export async function addContributor(repository_id: number, user_id: string, owner?: string): Promise<void> { ... }- Registration:
- Users can create new accounts, with a unique username, a password and an ssh public-key (must also be unique)
- Login:
- Users can login to their previously created account using their username and password
- Repository Management:
- Ability to create empty repositories in the web frontend, which can then be cloned via SSH
- Similar to the one used by github: https://github.com/torvalds/linux/blob/master/README
- Making the frontend look sleek and fit the CTF theme
- API to query access restrictions (used by the SSH wrapper)
- Endpoints:
- Identify the user that has the given public key
- Query permissions to repositories (read/write)
- List repositorys for user (including description, which is the flag)
- Clean up old users and repositories
- Reverse Proxy to forward public API
- Database schema definitions for Web-App
- Allows git clone/git push with access restrictions in place
- Prevent ZIP-Bombs/overly large repositories
- Repository settings
- Permissions
- Read/Write-Access to repositories
- Maybe public/private repositories (maybe only private repositories)
- Permissions
Test registering new users and authenticating.
Try creating a repository and using it without flag-related actions.
Try placing and retrieving the repository related flagstore flags.
Try placing and retrieving the description related flagstore flags.
Implement exploits for intended vulnerabilities.