Skip to content

Commit

Permalink
Work in progress gatox dev.
Browse files Browse the repository at this point in the history
  • Loading branch information
AdnaneKhan committed Feb 25, 2024
1 parent e82437f commit 04300df
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 12 deletions.
7 changes: 5 additions & 2 deletions gato/enumerate/enumerate.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,14 @@ def enumerate_organization(self, org: str):
else:
Output.warn("GraphQL query failed, will revert to REST workflow query for impacted repositories!")
for repo in enum_list:
if repo.is_archived():
continue
if self.skip_log and repo.is_fork():
continue
Output.tabbed(
f"Enumerating: {Output.bright(repo.name)}!"
)

self.repo_e.enumerate_repository(repo, large_org_enum=len(enum_list) > 100)
self.repo_e.enumerate_repository(repo, large_org_enum=len(enum_list) > 25)
self.repo_e.enumerate_repository_secrets(repo)

Recommender.print_repo_secrets(
Expand Down
5 changes: 4 additions & 1 deletion gato/enumerate/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def __perform_yml_enumeration(self, repository: Repository):
)


if wf_injection and not skip_injection:
if pwn_reqs and not skip_injection:
Output.result(
f"The workflow {Output.bright(parsed_yml.wf_name)} runs on a risky trigger "
f"and might check out the PR code, see if it runs it!"
Expand Down Expand Up @@ -303,6 +303,9 @@ def construct_workflow_cache(self, yml_results):
if 'nameWithOwner' not in result:
continue

if 'isArchived' in result and result['isArchived']:
continue

owner = result['nameWithOwner']
# Empty means no yamls, so just skip.
if not result['object']:
Expand Down
28 changes: 22 additions & 6 deletions gato/github/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ def __process_run_log(self, log_content: bytes, run_info: dict):
log_package["non_ephemeral"] = non_ephemeral

index += 1

# Continue if there is no runner name. This means
# we picked up a pending workflow.
if not runner_name:
continue

log_package = {
"requested_labels": labels,
Expand Down Expand Up @@ -704,7 +709,7 @@ def retrieve_run_logs(self, repo_name: str, short_circuit: str = True):
start_date = datetime.now() - timedelta(days = 60)
runs = self.call_get(
f'/repos/{repo_name}/actions/runs', params={
"per_page": "30",
"per_page": "50",
"status":"completed",
"exclude_pull_requests": "true",
"created":f">{start_date.isoformat()}"
Expand Down Expand Up @@ -1063,14 +1068,25 @@ def retrieve_composite_actions(self, repo_name: str, composite_actions: list):
)

elif composite['ref']:
resp = self.call_get(
f'/repos/{repo_name}/contents/{composite["path"]}/action.yml?ref={composite["ref"]}'
)

if len(composite["path"].split('/')) > 2:
repo_path = "/".join(composite["path"].split("/", 2)[:2])
composite_path = "/".join(composite["path"].split("/", 2)[2:])

resp = self.call_get(
f'/repos/{repo_path}/contents/{composite_path}/action.yml?ref={composite["ref"]}'
)
else:
resp = self.call_get(
f'/repos/{composite["path"]}/contents/action.yml?ref={composite["ref"]}'
)

if resp.status_code == 404:
print(f'TEMP FOR DEV, Got 404: /repos/{composite["path"]}/contents/action.yml?ref={composite["ref"]}')
else:
resp = self.call_get(
f'/repos/{repo_name}/contents/{composite["path"]}/action.yml'
)
f'/repos/{composite["path"]}/contents/action.yml'
)

if resp.status_code == 200:
content = base64.b64decode(resp.json()['content']).decode()
Expand Down
2 changes: 2 additions & 0 deletions gato/github/gql_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class GqlQueries():
fragment repoWorkflows on Repository {
nameWithOwner
isPrivate
isArchived
viewerPermission
defaultBranchRef {
name
Expand Down Expand Up @@ -35,6 +36,7 @@ class GqlQueries():
nodes(ids: $node_ids) {
... on Repository {
nameWithOwner
isArchived
object(expression: "HEAD:.github/workflows/") {
... on Tree {
entries {
Expand Down
3 changes: 3 additions & 0 deletions gato/models/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def can_pull(self):

def is_private(self):
return self.repo_data['private']

def is_archived(self):
return self.repo_data['archived']

def is_internal(self):
return self.repo_data['visibility'] == 'internal'
Expand Down
2 changes: 1 addition & 1 deletion gato/workflow_parser/composite_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ def check_injection(self, inbound_variables=None):

steps = self.parsed_yml['runs'].get('steps', [])
processed_steps = process_steps(steps)

for step in processed_steps:

if step['contents']:
tokens = re.findall(context_expression_regex, step['contents'])
else:
Expand Down
9 changes: 7 additions & 2 deletions gato/workflow_parser/workflow_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ def get_vulnerable_triggers(self):
# but if there are other triggers there is the SE possibility.
if 'labeled' in trigger_conditions['types'] and len(trigger_conditions['types']) == 1:
continue

vulnerable_triggers.append(trigger)
else:
vulnerable_triggers.append(trigger)

return vulnerable_triggers
Expand All @@ -203,7 +204,9 @@ def analyze_checkouts(self):

for job_name, job_details in self.parsed_yml['jobs'].items():
for step in job_details.get('steps', []):
if 'uses' in step and step['uses'] and 'actions/checkout' in step['uses'] \
# Check more more than just actions/checkout in case there are alternatives
# in use.
if 'uses' in step and step['uses'] and '/checkout' in step['uses'] \
and 'with' in step and 'ref' in step['with']:
ref_values.append(step['with']['ref'])

Expand All @@ -216,6 +219,7 @@ def check_pwn_request(self):
dict: A dictionary containing the job names as keys and a list of potentially vulnerable tokens as values.
"""
vulnerable_triggers = self.get_vulnerable_triggers()

if not vulnerable_triggers:
return {}

Expand Down Expand Up @@ -249,6 +253,7 @@ def check_pr_ref(cls, item):
]

for prefix in PR_ISH_VALUES:

if prefix in item.lower():
return True
return False
Expand Down

0 comments on commit 04300df

Please sign in to comment.